43namespace YM2413NukeYKT {
47 return (11 <= cycle) && (cycle <= 16);
54static constexpr auto logSinTab = [] {
55 std::array<uint16_t, 256> result = {};
57 for (
int i = 0; i < 256; ++i) {
58 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));
62static constexpr auto expTab = [] {
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::exp2<6>(
double(255 - i) / 256.0)) * 1024.0));
71constexpr std::array<YM2413::Patch, 15> YM2413::m_patches = {
72 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}},
73 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}},
74 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}},
75 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}},
76 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}},
77 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}},
78 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}},
79 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}},
80 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}},
81 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}},
82 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}},
83 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}},
84 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}},
85 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}},
86 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}},
90 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}},
91 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}},
92 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}},
93 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}},
94 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}},
95 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}},
98static constexpr std::array<uint8_t, 18> CH_OFFSET = {
99 1, 2, 0, 1, 2, 3, 4, 5, 3, 4, 5, 6, 7, 8, 6, 7, 8, 0
102static constexpr std::array<int8_t, 8> VIB_TAB = {0, 1, 2, 1, 0, -1, -2, -1};
112#include "YM2413NukeYktTables.ii"
116 : attackPtr (attack[0][0])
117 , releasePtr(releaseData[0])
126 for (
auto& w : writes) w.port = uint8_t(-1);
127 write_fm_cycle = uint8_t(-1);
128 write_data = fm_data = write_address = 0;
129 fast_fm_rewrite = test_mode_active =
false;
131 eg_counter_state = 3;
132 eg_timer = eg_timer_shift = eg_timer_shift_lock = eg_timer_lock = 0;
133 attackPtr =
attack[eg_timer_shift_lock][eg_timer_lock];
134 auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
135 releasePtr = releaseData[idx];
139 eg_rate[0] = eg_rate[1] = 0;
140 eg_sl[0] = eg_sl[1] = eg_out[0] = eg_out[1] = 0;
141 eg_timer_shift_stop =
false;
142 eg_kon[0] = eg_kon[1] = eg_off[0] = eg_off[1] =
false;
149 op_phase[0] = op_phase[1] = 0;
151 lfo_counter = lfo_am_counter = 0;
152 lfo_vib_counter = lfo_am_out = 0;
153 lfo_vib = VIB_TAB[lfo_vib_counter];
154 lfo_am_step = lfo_am_dir =
false;
161 for (
auto i :
xrange(9)) {
162 p_inst[i] = &patches[inst[i]];
165 rhythm = testMode = 0;
166 patches[0] = Patch();
167 c_dcm[0] = c_dcm[1] = c_dcm[2] = 0;
172 delay6 = delay7 = delay10 = delay11 = delay12 = 0;
178template<u
int32_t CYCLES>
ALWAYS_INLINE const YM2413::Patch& YM2413::preparePatch1(
bool use_rm_patches)
const
182 : *p_inst[CH_OFFSET[CYCLES]];
185template<u
int32_t CYCLES>
ALWAYS_INLINE uint32_t YM2413::envelopeKSLTL(
const Patch& patch1,
bool use_rm_patches)
const
187 constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
188 constexpr uint32_t ch = CH_OFFSET[CYCLES];
190 auto ksl = uint32_t(p_ksl[ch]) >> patch1.ksl_t[mcsel];
191 auto tl2 = [&]() -> uint32_t {
193 return inst[ch] << (2 + 1);
194 }
else if (mcsel == 1) {
203template<u
int32_t CYCLES>
ALWAYS_INLINE void YM2413::envelopeTimer1()
205 if constexpr (CYCLES == 0) {
206 eg_counter_state = (eg_counter_state + 1) & 3;
207 auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
208 releasePtr = releaseData[idx];
212template<u
int32_t CYCLES,
bool TEST_MODE>
ALWAYS_INLINE void YM2413::envelopeTimer2(
bool& eg_timer_carry)
214 if constexpr (TEST_MODE) {
215 if (CYCLES == 0 && (eg_counter_state & 1) == 0) {
216 eg_timer_lock = eg_timer & 3;
217 eg_timer_shift_lock = (eg_timer_shift <= 13) ? eg_timer_shift : 0;
220 attackPtr =
attack[eg_timer_shift_lock][eg_timer_lock];
221 auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
222 releasePtr = releaseData[idx];
225 bool timer_inc = (eg_counter_state != 3) ?
false
226 : (CYCLES == 0) ? true
228 auto timer_bit = (eg_timer & 1) + timer_inc;
229 eg_timer_carry = timer_bit & 2;
230 eg_timer = ((timer_bit & 1) << 17) | (eg_timer >> 1);
232 const auto& write = writes[CYCLES];
233 auto data = (write.port != uint8_t(-1)) ? write.value : write_data;
235 eg_timer |= (data << (16 - 2)) & 0x10000;
238 if constexpr (CYCLES == 0) {
239 eg_timer_shift_stop =
false;
240 }
else if (!eg_timer_shift_stop && ((eg_timer >> 16) & 1)) {
241 eg_timer_shift = CYCLES;
242 eg_timer_shift_stop =
true;
245 if constexpr (CYCLES == 0) {
246 if ((eg_counter_state & 1) == 0) {
247 eg_timer_lock = eg_timer & 3;
248 eg_timer_shift_lock = (eg_timer_shift > 13) ? 0 : eg_timer_shift;
250 attackPtr =
attack[eg_timer_shift_lock][eg_timer_lock];
251 auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
252 releasePtr = releaseData[idx];
254 if (eg_counter_state == 3) {
255 eg_timer = (eg_timer + 1) & 0x3ffff;
262template<u
int32_t CYCLES>
ALWAYS_INLINE bool YM2413::envelopeGenerate1()
264 int32_t level = eg_level[(CYCLES + 16) % 18];
265 bool prev2_eg_off = eg_off[(CYCLES + 16) & 1];
266 bool prev2_eg_kon = eg_kon[(CYCLES + 16) & 1];
267 bool prev2_eg_dokon = eg_dokon[(CYCLES + 16) % 18];
270 auto state = eg_state[(CYCLES + 16) % 18];
271 if (prev2_eg_dokon) [[unlikely]] {
272 eg_state[(CYCLES + 16) % 18] =
attack;
273 }
else if (!prev2_eg_kon) {
274 eg_state[(CYCLES + 16) % 18] =
release;
275 }
else if ((state ==
attack) && (level == 0)) [[unlikely]] {
276 eg_state[(CYCLES + 16) % 18] =
decay;
277 }
else if ((state ==
decay) && ((level >> 3) == eg_sl[CYCLES & 1])) [[unlikely]] {
278 eg_state[(CYCLES + 16) % 18] =
sustain;
281 auto prev2_rate = eg_rate[(CYCLES + 16) & 1];
283 = (state !=
attack && prev2_eg_off && !prev2_eg_dokon) ? 0x7f
284 : ((prev2_rate >= 60) && prev2_eg_dokon) ? 0x00
286 auto step = [&]() ->
int {
289 if (prev2_eg_kon && (level != 0)) [[likely]] {
290 return (level ^ 0xfff) >> attackPtr[prev2_rate];
294 if ((level >> 3) == eg_sl[CYCLES & 1])
return 0;
298 if (!prev2_eg_off && !prev2_eg_dokon) {
299 return releasePtr[prev2_rate];
307 eg_level[(CYCLES + 16) % 18] = narrow_cast<uint8_t>(next_level + step);
309 return level == 0x7f;
312template<u
int32_t CYCLES>
ALWAYS_INLINE void YM2413::envelopeGenerate2(
const Patch& patch1,
bool use_rm_patches)
314 constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
315 constexpr uint32_t ch = CH_OFFSET[CYCLES];
317 bool new_eg_off = eg_level[CYCLES] >= 124;
318 eg_off[CYCLES & 1] = new_eg_off;
320 auto sk = sk_on[CH_OFFSET[CYCLES]];
321 bool new_eg_kon = [&]() {
322 bool result = sk & 1;
328 result |= bool(rhythm & 0x10);
331 result |= bool(rhythm & 0x08);
334 result |= bool(rhythm & 0x04);
337 result |= bool(rhythm & 0x02);
340 result |= bool(rhythm & 0x01);
348 eg_kon[CYCLES & 1] = new_eg_kon;
352 auto state_rate = eg_state[CYCLES];
353 if (state_rate ==
release && new_eg_kon && new_eg_off) [[unlikely]] {
355 eg_dokon[CYCLES] =
true;
357 eg_dokon[CYCLES] =
false;
361 if (!new_eg_kon && !(sk & 2) && mcsel == 1 && !patch1.et[mcsel]) {
364 if (new_eg_kon && eg_state[CYCLES] ==
release && !new_eg_off) {
368 if (!new_eg_kon && !mcsel && !tom_or_hh) {
371 return (state_rate ==
attack ) ? patch1.ar4[mcsel]
372 : (state_rate ==
decay ) ? patch1.dr4[mcsel]
373 : (state_rate ==
sustain) ? (patch1.et[mcsel] ? (0 * 4) : patch1.rr4[mcsel])
374 : ((sk & 2) ? (5 * 4) : patch1.rr4[mcsel]);
377 eg_rate[CYCLES & 1] = narrow_cast<uint8_t>([&]() {
378 if (rate4 == 0)
return 0;
379 auto tmp = rate4 + (p_ksr_freq[ch] >> patch1.ksr_t[mcsel]);
380 return (tmp < 0x40) ? tmp
381 : (0x3c | (tmp & 3));
385template<u
int32_t CYCLES,
bool TEST_MODE>
ALWAYS_INLINE void YM2413::doLFO(
bool& lfo_am_car)
387 if constexpr (TEST_MODE) {
389 if constexpr (CYCLES == 17) {
391 if (((lfo_counter & 0x3ff) == 0) || (testMode & 8)) {
392 lfo_vib_counter = (lfo_vib_counter + 1) & 7;
393 lfo_vib = VIB_TAB[lfo_vib_counter];
395 lfo_am_step = (lfo_counter & 0x3f) == 0;
399 auto am_inc = ((lfo_am_step || (testMode & 8)) && CYCLES < 9)
400 ? (lfo_am_dir | (CYCLES == 0))
403 if constexpr (CYCLES == 0) {
404 if (lfo_am_dir && (lfo_am_counter & 0x7f) == 0) {
406 }
else if (!lfo_am_dir && (lfo_am_counter & 0x69) == 0x69) {
411 auto am_bit = (lfo_am_counter & 1) + am_inc + ((CYCLES < 9) ? lfo_am_car :
false);
412 if constexpr (CYCLES < 8) {
413 lfo_am_car = am_bit & 2;
415 lfo_am_counter = uint16_t(((am_bit & 1) << 8) | (lfo_am_counter >> 1));
420 lfo_vib = VIB_TAB[lfo_vib_counter];
423 lfo_am_counter &= 0xff;
426 if constexpr (CYCLES == 17) {
427 int delta = lfo_am_dir ? -1 : 1;
429 if (lfo_am_dir && (lfo_am_counter & 0x7f) == 0) {
431 }
else if (!lfo_am_dir && (lfo_am_counter & 0x69) == 0x69) {
436 lfo_am_counter = (lfo_am_counter + delta) & 0x1ff;
440 if ((lfo_counter & 0x3ff) == 0) {
441 lfo_vib_counter = (lfo_vib_counter + 1) & 7;
442 lfo_vib = VIB_TAB[lfo_vib_counter];
444 lfo_am_step = (lfo_counter & 0x3f) == 0;
447 if constexpr (CYCLES == 17) {
448 lfo_am_out = (lfo_am_counter >> 3) & 0x0f;
452template<u
int32_t CYCLES,
bool TEST_MODE>
ALWAYS_INLINE void YM2413::doRhythm()
454 if constexpr (TEST_MODE) {
455 bool nbit = (rm_noise ^ (rm_noise >> 14)) & 1;
456 nbit |= bool(testMode & 2);
457 rm_noise = (nbit << 22) | (rm_noise >> 1);
464 if constexpr (CYCLES == 17) {
465 rm_noise = ((rm_noise & 0x1ff) << 14)
466 ^ ((rm_noise & 0x3ffff) << 5)
467 ^ (rm_noise & 0x7fc000)
468 ^ ((rm_noise >> 9) & 0x3fe0)
474template<u
int32_t CYCLES>
ALWAYS_INLINE uint32_t YM2413::getPhaseMod(uint8_t fb_t)
476 bool ismod2 = ((rhythm & 0x20) && (CYCLES ==
one_of(12u, 13u)))
478 : (((CYCLES + 4) / 3) & 1);
479 bool ismod3 = ((rhythm & 0x20) && (CYCLES ==
one_of(15u, 16u)))
481 : (((CYCLES + 1) / 3) & 1);
483 if (ismod3)
return op_mod << 1;
485 constexpr uint32_t cycles9 = (CYCLES + 3) % 9;
486 uint32_t op_fbsum = (op_fb1[cycles9] + op_fb2[cycles9]) & 0x7fffffff;
487 return op_fbsum >> fb_t;
492template<u
int32_t CYCLES>
ALWAYS_INLINE void YM2413::doRegWrite()
494 if (write_fm_cycle == CYCLES) [[unlikely]] {
495 doRegWrite(CYCLES % 9);
499void YM2413::changeFnumBlock(uint32_t ch)
501 static constexpr std::array<uint8_t, 16> KSL_TABLE = {
502 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64
504 p_ksl[ch] = narrow_cast<uint8_t>(std::max(0, KSL_TABLE[fnum[ch] >> 5] - ((8 - block[ch]) << 3)) << 1);
505 p_incr[ch] = narrow_cast<uint16_t>(fnum[ch] << block[ch]);
506 p_ksr_freq[ch] = uint8_t((block[ch] << 1) | (fnum[ch] >> 8));
511 if (write_address < 0x40) {
512 write_fm_cycle = uint8_t(-1);
513 doRegWrite(write_address & 0xf0, channel, fm_data);
515 write_address -= 0x40;
519void YM2413::doRegWrite(uint8_t regBlock, uint8_t channel, uint8_t data)
523 fnum[channel] = uint16_t((fnum[channel] & 0x100) | data);
524 changeFnumBlock(channel);
527 fnum[channel] = uint16_t((fnum[channel] & 0xff) | ((data & 1) << 8));
528 block[channel] = (data >> 1) & 7;
529 changeFnumBlock(channel);
530 sk_on[channel] = (data >> 4) & 3;
533 vol8[channel] = uint8_t((data & 0x0f) << (2 + 1));
534 inst[channel] = (data >> 4) & 0x0f;
535 p_inst[channel] = &patches[inst[channel]];
542 if (writes[CYCLES].port != uint8_t(-1)) [[unlikely]] {
543 doIO((CYCLES + 1) % 18, writes[CYCLES]);
547NEVER_INLINE void YM2413::doIO(uint32_t cycles_plus_1, Write& write)
549 write_data = write.value;
552 if (write_address < 0x10) {
553 doModeWrite(write_address, write.value);
554 }
else if (write_address < 0x40) {
555 write_fm_cycle = write_address & 0xf;
556 fm_data = write.value;
557 if (!fast_fm_rewrite && (write_fm_cycle == cycles_plus_1)) {
558 write_address += 0x40;
564 fast_fm_rewrite =
true;
568 write_address = write.value;
569 write_fm_cycle = uint8_t(-1);
570 fast_fm_rewrite =
false;
573 write.port = uint8_t(-1);
576void YM2413::doModeWrite(uint8_t address, uint8_t value)
578 auto slot = address & 1;
582 patches[0].setMulti(slot, value & 0x0f);
583 patches[0].setKSR(slot, (value >> 4) & 1);
584 patches[0].et[slot] = (value >> 5) & 1;
585 patches[0].vib[slot] = (value >> 6) & 1;
586 patches[0].setAM(slot, (value >> 7) & 1);
590 patches[0].setKSL(0, (value >> 6) & 3);
591 patches[0].setTL(value & 0x3f);
595 patches[0].setKSL(1, (value >> 6) & 3);
596 patches[0].dcm = (value >> 3) & 3;
597 patches[0].setFB(value & 7);
602 patches[0].setDR(slot, value & 0x0f);
603 patches[0].setAR(slot, (value >> 4) & 0x0f);
608 patches[0].setRR(slot, value & 0x0f);
609 patches[0].sl[slot] = (value >> 4) & 0x0f;
613 rhythm = value & 0x3f;
617 testMode = value & 0x0f;
622template<u
int32_t CYCLES>
ALWAYS_INLINE void YM2413::doOperator(std::span<float*, 9 + 5> out,
bool eg_silent)
624 bool ismod1 = ((rhythm & 0x20) && (CYCLES ==
one_of(14u, 15u)))
626 : (((CYCLES + 2) / 3) & 1);
627 constexpr bool is_next_mod3 = ((CYCLES + 2) / 3) & 1;
629 auto output = [&]() -> int32_t {
630 if (eg_silent)
return 0;
631 auto prev2_phase = op_phase[(CYCLES - 2) & 1];
632 uint8_t quarter = narrow_cast<uint8_t>((prev2_phase & 0x100) ? ~prev2_phase : prev2_phase);
633 auto logSin = logSinTab[quarter];
634 auto op_level = std::min(4095, logSin + (eg_out[(CYCLES - 2) & 1] << 4));
635 uint32_t op_exp_m = expTab[op_level & 0xff];
636 auto op_exp_s = op_level >> 8;
637 if (prev2_phase & 0x200) {
638 return (c_dcm[(CYCLES + 16) % 3] & (ismod1 ? 1 : 2))
640 : ~(op_exp_m >> op_exp_s);
642 return narrow<int32_t>(op_exp_m >> op_exp_s);
647 constexpr uint32_t cycles9 = (CYCLES + 1) % 9;
648 op_fb2[cycles9] = op_fb1[cycles9];
649 op_fb1[cycles9] = narrow_cast<int16_t>(output);
651 channelOutput<CYCLES>(out, output >> 3);
654 op_mod = output & 0x1ff;
658template<u
int32_t CYCLES,
bool TEST_MODE>
ALWAYS_INLINE uint32_t YM2413::getPhase(uint8_t& rm_hh_bits)
660 uint32_t phase = pg_phase[CYCLES];
663 if constexpr (CYCLES == 12) {
664 rm_hh_bits = narrow_cast<uint8_t>(phase >> (2 + 9));
665 }
else if (CYCLES == 16 && (rhythm & 0x20)) {
666 rm_tc_bits = narrow_cast<uint8_t>(phase >> 8);
670 auto rm_bit = [&]() {
671 bool rm_hh_bit2 = (rm_hh_bits >> (2 - 2)) & 1;
672 bool rm_hh_bit3 = (rm_hh_bits >> (3 - 2)) & 1;
673 bool rm_hh_bit7 = (rm_hh_bits >> (7 - 2)) & 1;
674 bool rm_tc_bit3 = (rm_tc_bits >> (3 + 9 - 8)) & 1;
675 bool rm_tc_bit5 = (rm_tc_bits >> (5 + 9 - 8)) & 1;
676 return (rm_hh_bit2 ^ rm_hh_bit7)
677 | (rm_hh_bit3 ^ rm_tc_bit5)
678 | (rm_tc_bit3 ^ rm_tc_bit5);
680 auto noise_bit = [&]() {
682 return (rm_noise >> (TEST_MODE ? 0 : (CYCLES + 1))) & 1;
687 return (b << 9) | ((b ^ noise_bit()) ? 0xd0 : 0x34);
690 auto rm_hh_bit8 = (rm_hh_bits >> (8 - 2)) & 1;
691 return (rm_hh_bit8 << 9) | ((rm_hh_bit8 ^ noise_bit()) << 8);
694 return (rm_bit() << 9) | 0x100;
702template<u
int32_t CYCLES>
ALWAYS_INLINE uint32_t YM2413::phaseCalcIncrement(
const Patch& patch1)
const
704 constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
705 constexpr uint32_t ch = CH_OFFSET[CYCLES];
707 uint32_t incr = [&]() {
709 if (patch1.vib[mcsel]) {
712 uint32_t freq = fnum[ch] << 1;
713 freq += (int(freq) * lfo_vib) / 256;
714 return (freq << block[ch]) >> 1;
716 return uint32_t(p_incr[ch]);
719 return (incr * patch1.multi_t[mcsel]) >> 1;
722template<u
int32_t CYCLES>
ALWAYS_INLINE bool YM2413::keyOnEvent()
const
724 bool ismod = ((rhythm & 0x20) && (CYCLES ==
one_of(12u, 13u)))
726 : (((CYCLES + 4) / 3) & 1);
727 return ismod ? eg_dokon[(CYCLES + 3) % 18]
731template<u
int32_t CYCLES,
bool TEST_MODE>
ALWAYS_INLINE void YM2413::incrementPhase(uint32_t phase_incr,
bool key_on_event)
733 uint32_t pg_phase_next = ((TEST_MODE && (testMode & 4)) || key_on_event)
736 pg_phase[CYCLES] = pg_phase_next + phase_incr;
739template<u
int32_t CYCLES>
ALWAYS_INLINE void YM2413::channelOutput(std::span<float*, 9 + 5> out, int32_t ch_out)
741 auto outF = narrow_cast<float>(ch_out);
743 case 4: *out[ 0]++ += outF;
break;
744 case 5: *out[ 1]++ += outF;
break;
745 case 6: *out[ 2]++ += outF;
break;
746 case 10: *out[ 3]++ += outF;
break;
747 case 11: *out[ 4]++ += outF;
break;
748 case 12: *out[ 5]++ += outF;
break;
749 case 14: *out[ 9]++ += (rhythm & 0x20) ? 2.0f * outF : 0.0f;
break;
750 case 15: *out[10]++ += narrow_cast<float>(delay10);
751 delay10 = (rhythm & 0x20) ? 2 * ch_out : 0;
break;
752 case 16: *out[ 6]++ += narrow_cast<float>(delay6);
753 *out[11]++ += narrow_cast<float>(delay11);
754 delay6 = (rhythm & 0x20) ? 0 : ch_out;
755 delay11 = (rhythm & 0x20) ? 2 * ch_out : 0;
break;
756 case 17: *out[ 7]++ += narrow_cast<float>(delay7);
757 *out[12]++ += narrow_cast<float>(delay12);
758 delay7 = (rhythm & 0x20) ? 0 : ch_out;
759 delay12 = (rhythm & 0x20) ? 2 * ch_out : 0;
break;
760 case 0: *out[ 8]++ += (rhythm & 0x20) ? 0.0f : outF;
761 *out[13]++ += (rhythm & 0x20) ? 2.0f * outF : 0.0f;
break;
767template<u
int32_t CYCLES,
bool TEST_MODE>
ALWAYS_INLINE uint8_t YM2413::envelopeOutput(uint32_t ksltl, int8_t am_t)
const
769 if (TEST_MODE && (testMode & 1)) {
772 int32_t level = eg_level[CYCLES] + ksltl + (am_t & lfo_am_out);
773 return narrow_cast<uint8_t>(std::min(127, level));
776template<u
int32_t CYCLES,
bool TEST_MODE>
779 if constexpr (CYCLES == 11) {
782 l.use_rm_patches = rhythm & 0x20;
784 const Patch& patch1 = preparePatch1<CYCLES>(l.use_rm_patches);
785 uint32_t ksltl = envelopeKSLTL<CYCLES>(patch1, l.use_rm_patches);
786 envelopeTimer1<CYCLES>();
787 bool eg_silent = envelopeGenerate1<CYCLES>();
788 envelopeTimer2<CYCLES, TEST_MODE>(l.eg_timer_carry);
789 envelopeGenerate2<CYCLES>(patch1, l.use_rm_patches);
790 bool key_on_event = keyOnEvent<CYCLES>();
792 doLFO<CYCLES, TEST_MODE>(l.lfo_am_car);
793 doRhythm<CYCLES, TEST_MODE>();
794 uint32_t phaseMod = getPhaseMod<CYCLES>(patch1.fb_t);
796 constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
797 eg_sl[CYCLES & 1] = patch1.sl[mcsel];
798 auto patch2_am_t = patch1.am_t[mcsel];
800 uint32_t phase_incr = phaseCalcIncrement<CYCLES>(patch1);
801 c_dcm[CYCLES % 3] = patch1.dcm;
803 doRegWrite<CYCLES>();
806 doOperator<CYCLES>(l.out, eg_silent);
808 uint32_t pg_out = getPhase<CYCLES, TEST_MODE>(l.rm_hh_bits);
809 op_phase[CYCLES & 1] = narrow_cast<uint16_t>(phaseMod + pg_out);
810 incrementPhase<CYCLES, TEST_MODE>(phase_incr, key_on_event);
812 eg_out[CYCLES & 1] = envelopeOutput<CYCLES, TEST_MODE>(ksltl, patch2_am_t);
817 std::array<float*, 9 + 5> out;
821 if (test_mode_active) [[unlikely]] {
822 repeat(n, [&] { step18<true >(out); });
824 repeat(n, [&] { step18<false>(out); });
826 test_mode_active = testMode;
829template<
bool TEST_MODE>
830NEVER_INLINE void YM2413::step18(std::span<float*, 9 + 5> out)
834 step< 0, TEST_MODE>(l);
835 step< 1, TEST_MODE>(l);
836 step< 2, TEST_MODE>(l);
837 step< 3, TEST_MODE>(l);
838 step< 4, TEST_MODE>(l);
839 step< 5, TEST_MODE>(l);
840 step< 6, TEST_MODE>(l);
841 step< 7, TEST_MODE>(l);
842 step< 8, TEST_MODE>(l);
843 step< 9, TEST_MODE>(l);
844 step<10, TEST_MODE>(l);
845 step<11, TEST_MODE>(l);
846 step<12, TEST_MODE>(l);
847 step<13, TEST_MODE>(l);
848 step<14, TEST_MODE>(l);
849 step<15, TEST_MODE>(l);
850 step<16, TEST_MODE>(l);
851 step<17, TEST_MODE>(l);
853 allowed_offset = std::max<int>(0, allowed_offset - 18);
867 if (speedUpHack) [[unlikely]] {
868 while (cycle_offset < allowed_offset) [[unlikely]] {
870 std::array<float*, 9 + 5> dummy = {
871 &d, &d, &d, &d, &d, &d, &d, &d, &d,
874 step18<false>(dummy);
879 allowed_offset = ((port ? 84 : 12) / 4) + cycle_offset;
882 writes[cycle_offset] = {port, value};
883 if (port && (write_address == 0xf)) {
884 test_mode_active =
true;
899 doModeWrite(reg, value);
901 if (uint8_t ch = reg & 0xf; ch < 9) {
902 doRegWrite(reg & 0xf0, ch, value);
909 return regs[reg & 63];
914 return 1.0f / 256.0f;
919 speedUpHack = speed > 1.0;