43namespace YM2413NukeYKT {
55 return (11 <= cycle) && (cycle <= 16);
59 return RmNum(cycle - 11);
62static constexpr auto logSinTab = [] {
63 std::array<uint16_t, 256> result = {};
65 for (
int i = 0; i < 256; ++i) {
66 result[i] = narrow_cast<uint16_t>(
cstd::round(-cstd::log2<8, 3>(cstd::sin<2>((
double(i) + 0.5) *
Math::pi / 256.0 / 2.0)) * 256.0));
70static constexpr auto expTab = [] {
71 std::array<uint16_t, 256> result = {};
73 for (
int i = 0; i < 256; ++i) {
74 result[i] = narrow_cast<uint16_t>(
cstd::round((cstd::exp2<6>(
double(255 - i) / 256.0)) * 1024.0));
79constexpr std::array<YM2413::Patch, 15> YM2413::m_patches = {
80 YM2413::Patch{0x1e, 2, 7, {0, 0}, {1, 1}, {1, 1}, {1, 0}, {0x1, 0x1}, {0, 0}, {0xd, 0x7}, {0x0, 0x8}, {0x0, 0x1}, {0x0, 0x7}},
81 YM2413::Patch{0x1a, 1, 5, {0, 0}, {0, 1}, {0, 0}, {1, 0}, {0x3, 0x1}, {0, 0}, {0xd, 0xf}, {0x8, 0x7}, {0x2, 0x1}, {0x3, 0x3}},
82 YM2413::Patch{0x19, 0, 0, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0x3, 0x1}, {2, 0}, {0xf, 0xc}, {0x2, 0x4}, {0x1, 0x2}, {0x1, 0x3}},
83 YM2413::Patch{0x0e, 0, 7, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0x1, 0x1}, {0, 0}, {0xa, 0x6}, {0x8, 0x4}, {0x7, 0x2}, {0x0, 0x7}},
84 YM2413::Patch{0x1e, 0, 6, {0, 0}, {0, 0}, {1, 1}, {1, 0}, {0x2, 0x1}, {0, 0}, {0xe, 0x7}, {0x0, 0x6}, {0x0, 0x2}, {0x0, 0x8}},
85 YM2413::Patch{0x16, 0, 5, {0, 0}, {0, 0}, {1, 1}, {1, 0}, {0x1, 0x2}, {0, 0}, {0xe, 0x7}, {0x0, 0x1}, {0x0, 0x1}, {0x0, 0x8}},
86 YM2413::Patch{0x1d, 0, 7, {0, 0}, {0, 1}, {1, 1}, {0, 0}, {0x1, 0x1}, {0, 0}, {0x8, 0x8}, {0x2, 0x1}, {0x1, 0x0}, {0x0, 0x7}},
87 YM2413::Patch{0x2d, 2, 4, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0x3, 0x1}, {0, 0}, {0xa, 0x7}, {0x2, 0x2}, {0x0, 0x0}, {0x0, 0x7}},
88 YM2413::Patch{0x1b, 0, 6, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0x1, 0x1}, {0, 0}, {0x6, 0x6}, {0x4, 0x5}, {0x1, 0x1}, {0x0, 0x7}},
89 YM2413::Patch{0x0b, 3, 0, {0, 0}, {1, 1}, {0, 1}, {0, 0}, {0x1, 0x1}, {0, 0}, {0x8, 0xf}, {0x5, 0x7}, {0x7, 0x0}, {0x1, 0x7}},
90 YM2413::Patch{0x03, 2, 1, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0x3, 0x1}, {2, 0}, {0xf, 0xe}, {0xa, 0x4}, {0x1, 0x0}, {0x0, 0x4}},
91 YM2413::Patch{0x24, 0, 7, {0, 1}, {0, 1}, {0, 0}, {1, 0}, {0x7, 0x1}, {0, 0}, {0xf, 0xf}, {0x8, 0x8}, {0x2, 0x1}, {0x2, 0x2}},
92 YM2413::Patch{0x0c, 0, 5, {0, 0}, {1, 1}, {1, 0}, {0, 1}, {0x1, 0x0}, {0, 0}, {0xc, 0xf}, {0x2, 0x5}, {0x2, 0x4}, {0x0, 0x2}},
93 YM2413::Patch{0x15, 0, 3, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x1, 0x1}, {1, 0}, {0xc, 0x9}, {0x9, 0x5}, {0x0, 0x0}, {0x3, 0x2}},
94 YM2413::Patch{0x09, 0, 3, {0, 0}, {1, 1}, {1, 0}, {0, 0}, {0x1, 0x1}, {2, 0}, {0xf, 0xe}, {0x1, 0x4}, {0x4, 0x1}, {0x0, 0x3}},
97constexpr std::array<YM2413::Patch, 6> YM2413::r_patches = {
98 YM2413::Patch{0x18, 1, 7, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x1, 0x0}, {0, 0}, {0xd, 0x0}, {0xf, 0x0}, {0x6, 0x0}, {0xa, 0x0}},
99 YM2413::Patch{0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x1, 0x0}, {0, 0}, {0xc, 0x0}, {0x8, 0x0}, {0xa, 0x0}, {0x7, 0x0}},
100 YM2413::Patch{0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x5, 0x0}, {0, 0}, {0xf, 0x0}, {0x8, 0x0}, {0x5, 0x0}, {0x9, 0x0}},
101 YM2413::Patch{0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x0, 0x1}, {0, 0}, {0x0, 0xf}, {0x0, 0x8}, {0x0, 0x6}, {0x0, 0xd}},
102 YM2413::Patch{0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x0, 0x1}, {0, 0}, {0x0, 0xd}, {0x0, 0x8}, {0x0, 0x4}, {0x0, 0x8}},
103 YM2413::Patch{0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x0, 0x1}, {0, 0}, {0x0, 0xa}, {0x0, 0xa}, {0x0, 0x5}, {0x0, 0x5}},
106static constexpr std::array<uint8_t, 18> CH_OFFSET = {
107 1, 2, 0, 1, 2, 3, 4, 5, 3, 4, 5, 6, 7, 8, 6, 7, 8, 0
110static constexpr std::array<int8_t, 8> VIB_TAB = {0, 1, 2, 1, 0, -1, -2, -1};
120#include "YM2413NukeYktTables.ii"
124 : attackPtr (attack[0][0])
125 , releasePtr(releaseData[0])
134 for (
auto& w : writes) w.port = uint8_t(-1);
135 write_fm_cycle = uint8_t(-1);
136 write_data = fm_data = write_address = 0;
137 fast_fm_rewrite = test_mode_active =
false;
139 eg_counter_state = 3;
140 eg_timer = eg_timer_shift = eg_timer_shift_lock = eg_timer_lock = 0;
141 attackPtr = attack[eg_timer_shift_lock][eg_timer_lock];
142 auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
143 releasePtr = releaseData[idx];
147 eg_rate[0] = eg_rate[1] = 0;
148 eg_sl[0] = eg_sl[1] = eg_out[0] = eg_out[1] = 0;
149 eg_timer_shift_stop =
false;
150 eg_kon[0] = eg_kon[1] = eg_off[0] = eg_off[1] =
false;
157 op_phase[0] = op_phase[1] = 0;
159 lfo_counter = lfo_am_counter = 0;
160 lfo_vib_counter = lfo_am_out = 0;
161 lfo_vib = VIB_TAB[lfo_vib_counter];
162 lfo_am_step = lfo_am_dir =
false;
169 for (
auto i :
xrange(9)) {
170 p_inst[i] = &patches[inst[i]];
173 rhythm = testMode = 0;
174 patches[0] = Patch();
175 c_dcm[0] = c_dcm[1] = c_dcm[2] = 0;
180 delay6 = delay7 = delay10 = delay11 = delay12 = 0;
186template<u
int32_t CYCLES>
ALWAYS_INLINE const YM2413::Patch& YM2413::preparePatch1(
bool use_rm_patches)
const
190 : *p_inst[CH_OFFSET[CYCLES]];
193template<u
int32_t CYCLES>
ALWAYS_INLINE uint32_t YM2413::envelopeKSLTL(
const Patch& patch1,
bool use_rm_patches)
const
195 constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
196 constexpr uint32_t ch = CH_OFFSET[CYCLES];
198 auto ksl = uint32_t(p_ksl[ch]) >> patch1.ksl_t[mcsel];
199 auto tl2 = [&]() -> uint32_t {
201 return inst[ch] << (2 + 1);
202 }
else if (mcsel == 1) {
211template<u
int32_t CYCLES>
ALWAYS_INLINE void YM2413::envelopeTimer1()
213 if constexpr (CYCLES == 0) {
214 eg_counter_state = (eg_counter_state + 1) & 3;
215 auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
216 releasePtr = releaseData[idx];
220template<u
int32_t CYCLES,
bool TEST_MODE>
ALWAYS_INLINE void YM2413::envelopeTimer2(
bool& eg_timer_carry)
222 if constexpr (TEST_MODE) {
223 if (CYCLES == 0 && (eg_counter_state & 1) == 0) {
224 eg_timer_lock = eg_timer & 3;
225 eg_timer_shift_lock = (eg_timer_shift <= 13) ? eg_timer_shift : 0;
228 attackPtr = attack[eg_timer_shift_lock][eg_timer_lock];
229 auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
230 releasePtr = releaseData[idx];
233 bool timer_inc = (eg_counter_state != 3) ?
false
234 : (CYCLES == 0) ? true
236 auto timer_bit = (eg_timer & 1) + timer_inc;
237 eg_timer_carry = timer_bit & 2;
238 eg_timer = ((timer_bit & 1) << 17) | (eg_timer >> 1);
240 const auto& write = writes[CYCLES];
241 auto data = (write.port != uint8_t(-1)) ? write.value : write_data;
243 eg_timer |= (data << (16 - 2)) & 0x10000;
246 if constexpr (CYCLES == 0) {
247 eg_timer_shift_stop =
false;
248 }
else if (!eg_timer_shift_stop && ((eg_timer >> 16) & 1)) {
249 eg_timer_shift = CYCLES;
250 eg_timer_shift_stop =
true;
253 if constexpr (CYCLES == 0) {
254 if ((eg_counter_state & 1) == 0) {
255 eg_timer_lock = eg_timer & 3;
256 eg_timer_shift_lock = (eg_timer_shift > 13) ? 0 : eg_timer_shift;
258 attackPtr = attack[eg_timer_shift_lock][eg_timer_lock];
259 auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
260 releasePtr = releaseData[idx];
262 if (eg_counter_state == 3) {
263 eg_timer = (eg_timer + 1) & 0x3ffff;
270template<u
int32_t CYCLES>
ALWAYS_INLINE bool YM2413::envelopeGenerate1()
272 int32_t level = eg_level[(CYCLES + 16) % 18];
273 bool prev2_eg_off = eg_off[(CYCLES + 16) & 1];
274 bool prev2_eg_kon = eg_kon[(CYCLES + 16) & 1];
275 bool prev2_eg_dokon = eg_dokon[(CYCLES + 16) % 18];
277 auto state = eg_state[(CYCLES + 16) % 18];
278 if (prev2_eg_dokon) [[unlikely]] {
280 }
else if (!prev2_eg_kon) {
284 }
else if ((state ==
EgState::decay) && ((level >> 3) == eg_sl[CYCLES & 1])) [[unlikely]] {
288 auto prev2_rate = eg_rate[(CYCLES + 16) & 1];
291 : ((prev2_rate >= 60) && prev2_eg_dokon) ? 0x00
293 auto step = [&]() ->
int {
296 if (prev2_eg_kon && (level != 0)) [[likely]] {
297 return (level ^ 0xfff) >> attackPtr[prev2_rate];
301 if ((level >> 3) == eg_sl[CYCLES & 1])
return 0;
305 if (!prev2_eg_off && !prev2_eg_dokon) {
306 return releasePtr[prev2_rate];
314 eg_level[(CYCLES + 16) % 18] = narrow_cast<uint8_t>(next_level + step);
316 return level == 0x7f;
319template<u
int32_t CYCLES>
ALWAYS_INLINE void YM2413::envelopeGenerate2(
const Patch& patch1,
bool use_rm_patches)
321 constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
322 constexpr uint32_t ch = CH_OFFSET[CYCLES];
324 bool new_eg_off = eg_level[CYCLES] >= 124;
325 eg_off[CYCLES & 1] = new_eg_off;
327 auto sk = sk_on[CH_OFFSET[CYCLES]];
328 bool new_eg_kon = [&]() {
329 bool result = sk & 1;
334 result |= bool(rhythm & 0x10);
337 result |= bool(rhythm & 0x08);
340 result |= bool(rhythm & 0x04);
343 result |= bool(rhythm & 0x02);
346 result |= bool(rhythm & 0x01);
354 eg_kon[CYCLES & 1] = new_eg_kon;
357 auto state_rate = eg_state[CYCLES];
358 if (state_rate ==
EgState::release && new_eg_kon && new_eg_off) [[unlikely]] {
360 eg_dokon[CYCLES] =
true;
362 eg_dokon[CYCLES] =
false;
366 if (!new_eg_kon && !(sk & 2) && mcsel == 1 && !patch1.et[mcsel]) {
373 if (!new_eg_kon && !mcsel && !tom_or_hh) {
378 : (state_rate ==
EgState::sustain) ? (patch1.et[mcsel] ? (0 * 4) : patch1.rr4[mcsel])
379 : ((sk & 2) ? (5 * 4) : patch1.rr4[mcsel]);
382 eg_rate[CYCLES & 1] = narrow_cast<uint8_t>([&]() {
383 if (rate4 == 0)
return 0;
384 auto tmp = rate4 + (p_ksr_freq[ch] >> patch1.ksr_t[mcsel]);
385 return (tmp < 0x40) ? tmp
386 : (0x3c | (tmp & 3));
390template<u
int32_t CYCLES,
bool TEST_MODE>
ALWAYS_INLINE void YM2413::doLFO(
bool& lfo_am_car)
392 if constexpr (TEST_MODE) {
394 if constexpr (CYCLES == 17) {
396 if (((lfo_counter & 0x3ff) == 0) || (testMode & 8)) {
397 lfo_vib_counter = (lfo_vib_counter + 1) & 7;
398 lfo_vib = VIB_TAB[lfo_vib_counter];
400 lfo_am_step = (lfo_counter & 0x3f) == 0;
404 auto am_inc = ((lfo_am_step || (testMode & 8)) && CYCLES < 9)
405 ? (lfo_am_dir | (CYCLES == 0))
408 if constexpr (CYCLES == 0) {
409 if (lfo_am_dir && (lfo_am_counter & 0x7f) == 0) {
411 }
else if (!lfo_am_dir && (lfo_am_counter & 0x69) == 0x69) {
416 auto am_bit = (lfo_am_counter & 1) + am_inc + ((CYCLES < 9) ? lfo_am_car :
false);
417 if constexpr (CYCLES < 8) {
418 lfo_am_car = am_bit & 2;
420 lfo_am_counter = uint16_t(((am_bit & 1) << 8) | (lfo_am_counter >> 1));
425 lfo_vib = VIB_TAB[lfo_vib_counter];
428 lfo_am_counter &= 0xff;
431 if constexpr (CYCLES == 17) {
432 int delta = lfo_am_dir ? -1 : 1;
434 if (lfo_am_dir && (lfo_am_counter & 0x7f) == 0) {
436 }
else if (!lfo_am_dir && (lfo_am_counter & 0x69) == 0x69) {
441 lfo_am_counter = (lfo_am_counter + delta) & 0x1ff;
445 if (((lfo_counter & 0x3ff) == 0)) {
446 lfo_vib_counter = (lfo_vib_counter + 1) & 7;
447 lfo_vib = VIB_TAB[lfo_vib_counter];
449 lfo_am_step = (lfo_counter & 0x3f) == 0;
452 if constexpr (CYCLES == 17) {
453 lfo_am_out = (lfo_am_counter >> 3) & 0x0f;
457template<u
int32_t CYCLES,
bool TEST_MODE>
ALWAYS_INLINE void YM2413::doRhythm()
459 if constexpr (TEST_MODE) {
460 bool nbit = (rm_noise ^ (rm_noise >> 14)) & 1;
461 nbit |= bool(testMode & 2);
462 rm_noise = (nbit << 22) | (rm_noise >> 1);
469 if constexpr (CYCLES == 17) {
470 rm_noise = ((rm_noise & 0x1ff) << 14)
471 ^ ((rm_noise & 0x3ffff) << 5)
472 ^ (rm_noise & 0x7fc000)
473 ^ ((rm_noise >> 9) & 0x3fe0)
479template<u
int32_t CYCLES>
ALWAYS_INLINE uint32_t YM2413::getPhaseMod(uint8_t fb_t)
481 bool ismod2 = ((rhythm & 0x20) && (CYCLES ==
one_of(12u, 13u)))
483 : (((CYCLES + 4) / 3) & 1);
484 bool ismod3 = ((rhythm & 0x20) && (CYCLES ==
one_of(15u, 16u)))
486 : (((CYCLES + 1) / 3) & 1);
488 if (ismod3)
return op_mod << 1;
490 constexpr uint32_t cycles9 = (CYCLES + 3) % 9;
491 uint32_t op_fbsum = (op_fb1[cycles9] + op_fb2[cycles9]) & 0x7fffffff;
492 return op_fbsum >> fb_t;
497template<u
int32_t CYCLES>
ALWAYS_INLINE void YM2413::doRegWrite()
499 if (write_fm_cycle == CYCLES) [[unlikely]] {
500 doRegWrite(CYCLES % 9);
504void YM2413::changeFnumBlock(uint32_t ch)
506 static constexpr std::array<uint8_t, 16> KSL_TABLE = {
507 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64
509 p_ksl[ch] = narrow_cast<uint8_t>(
std::max(0, KSL_TABLE[fnum[ch] >> 5] - ((8 - block[ch]) << 3)) << 1);
510 p_incr[ch] = narrow_cast<uint16_t>(fnum[ch] << block[ch]);
511 p_ksr_freq[ch] = uint8_t((block[ch] << 1) | (fnum[ch] >> 8));
516 if (write_address < 0x40) {
517 write_fm_cycle = uint8_t(-1);
518 doRegWrite(write_address & 0xf0, channel, fm_data);
520 write_address -= 0x40;
524void YM2413::doRegWrite(uint8_t regBlock, uint8_t channel, uint8_t data)
528 fnum[channel] = uint16_t((fnum[channel] & 0x100) | data);
529 changeFnumBlock(channel);
532 fnum[channel] = uint16_t((fnum[channel] & 0xff) | ((data & 1) << 8));
533 block[channel] = (data >> 1) & 7;
534 changeFnumBlock(channel);
535 sk_on[channel] = (data >> 4) & 3;
538 vol8[channel] = uint8_t((data & 0x0f) << (2 + 1));
539 inst[channel] = (data >> 4) & 0x0f;
540 p_inst[channel] = &patches[inst[channel]];
547 if (writes[CYCLES].port != uint8_t(-1)) [[unlikely]] {
548 doIO((CYCLES + 1) % 18, writes[CYCLES]);
552NEVER_INLINE void YM2413::doIO(uint32_t cycles_plus_1, Write& write)
554 write_data = write.value;
557 if (write_address < 0x10) {
558 doModeWrite(write_address, write.value);
559 }
else if (write_address < 0x40) {
560 write_fm_cycle = write_address & 0xf;
561 fm_data = write.value;
562 if (!fast_fm_rewrite && (write_fm_cycle == cycles_plus_1)) {
563 write_address += 0x40;
569 fast_fm_rewrite =
true;
573 write_address = write.value;
574 write_fm_cycle = uint8_t(-1);
575 fast_fm_rewrite =
false;
578 write.port = uint8_t(-1);
581void YM2413::doModeWrite(uint8_t address, uint8_t value)
583 auto slot = address & 1;
587 patches[0].setMulti(slot, value & 0x0f);
588 patches[0].setKSR(slot, (value >> 4) & 1);
589 patches[0].et[slot] = (value >> 5) & 1;
590 patches[0].vib[slot] = (value >> 6) & 1;
591 patches[0].setAM(slot, (value >> 7) & 1);
595 patches[0].setKSL(0, (value >> 6) & 3);
596 patches[0].setTL(value & 0x3f);
600 patches[0].setKSL(1, (value >> 6) & 3);
601 patches[0].dcm = (value >> 3) & 3;
602 patches[0].setFB(value & 7);
607 patches[0].setDR(slot, value & 0x0f);
608 patches[0].setAR(slot, (value >> 4) & 0x0f);
613 patches[0].setRR(slot, value & 0x0f);
614 patches[0].sl[slot] = (value >> 4) & 0x0f;
618 rhythm = value & 0x3f;
622 testMode = value & 0x0f;
627template<u
int32_t CYCLES>
ALWAYS_INLINE void YM2413::doOperator(std::span<float*, 9 + 5> out,
bool eg_silent)
629 bool ismod1 = ((rhythm & 0x20) && (CYCLES ==
one_of(14u, 15u)))
631 : (((CYCLES + 2) / 3) & 1);
632 constexpr bool is_next_mod3 = ((CYCLES + 2) / 3) & 1;
634 auto output = [&]() -> int32_t {
635 if (eg_silent)
return 0;
636 auto prev2_phase = op_phase[(CYCLES - 2) & 1];
637 uint8_t quarter = narrow_cast<uint8_t>((prev2_phase & 0x100) ? ~prev2_phase : prev2_phase);
638 auto logSin = logSinTab[quarter];
639 auto op_level =
std::min(4095, logSin + (eg_out[(CYCLES - 2) & 1] << 4));
640 uint32_t op_exp_m = expTab[op_level & 0xff];
641 auto op_exp_s = op_level >> 8;
642 if (prev2_phase & 0x200) {
643 return (c_dcm[(CYCLES + 16) % 3] & (ismod1 ? 1 : 2))
645 : ~(op_exp_m >> op_exp_s);
647 return narrow<int32_t>(op_exp_m >> op_exp_s);
652 constexpr uint32_t cycles9 = (CYCLES + 1) % 9;
653 op_fb2[cycles9] = op_fb1[cycles9];
654 op_fb1[cycles9] = narrow_cast<int16_t>(output);
656 channelOutput<CYCLES>(out, output >> 3);
659 op_mod = output & 0x1ff;
663template<u
int32_t CYCLES,
bool TEST_MODE>
ALWAYS_INLINE uint32_t YM2413::getPhase(uint8_t& rm_hh_bits)
665 uint32_t phase = pg_phase[CYCLES];
668 if constexpr (CYCLES == 12) {
669 rm_hh_bits = narrow_cast<uint8_t>(phase >> (2 + 9));
670 }
else if (CYCLES == 16 && (rhythm & 0x20)) {
671 rm_tc_bits = narrow_cast<uint8_t>(phase >> 8);
675 auto rm_bit = [&]() {
676 bool rm_hh_bit2 = (rm_hh_bits >> (2 - 2)) & 1;
677 bool rm_hh_bit3 = (rm_hh_bits >> (3 - 2)) & 1;
678 bool rm_hh_bit7 = (rm_hh_bits >> (7 - 2)) & 1;
679 bool rm_tc_bit3 = (rm_tc_bits >> (3 + 9 - 8)) & 1;
680 bool rm_tc_bit5 = (rm_tc_bits >> (5 + 9 - 8)) & 1;
681 return (rm_hh_bit2 ^ rm_hh_bit7)
682 | (rm_hh_bit3 ^ rm_tc_bit5)
683 | (rm_tc_bit3 ^ rm_tc_bit5);
685 auto noise_bit = [&]() {
687 return (rm_noise >> (TEST_MODE ? 0 : (CYCLES + 1))) & 1;
692 return (b << 9) | ((b ^ noise_bit()) ? 0xd0 : 0x34);
695 auto rm_hh_bit8 = (rm_hh_bits >> (8 - 2)) & 1;
696 return (rm_hh_bit8 << 9) | ((rm_hh_bit8 ^ noise_bit()) << 8);
699 return (rm_bit() << 9) | 0x100;
707template<u
int32_t CYCLES>
ALWAYS_INLINE uint32_t YM2413::phaseCalcIncrement(
const Patch& patch1)
const
709 constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
710 constexpr uint32_t ch = CH_OFFSET[CYCLES];
712 uint32_t incr = [&]() {
714 if (patch1.vib[mcsel]) {
717 uint32_t freq = fnum[ch] << 1;
718 freq += (int(freq) * lfo_vib) / 256;
719 return (freq << block[ch]) >> 1;
721 return uint32_t(p_incr[ch]);
724 return (incr * patch1.multi_t[mcsel]) >> 1;
727template<u
int32_t CYCLES>
ALWAYS_INLINE bool YM2413::keyOnEvent()
const
729 bool ismod = ((rhythm & 0x20) && (CYCLES ==
one_of(12u, 13u)))
731 : (((CYCLES + 4) / 3) & 1);
732 return ismod ? eg_dokon[(CYCLES + 3) % 18]
736template<u
int32_t CYCLES,
bool TEST_MODE>
ALWAYS_INLINE void YM2413::incrementPhase(uint32_t phase_incr,
bool key_on_event)
738 uint32_t pg_phase_next = ((TEST_MODE && (testMode & 4)) || key_on_event)
741 pg_phase[CYCLES] = pg_phase_next + phase_incr;
744template<u
int32_t CYCLES>
ALWAYS_INLINE void YM2413::channelOutput(std::span<float*, 9 + 5> out, int32_t ch_out)
746 auto outF = narrow_cast<float>(ch_out);
748 case 4: *out[ 0]++ += outF;
break;
749 case 5: *out[ 1]++ += outF;
break;
750 case 6: *out[ 2]++ += outF;
break;
751 case 10: *out[ 3]++ += outF;
break;
752 case 11: *out[ 4]++ += outF;
break;
753 case 12: *out[ 5]++ += outF;
break;
754 case 14: *out[ 9]++ += (rhythm & 0x20) ? 2.0f * outF : 0.0f;
break;
755 case 15: *out[10]++ += narrow_cast<float>(delay10);
756 delay10 = (rhythm & 0x20) ? 2 * ch_out : 0;
break;
757 case 16: *out[ 6]++ += narrow_cast<float>(delay6);
758 *out[11]++ += narrow_cast<float>(delay11);
759 delay6 = (rhythm & 0x20) ? 0 : ch_out;
760 delay11 = (rhythm & 0x20) ? 2 * ch_out : 0;
break;
761 case 17: *out[ 7]++ += narrow_cast<float>(delay7);
762 *out[12]++ += narrow_cast<float>(delay12);
763 delay7 = (rhythm & 0x20) ? 0 : ch_out;
764 delay12 = (rhythm & 0x20) ? 2 * ch_out : 0;
break;
765 case 0: *out[ 8]++ += (rhythm & 0x20) ? 0.0f : outF;
766 *out[13]++ += (rhythm & 0x20) ? 2.0f * outF : 0.0f;
break;
772template<u
int32_t CYCLES,
bool TEST_MODE>
ALWAYS_INLINE uint8_t YM2413::envelopeOutput(uint32_t ksltl, int8_t am_t)
const
774 if (TEST_MODE && (testMode & 1)) {
777 int32_t level = eg_level[CYCLES] + ksltl + (am_t & lfo_am_out);
778 return narrow_cast<uint8_t>(
std::min(127, level));
781template<u
int32_t CYCLES,
bool TEST_MODE>
784 if constexpr (CYCLES == 11) {
787 l.use_rm_patches = rhythm & 0x20;
789 const Patch& patch1 = preparePatch1<CYCLES>(l.use_rm_patches);
790 uint32_t ksltl = envelopeKSLTL<CYCLES>(patch1, l.use_rm_patches);
791 envelopeTimer1<CYCLES>();
792 bool eg_silent = envelopeGenerate1<CYCLES>();
793 envelopeTimer2<CYCLES, TEST_MODE>(l.eg_timer_carry);
794 envelopeGenerate2<CYCLES>(patch1, l.use_rm_patches);
795 bool key_on_event = keyOnEvent<CYCLES>();
797 doLFO<CYCLES, TEST_MODE>(l.lfo_am_car);
798 doRhythm<CYCLES, TEST_MODE>();
799 uint32_t phaseMod = getPhaseMod<CYCLES>(patch1.fb_t);
801 constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
802 eg_sl[CYCLES & 1] = patch1.sl[mcsel];
803 auto patch2_am_t = patch1.am_t[mcsel];
805 uint32_t phase_incr = phaseCalcIncrement<CYCLES>(patch1);
806 c_dcm[CYCLES % 3] = patch1.dcm;
808 doRegWrite<CYCLES>();
811 doOperator<CYCLES>(l.out, eg_silent);
813 uint32_t pg_out = getPhase<CYCLES, TEST_MODE>(l.rm_hh_bits);
814 op_phase[CYCLES & 1] = narrow_cast<uint16_t>(phaseMod + pg_out);
815 incrementPhase<CYCLES, TEST_MODE>(phase_incr, key_on_event);
817 eg_out[CYCLES & 1] = envelopeOutput<CYCLES, TEST_MODE>(ksltl, patch2_am_t);
822 std::array<float*, 9 + 5> out;
826 if (test_mode_active) [[unlikely]] {
827 repeat(n, [&] { step18<true >(out); });
829 repeat(n, [&] { step18<false>(out); });
831 test_mode_active = testMode;
834template<
bool TEST_MODE>
835NEVER_INLINE void YM2413::step18(std::span<float*, 9 + 5> out)
838 l.use_rm_patches =
false;
839 l.lfo_am_car =
false;
841 step< 0, TEST_MODE>(l);
842 step< 1, TEST_MODE>(l);
843 step< 2, TEST_MODE>(l);
844 step< 3, TEST_MODE>(l);
845 step< 4, TEST_MODE>(l);
846 step< 5, TEST_MODE>(l);
847 step< 6, TEST_MODE>(l);
848 step< 7, TEST_MODE>(l);
849 step< 8, TEST_MODE>(l);
850 step< 9, TEST_MODE>(l);
851 step<10, TEST_MODE>(l);
852 step<11, TEST_MODE>(l);
853 step<12, TEST_MODE>(l);
854 step<13, TEST_MODE>(l);
855 step<14, TEST_MODE>(l);
856 step<15, TEST_MODE>(l);
857 step<16, TEST_MODE>(l);
858 step<17, TEST_MODE>(l);
860 allowed_offset = std::max<int>(0, allowed_offset - 18);
874 if (speedUpHack) [[unlikely]] {
875 while (cycle_offset < allowed_offset) [[unlikely]] {
877 std::array<float*, 9 + 5> dummy = {
878 &d, &d, &d, &d, &d, &d, &d, &d, &d,
881 step18<false>(dummy);
886 allowed_offset = ((port ? 84 : 12) / 4) + cycle_offset;
889 writes[cycle_offset] = {port, value};
890 if (port && (write_address == 0xf)) {
891 test_mode_active =
true;
906 doModeWrite(reg, value);
908 if (uint8_t ch = reg & 0xf; ch < 9) {
909 doRegWrite(reg & 0xf0, ch, value);
916 return regs[reg & 63];
921 return 1.0f / 256.0f;
926 speedUpHack = speed > 1.0;
932static constexpr std::initializer_list<enum_string<YM2413NukeYKT::YM2413::EgState>> egStateInfo = {
940namespace YM2413NukeYKT {
942template<
typename Archive>
945 ar.serialize(
"port", port,
949template<
typename Archive>
952 ar.serialize(
"writes", writes,
953 "write_data", write_data,
955 "write_address", write_address,
956 "write_fm_cycle", write_fm_cycle,
957 "fast_fm_rewrite", fast_fm_rewrite,
958 "test_mode_active", test_mode_active);
960 ar.serialize(
"eg_timer", eg_timer,
963 "eg_counter_state", eg_counter_state,
964 "eg_timer_shift", eg_timer_shift,
965 "eg_timer_shift_lock", eg_timer_shift_lock,
966 "eg_timer_lock", eg_timer_lock,
967 "eg_state", eg_state,
968 "eg_level", eg_level,
970 "eg_dokon", eg_dokon,
973 "eg_timer_shift_stop", eg_timer_shift_stop,
974 "pg_phase", pg_phase);
976 ar.serialize(
"op_fb1", op_fb1,
979 "op_phase", op_phase,
980 "lfo_counter", lfo_counter,
981 "lfo_am_counter", lfo_am_counter,
982 "lfo_vib_counter", lfo_vib_counter,
983 "lfo_am_out", lfo_am_out,
984 "lfo_am_step", lfo_am_step,
985 "lfo_am_dir", lfo_am_dir);
987 ar.serialize(
"rm_noise", rm_noise,
988 "rm_tc_bits", rm_tc_bits,
993 if constexpr (Archive::IS_LOADER) {
995 attackPtr = attack[eg_timer_shift_lock][eg_timer_lock];
996 auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
997 releasePtr = releaseData[idx];
999 lfo_vib = VIB_TAB[lfo_vib_counter];
1001 delay6 = delay7 = delay10 = delay11 = delay12 = 0;
1006 for (
auto i :
xrange(uint8_t(64))) {
Abstract interface for the YM2413 core.
uint8_t peekReg(uint8_t reg) const override
Read from a YM2413 register (for debug).
void writePort(bool port, uint8_t value, int cycle_offset) override
Write to the YM2413 register/data port.
void setSpeed(double speed) override
Sets real-time speed factor (aka the openMSX 'speed' setting).
float getAmplificationFactor() const override
Returns normalization factor.
void pokeReg(uint8_t reg, uint8_t value) override
Write to a YM2413 register (for debug).
void serialize(Archive &ar, unsigned version)
void generateChannels(std::span< float *, 9+5 > out, uint32_t n) override
void reset() override
Reset this YM2413 core.
unsigned findFirstSet(uint32_t x)
Find the least significant bit that is set.
constexpr double round(double x)
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
constexpr bool is_rm_cycle(int cycle)
constexpr RmNum rm_for_cycle(int cycle)
This file implemented 3 utility functions:
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
void serialize(Archive &ar, T &t, unsigned version)
constexpr void fill(ForwardRange &&range, const T &value)
auto copy(InputRange &&range, OutputIter out)
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr void repeat(T n, Op op)
Repeat the given operation 'op' 'n' times.
constexpr auto xrange(T e)