openMSX
YM2413NukeYKT.cc
Go to the documentation of this file.
1 /*
2 * Original copyright:
3 * -------------------------------------------------------------------
4 * Copyright (C) 2019 Nuke.YKT
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 *
17 * Yamaha YM2413 emulator
18 * Thanks:
19 * siliconpr0n.org(digshadow, John McMaster):
20 * VRC VII decap and die shot.
21 *
22 * version: 0.9
23 * -------------------------------------------------------------------
24 *
25 * See YM2413NukeYKT.hh for more info.
26 */
27 
28 #include "YM2413NukeYKT.hh"
29 #include "serialize.hh"
30 #include "cstd.hh"
31 #include "likely.hh"
32 #include "Math.hh"
33 #include "one_of.hh"
34 #include "unreachable.hh"
35 #include <algorithm>
36 #include <cstring>
37 
38 namespace openmsx {
39 namespace YM2413NukeYKT {
40 
41 enum RmNum : uint8_t {
42  rm_num_bd0 = 0, // cycles == 11
43  rm_num_hh = 1, // 12
44  rm_num_tom = 2, // 13
45  rm_num_bd1 = 3, // 14
46  rm_num_sd = 4, // 15
47  rm_num_tc = 5, // 16
48 };
49 constexpr bool is_rm_cycle(int cycle)
50 {
51  return (11 <= cycle) && (cycle <= 16);
52 }
53 constexpr RmNum rm_for_cycle(int cycle)
54 {
55  return RmNum(cycle - 11);
56 }
57 
58 struct Rom {
59  uint16_t logsin[256];
60  uint16_t exp[256];
61 };
62 constexpr Rom makeRomTables()
63 {
64  Rom t = {};
65  for (int i = 0; i < 256; ++i) {
66  t.logsin[i] = cstd::round(-cstd::log2<8, 3>(cstd::sin<2>((double(i) + 0.5) * M_PI / 256.0 / 2.0)) * 256.0);
67  t.exp[i] = cstd::round((cstd::exp2<6>(double(255 - i) / 256.0)) * 1024.0);
68  }
69  return t;
70 }
71 constexpr Rom rom = makeRomTables();
72 
73 
74 constexpr YM2413::Patch YM2413::m_patches[15] = {
75  {0x1e, 2, 7, {0, 0}, {1, 1}, {1, 1}, {1, 0}, {0x1, 0x1}, {0, 0}, {0xd, 0x7}, {0x0, 0x8}, {0x0, 0x1}, {0x0, 0x7}},
76  {0x1a, 1, 5, {0, 0}, {0, 1}, {0, 0}, {1, 0}, {0x3, 0x1}, {0, 0}, {0xd, 0xf}, {0x8, 0x7}, {0x2, 0x1}, {0x3, 0x3}},
77  {0x19, 0, 0, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0x3, 0x1}, {2, 0}, {0xf, 0xc}, {0x2, 0x4}, {0x1, 0x2}, {0x1, 0x3}},
78  {0x0e, 0, 7, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0x1, 0x1}, {0, 0}, {0xa, 0x6}, {0x8, 0x4}, {0x7, 0x2}, {0x0, 0x7}},
79  {0x1e, 0, 6, {0, 0}, {0, 0}, {1, 1}, {1, 0}, {0x2, 0x1}, {0, 0}, {0xe, 0x7}, {0x0, 0x6}, {0x0, 0x2}, {0x0, 0x8}},
80  {0x16, 0, 5, {0, 0}, {0, 0}, {1, 1}, {1, 0}, {0x1, 0x2}, {0, 0}, {0xe, 0x7}, {0x0, 0x1}, {0x0, 0x1}, {0x0, 0x8}},
81  {0x1d, 0, 7, {0, 0}, {0, 1}, {1, 1}, {0, 0}, {0x1, 0x1}, {0, 0}, {0x8, 0x8}, {0x2, 0x1}, {0x1, 0x0}, {0x0, 0x7}},
82  {0x2d, 2, 4, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0x3, 0x1}, {0, 0}, {0xa, 0x7}, {0x2, 0x2}, {0x0, 0x0}, {0x0, 0x7}},
83  {0x1b, 0, 6, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0x1, 0x1}, {0, 0}, {0x6, 0x6}, {0x4, 0x5}, {0x1, 0x1}, {0x0, 0x7}},
84  {0x0b, 3, 0, {0, 0}, {1, 1}, {0, 1}, {0, 0}, {0x1, 0x1}, {0, 0}, {0x8, 0xf}, {0x5, 0x7}, {0x7, 0x0}, {0x1, 0x7}},
85  {0x03, 2, 1, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0x3, 0x1}, {2, 0}, {0xf, 0xe}, {0xa, 0x4}, {0x1, 0x0}, {0x0, 0x4}},
86  {0x24, 0, 7, {0, 1}, {0, 1}, {0, 0}, {1, 0}, {0x7, 0x1}, {0, 0}, {0xf, 0xf}, {0x8, 0x8}, {0x2, 0x1}, {0x2, 0x2}},
87  {0x0c, 0, 5, {0, 0}, {1, 1}, {1, 0}, {0, 1}, {0x1, 0x0}, {0, 0}, {0xc, 0xf}, {0x2, 0x5}, {0x2, 0x4}, {0x0, 0x2}},
88  {0x15, 0, 3, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x1, 0x1}, {1, 0}, {0xc, 0x9}, {0x9, 0x5}, {0x0, 0x0}, {0x3, 0x2}},
89  {0x09, 0, 3, {0, 0}, {1, 1}, {1, 0}, {0, 0}, {0x1, 0x1}, {2, 0}, {0xf, 0xe}, {0x1, 0x4}, {0x4, 0x1}, {0x0, 0x3}}
90 };
91 
92 constexpr YM2413::Patch YM2413::r_patches[6] = {
93  {0x18, 1, 7, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x1, 0x0}, {0, 0}, {0xd, 0x0}, {0xf, 0x0}, {0x6, 0x0}, {0xa, 0x0}},
94  {0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x1, 0x0}, {0, 0}, {0xc, 0x0}, {0x8, 0x0}, {0xa, 0x0}, {0x7, 0x0}},
95  {0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x5, 0x0}, {0, 0}, {0xf, 0x0}, {0x8, 0x0}, {0x5, 0x0}, {0x9, 0x0}},
96  {0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x0, 0x1}, {0, 0}, {0x0, 0xf}, {0x0, 0x8}, {0x0, 0x6}, {0x0, 0xd}},
97  {0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x0, 0x1}, {0, 0}, {0x0, 0xd}, {0x0, 0x8}, {0x0, 0x4}, {0x0, 0x8}},
98  {0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x0, 0x1}, {0, 0}, {0x0, 0xa}, {0x0, 0xa}, {0x0, 0x5}, {0x0, 0x5}}
99 };
100 
101 static constexpr uint8_t CH_OFFSET[18] = {
102  1, 2, 0, 1, 2, 3, 4, 5, 3, 4, 5, 6, 7, 8, 6, 7, 8, 0
103 };
104 
105 static constexpr int8_t VIB_TAB[8] = {0, 1, 2, 1, 0, -1, -2, -1};
106 
107 // Define the tables
108 // constexpr uint8_t attack[14][4][64] = { ... };
109 // constexpr uint8_t releaseIndex[14][4][4] = { ... };
110 // constexpr uint8_t releaseData[64][64] = { ... };
111 // Theoretically these could all be initialized via some constepr functions.
112 // The calculation isn't difficult, but it's a bit long. 'clang' can handle it,
113 // but 'gcc' cannot. So instead, for now, we pre-calculate these tables and
114 // #include them. See 'generateNukeYktTables.cpp' for the generator code.
115 #include "YM2413NukeYktTables.ii"
116 
117 
119 {
120  // copy ROM patches to array (for faster lookup)
121  for (int i = 0; i < 15; ++i) {
122  patches[i + 1] = m_patches[i];
123  }
124  reset();
125 }
126 
128 {
129  for (auto& w : writes) w.port = uint8_t(-1);
130  write_fm_cycle = uint8_t(-1);
131  write_data = fm_data = write_address = 0;
132  fast_fm_rewrite = test_mode_active = false;
133 
134  eg_counter_state = 3;
135  eg_timer = eg_timer_shift = eg_timer_shift_lock = eg_timer_lock = 0;
136  attackPtr = attack[eg_timer_shift_lock][eg_timer_lock];
137  auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
138  releasePtr = releaseData[idx];
139  for (int i = 0; i < 18; i++) {
140  eg_state[i] = EgState::release;
141  eg_level[i] = 0x7f;
142  eg_dokon[i] = false;
143  }
144  eg_rate[0] = eg_rate[1] = 0;
145  eg_sl[0] = eg_sl[1] = eg_out[0] = eg_out[1] = 0;
146  eg_timer_shift_stop = false;
147  eg_kon[0] = eg_kon[1] = eg_off[0] = eg_off[1] = false;
148 
149  for (int i = 0; i < 18; ++i) {
150  pg_phase[i] = 0;
151  }
152 
153  for (int i = 0; i < 9; ++i) {
154  op_fb1[i] = op_fb2[i] = 0;
155  }
156  op_mod = 0;
157  op_phase[0] = op_phase[1] = 0;
158 
159  lfo_counter = lfo_vib_counter = lfo_am_out = lfo_am_counter = 0;
160  lfo_vib = VIB_TAB[lfo_vib_counter];
161  lfo_am_step = lfo_am_dir = false;
162 
163  for (int i = 0; i < 9; ++i) {
164  fnum[i] = block[i] = vol8[i] = inst[i] = 0;
165  p_inst[i] = &patches[inst[i]];
166  sk_on[i] = 0;
167  changeFnumBlock(i);
168  }
169  rhythm = testmode = 0;
170  patches[0] = Patch(); // reset user patch, leave ROM patches alone
171  c_dcm[0] = c_dcm[1] = c_dcm[2] = 0;
172 
173  rm_noise = 1; // any value except 0 (1 keeps the output the same as the original code)
174  rm_tc_bits = 0;
175 
176  delay6 = delay7 = delay10 = delay11 = delay12 = 0;
177 
178  for (int i = 0; i < 64; ++i) {
179  regs[i] = 0;
180  }
181  latch = 0;
182 }
183 
184 template<uint32_t CYCLES> ALWAYS_INLINE const YM2413::Patch& YM2413::preparePatch1(bool use_rm_patches) const
185 {
186  return (is_rm_cycle(CYCLES) && use_rm_patches)
187  ? r_patches[rm_for_cycle(CYCLES)]
188  : *p_inst[CH_OFFSET[CYCLES]];
189 }
190 
191 template<uint32_t CYCLES> ALWAYS_INLINE uint32_t YM2413::envelopeKSLTL(const Patch& patch1, bool use_rm_patches) const
192 {
193  constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
194  constexpr uint32_t ch = CH_OFFSET[CYCLES];
195 
196  auto ksl = uint32_t(p_ksl[ch]) >> patch1.ksl_t[mcsel];
197  auto tl2 = [&]() -> uint32_t {
198  if ((rm_for_cycle(CYCLES) == one_of(rm_num_hh, rm_num_tom)) && use_rm_patches) {
199  return inst[ch] << (2 + 1);
200  } else if (mcsel == 1) {
201  return vol8[ch];
202  } else {
203  return patch1.tl2;
204  }
205  }();
206  return ksl + tl2;
207 }
208 
209 template<uint32_t CYCLES> ALWAYS_INLINE void YM2413::envelopeTimer1()
210 {
211  if (CYCLES == 0) {
212  eg_counter_state = (eg_counter_state + 1) & 3;
213  auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
214  releasePtr = releaseData[idx];
215  }
216 }
217 
218 template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE void YM2413::envelopeTimer2(bool& eg_timer_carry)
219 {
220  if (TEST_MODE) {
221  if (CYCLES == 0 && (eg_counter_state & 1) == 0) {
222  eg_timer_lock = eg_timer & 3;
223  eg_timer_shift_lock = likely(eg_timer_shift <= 13) ? eg_timer_shift : 0;
224  eg_timer_shift = 0;
225 
226  attackPtr = attack[eg_timer_shift_lock][eg_timer_lock];
227  auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
228  releasePtr = releaseData[idx];
229  }
230  { // EG timer
231  bool timer_inc = (eg_counter_state != 3) ? 0
232  : (CYCLES == 0) ? true
233  : eg_timer_carry;
234  auto timer_bit = (eg_timer & 1) + timer_inc;
235  eg_timer_carry = timer_bit & 2;
236  eg_timer = ((timer_bit & 1) << 17) | (eg_timer >> 1);
237  if (testmode & 8) {
238  const auto& write = writes[CYCLES];
239  auto data = (write.port != uint8_t(-1)) ? write.value : write_data;
240  eg_timer &= 0x2ffff;
241  eg_timer |= (data << (16 - 2)) & 0x10000;
242  }
243  }
244  if (CYCLES == 0) {
245  eg_timer_shift_stop = false;
246  } else if (!eg_timer_shift_stop && ((eg_timer >> 16) & 1)) {
247  eg_timer_shift = CYCLES;
248  eg_timer_shift_stop = true;
249  }
250  } else {
251  if (CYCLES == 0) {
252  if ((eg_counter_state & 1) == 0) {
253  eg_timer_lock = eg_timer & 3;
254  eg_timer_shift_lock = (eg_timer_shift > 13) ? 0 : eg_timer_shift;
255 
256  attackPtr = attack[eg_timer_shift_lock][eg_timer_lock];
257  auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
258  releasePtr = releaseData[idx];
259  }
260  if (eg_counter_state == 3) {
261  eg_timer = (eg_timer + 1) & 0x3ffff;
262  eg_timer_shift = Math::findFirstSet(eg_timer);
263  }
264  }
265  }
266 }
267 
268 template<uint32_t CYCLES> ALWAYS_INLINE bool YM2413::envelopeGenerate1()
269 {
270  int32_t level = eg_level[(CYCLES + 16) % 18];
271  bool prev2_eg_off = eg_off[(CYCLES + 16) & 1];
272  bool prev2_eg_kon = eg_kon[(CYCLES + 16) & 1];
273  bool prev2_eg_dokon = eg_dokon[(CYCLES + 16) % 18];
274 
275  auto state = eg_state[(CYCLES + 16) % 18];
276  if (unlikely(prev2_eg_dokon)) {
277  eg_state[(CYCLES + 16) % 18] = EgState::attack;
278  } else if (!prev2_eg_kon) {
279  eg_state[(CYCLES + 16) % 18] = EgState::release;
280  } else if (unlikely((state == EgState::attack) && (level == 0))) {
281  eg_state[(CYCLES + 16) % 18] = EgState::decay;
282  } else if (unlikely((state == EgState::decay) && ((level >> 3) == eg_sl[CYCLES & 1]))) {
283  eg_state[(CYCLES + 16) % 18] = EgState::sustain;
284  }
285 
286  auto prev2_rate = eg_rate[(CYCLES + 16) & 1];
287  int32_t next_level
288  = (state != EgState::attack && prev2_eg_off && !prev2_eg_dokon) ? 0x7f
289  : ((prev2_rate >= 60) && prev2_eg_dokon) ? 0x00
290  : level;
291  auto step = [&]() -> int {
292  switch (state) {
293  case EgState::attack:
294  if (likely(prev2_eg_kon && (level != 0))) {
295  return (level ^ 0xfff) >> attackPtr[prev2_rate];
296  }
297  break;
298  case EgState::decay:
299  if ((level >> 3) == eg_sl[CYCLES & 1]) return 0;
300  [[fallthrough]];
301  case EgState::sustain:
302  case EgState::release:
303  if (!prev2_eg_off && !prev2_eg_dokon) {
304  return releasePtr[prev2_rate];
305  }
306  break;
307  default:
308  UNREACHABLE;
309  }
310  return 0;
311  }();
312  eg_level[(CYCLES + 16) % 18] = next_level + step;
313 
314  return level == 0x7f; // eg_silent
315 }
316 
317 template<uint32_t CYCLES> ALWAYS_INLINE void YM2413::envelopeGenerate2(const Patch& patch1, bool use_rm_patches)
318 {
319  constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
320  constexpr uint32_t ch = CH_OFFSET[CYCLES];
321 
322  bool new_eg_off = eg_level[CYCLES] >= 124; // (eg_level[CYCLES] >> 2) == 0x1f;
323  eg_off[CYCLES & 1] = new_eg_off;
324 
325  auto sk = sk_on[CH_OFFSET[CYCLES]];
326  bool new_eg_kon = [&]() {
327  bool result = sk & 1;
328  if (is_rm_cycle(CYCLES) && use_rm_patches) {
329  switch (rm_for_cycle(CYCLES)) {
330  case rm_num_bd0:
331  case rm_num_bd1:
332  result |= bool(rhythm & 0x10);
333  break;
334  case rm_num_sd:
335  result |= bool(rhythm & 0x08);
336  break;
337  case rm_num_tom:
338  result |= bool(rhythm & 0x04);
339  break;
340  case rm_num_tc:
341  result |= bool(rhythm & 0x02);
342  break;
343  case rm_num_hh:
344  result |= bool(rhythm & 0x01);
345  break;
346  default:
347  break; // suppress warning
348  }
349  }
350  return result;
351  }();
352  eg_kon[CYCLES & 1] = new_eg_kon;
353 
354  // Calculate rate
355  auto state_rate = eg_state[CYCLES];
356  if (unlikely(state_rate == EgState::release && new_eg_kon && new_eg_off)) {
357  state_rate = EgState::attack;
358  eg_dokon[CYCLES] = true;
359  } else {
360  eg_dokon[CYCLES] = false;
361  }
362 
363  auto rate4 = [&]() {
364  if (!new_eg_kon && !(sk & 2) && mcsel == 1 && !patch1.et[mcsel]) {
365  return 7 * 4;
366  }
367  if (new_eg_kon && eg_state[CYCLES] == EgState::release && !new_eg_off) {
368  return 12 * 4;
369  }
370  bool tom_or_hh = (rm_for_cycle(CYCLES) == one_of(rm_num_tom, rm_num_hh)) && use_rm_patches;
371  if (!new_eg_kon && !mcsel && !tom_or_hh) {
372  return 0 * 4;
373  }
374  return (state_rate == EgState::attack ) ? patch1.ar4[mcsel]
375  : (state_rate == EgState::decay ) ? patch1.dr4[mcsel]
376  : (state_rate == EgState::sustain) ? (patch1.et[mcsel] ? (0 * 4) : patch1.rr4[mcsel])
377  : /*(state_rate == EgState::release) ?*/ ((sk & 2) ? (5 * 4) : patch1.rr4[mcsel]);
378  }();
379 
380  eg_rate[CYCLES & 1] = [&]() {
381  if (rate4 == 0) return 0;
382  auto tmp = rate4 + (p_ksr_freq[ch] >> patch1.ksr_t[mcsel]);
383  return (tmp < 0x40) ? tmp
384  : (0x3c | (tmp & 3));
385  }();
386 }
387 
388 template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE void YM2413::doLFO(bool& lfo_am_car)
389 {
390  if (TEST_MODE) {
391  // Update counter
392  if (CYCLES == 17) {
393  lfo_counter++;
394  if (((lfo_counter & 0x3ff) == 0) || (testmode & 8)) {
395  lfo_vib_counter = (lfo_vib_counter + 1) & 7;
396  lfo_vib = VIB_TAB[lfo_vib_counter];
397  }
398  lfo_am_step = (lfo_counter & 0x3f) == 0;
399  }
400 
401  // LFO AM
402  auto am_inc = ((lfo_am_step || (testmode & 8)) && CYCLES < 9)
403  ? (lfo_am_dir | (CYCLES == 0))
404  : 0;
405 
406  if (CYCLES == 0) {
407  if (lfo_am_dir && (lfo_am_counter & 0x7f) == 0) {
408  lfo_am_dir = false;
409  } else if (!lfo_am_dir && (lfo_am_counter & 0x69) == 0x69) {
410  lfo_am_dir = true;
411  }
412  }
413 
414  auto am_bit = (lfo_am_counter & 1) + am_inc + ((CYCLES < 9) ? lfo_am_car : false);
415  if (CYCLES < 8) {
416  lfo_am_car = am_bit & 2;
417  }
418  lfo_am_counter = ((am_bit & 1) << 8) | (lfo_am_counter >> 1);
419 
420  // Reset LFO
421  if (testmode & 2) {
422  lfo_vib_counter = 0;
423  lfo_vib = VIB_TAB[lfo_vib_counter];
424  lfo_counter = 0;
425  lfo_am_dir = false;
426  lfo_am_counter &= 0xff;
427  }
428  } else {
429  if (CYCLES == 17) {
430  int delta = lfo_am_dir ? -1 : 1;
431 
432  if (lfo_am_dir && (lfo_am_counter & 0x7f) == 0) {
433  lfo_am_dir = false;
434  } else if (!lfo_am_dir && (lfo_am_counter & 0x69) == 0x69) {
435  lfo_am_dir = true;
436  }
437 
438  if (lfo_am_step) {
439  lfo_am_counter = (lfo_am_counter + delta) & 0x1ff;
440  }
441 
442  lfo_counter++;
443  if (((lfo_counter & 0x3ff) == 0)) {
444  lfo_vib_counter = (lfo_vib_counter + 1) & 7;
445  lfo_vib = VIB_TAB[lfo_vib_counter];
446  }
447  lfo_am_step = (lfo_counter & 0x3f) == 0;
448  }
449  }
450  if (CYCLES == 17) {
451  lfo_am_out = (lfo_am_counter >> 3) & 0x0f;
452  }
453 }
454 
455 template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE void YM2413::doRhythm()
456 {
457  if (TEST_MODE) {
458  bool nbit = (rm_noise ^ (rm_noise >> 14)) & 1;
459  nbit |= bool(testmode & 2);
460  rm_noise = (nbit << 22) | (rm_noise >> 1);
461  } else {
462  // When test-mode does not interfere, the formula for a single step is:
463  // x = ((x & 1) << 22) ^ ((x & 0x4000) << 8) ^ (x >> 1);
464  // From this we can easily derive the value of the noise bit (bit 0)
465  // 13 and 16 steps in the future (see getPhase()). We can also
466  // derive a formula that takes 18 steps at once.
467  if (CYCLES == 17) {
468  rm_noise = ((rm_noise & 0x1ff) << 14)
469  ^ ((rm_noise & 0x3ffff) << 5)
470  ^ (rm_noise & 0x7fc000)
471  ^ ((rm_noise >> 9) & 0x3fe0)
472  ^ (rm_noise >> 18);
473  }
474  }
475 }
476 
477 template<uint32_t CYCLES> ALWAYS_INLINE uint32_t YM2413::getPhaseMod(uint8_t fb_t)
478 {
479  bool ismod2 = ((rhythm & 0x20) && (CYCLES == one_of(12u, 13u)))
480  ? false
481  : (((CYCLES + 4) / 3) & 1);
482  bool ismod3 = ((rhythm & 0x20) && (CYCLES == one_of(15u, 16u)))
483  ? false
484  : (((CYCLES + 1) / 3) & 1);
485 
486  if (ismod3) return op_mod << 1;
487  if (ismod2) {
488  constexpr uint32_t cycles9 = (CYCLES + 3) % 9;
489  uint32_t op_fbsum = (op_fb1[cycles9] + op_fb2[cycles9]) & 0x7fffffff;
490  return op_fbsum >> fb_t;
491  }
492  return 0;
493 }
494 
495 template<uint32_t CYCLES> ALWAYS_INLINE void YM2413::doRegWrite()
496 {
497  if (unlikely(write_fm_cycle == CYCLES)) {
498  doRegWrite(CYCLES % 9);
499  }
500 }
501 
502 void YM2413::changeFnumBlock(uint32_t ch)
503 {
504  static constexpr uint8_t KSL_TABLE[16] = {
505  0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64
506  };
507  p_ksl[ch] = std::max(0, KSL_TABLE[fnum[ch] >> 5] - ((8 - block[ch]) << 3)) << 1;
508  p_incr[ch] = fnum[ch] << block[ch];
509  p_ksr_freq[ch] = (block[ch] << 1) | (fnum[ch] >> 8);
510 }
511 
512 NEVER_INLINE void YM2413::doRegWrite(uint32_t channel)
513 {
514  if (write_address < 0x40) {
515  write_fm_cycle = uint8_t(-1);
516  doRegWrite(write_address & 0xf0, channel, fm_data);
517  } else {
518  write_address -= 0x40; // try again in 18 steps
519  }
520 }
521 
522 void YM2413::doRegWrite(uint8_t regBlock, uint8_t channel, uint8_t data)
523 {
524  switch (regBlock) {
525  case 0x10:
526  fnum[channel] = (fnum[channel] & 0x100) | data;
527  changeFnumBlock(channel);
528  break;
529  case 0x20:
530  fnum[channel] = (fnum[channel] & 0xff) | ((data & 1) << 8);
531  block[channel] = (data >> 1) & 7;
532  changeFnumBlock(channel);
533  sk_on[channel] = (data >> 4) & 3;
534  break;
535  case 0x30:
536  vol8[channel] = (data & 0x0f) << (2 + 1); // pre-multiply by 8
537  inst[channel] = (data >> 4) & 0x0f;
538  p_inst[channel] = &patches[inst[channel]];
539  break;
540  }
541 }
542 
543 template<uint32_t CYCLES> ALWAYS_INLINE void YM2413::doIO()
544 {
545  if (unlikely(writes[CYCLES].port != uint8_t(-1))) {
546  doIO((CYCLES + 1) % 18, writes[CYCLES]);
547  }
548 }
549 
550 NEVER_INLINE void YM2413::doIO(uint32_t cycles_plus_1, Write& write)
551 {
552  write_data = write.value;
553  if (write.port) {
554  // data
555  if (write_address < 0x10) {
556  doModeWrite(write_address, write.value);
557  } else if (write_address < 0x40) {
558  write_fm_cycle = write_address & 0xf;
559  fm_data = write.value;
560  if (!fast_fm_rewrite && (write_fm_cycle == cycles_plus_1)) {
561  write_address += 0x40; // postpone for 18 steps
562  }
563  // First fm-register write takes one cycle longer than
564  // subsequent writes to the same register. When the address
565  // is changed (even if to the same value) then there's again
566  // one cycle penalty.
567  fast_fm_rewrite = true;
568  }
569  } else {
570  // address
571  write_address = write.value;
572  write_fm_cycle = uint8_t(-1); // cancel pending fm write
573  fast_fm_rewrite = false;
574  }
575 
576  write.port = uint8_t(-1);
577 }
578 
579 void YM2413::doModeWrite(uint8_t address, uint8_t value)
580 {
581  auto slot = address & 1;
582  switch (address) {
583  case 0x00:
584  case 0x01:
585  patches[0].setMulti(slot, value & 0x0f);
586  patches[0].setKSR(slot, (value >> 4) & 1);
587  patches[0].et[slot] = (value >> 5) & 1;
588  patches[0].vib[slot] = (value >> 6) & 1;
589  patches[0].setAM(slot, (value >> 7) & 1);
590  break;
591 
592  case 0x02:
593  patches[0].setKSL(0, (value >> 6) & 3);
594  patches[0].setTL(value & 0x3f);
595  break;
596 
597  case 0x03:
598  patches[0].setKSL(1, (value >> 6) & 3);
599  patches[0].dcm = (value >> 3) & 3;
600  patches[0].setFB(value & 7);
601  break;
602 
603  case 0x04:
604  case 0x05:
605  patches[0].setDR(slot, value & 0x0f);
606  patches[0].setAR(slot, (value >> 4) & 0x0f);
607  break;
608 
609  case 0x06:
610  case 0x07:
611  patches[0].setRR(slot, value & 0x0f);
612  patches[0].sl[slot] = (value >> 4) & 0x0f;
613  break;
614 
615  case 0x0e:
616  rhythm = value & 0x3f;
617  break;
618 
619  case 0x0f:
620  testmode = value & 0x0f;
621  break;
622  }
623 }
624 
625 template<uint32_t CYCLES> ALWAYS_INLINE void YM2413::doOperator(float* out[9 + 5], bool eg_silent)
626 {
627  bool ismod1 = ((rhythm & 0x20) && (CYCLES == one_of(14u, 15u)))
628  ? false
629  : (((CYCLES + 2) / 3) & 1);
630  constexpr bool is_next_mod3 = ((CYCLES + 2) / 3) & 1; // approximate: will 'ismod3' possibly be true next step
631 
632  auto output = [&]() -> int32_t {
633  if (eg_silent) return 0;
634  auto prev2_phase = op_phase[(CYCLES - 2) & 1];
635  uint8_t quarter = (prev2_phase & 0x100) ? ~prev2_phase : prev2_phase;
636  auto logsin = rom.logsin[quarter];
637  auto op_level = std::min(4095, logsin + (eg_out[(CYCLES - 2) & 1] << 4));
638  uint32_t op_exp_m = rom.exp[op_level & 0xff];
639  auto op_exp_s = op_level >> 8;
640  if (prev2_phase & 0x200) {
641  return unlikely(c_dcm[(CYCLES + 16) % 3] & (ismod1 ? 1 : 2))
642  ? ~0
643  : ~(op_exp_m >> op_exp_s);
644  } else {
645  return op_exp_m >> op_exp_s;
646  }
647  }();
648 
649  if (ismod1) {
650  constexpr uint32_t cycles9 = (CYCLES + 1) % 9;
651  op_fb2[cycles9] = op_fb1[cycles9];
652  op_fb1[cycles9] = output;
653  }
654  channelOutput<CYCLES>(out, output >> 3);
655 
656  if (is_next_mod3) {
657  op_mod = output & 0x1ff;
658  }
659 }
660 
661 template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE uint32_t YM2413::getPhase(uint8_t& rm_hh_bits)
662 {
663  uint32_t phase = pg_phase[CYCLES];
664 
665  // Rhythm mode
666  if (CYCLES == 12) {
667  rm_hh_bits = phase >> (2 + 9);
668  } else if (CYCLES == 16 && (rhythm & 0x20)) {
669  rm_tc_bits = phase >> 8;
670  }
671 
672  if (rhythm & 0x20) {
673  auto rm_bit = [&]() {
674  bool rm_hh_bit2 = (rm_hh_bits >> (2 - 2)) & 1;
675  bool rm_hh_bit3 = (rm_hh_bits >> (3 - 2)) & 1;
676  bool rm_hh_bit7 = (rm_hh_bits >> (7 - 2)) & 1;
677  bool rm_tc_bit3 = (rm_tc_bits >> (3 + 9 - 8)) & 1;
678  bool rm_tc_bit5 = (rm_tc_bits >> (5 + 9 - 8)) & 1;
679  return (rm_hh_bit2 ^ rm_hh_bit7)
680  | (rm_hh_bit3 ^ rm_tc_bit5)
681  | (rm_tc_bit3 ^ rm_tc_bit5);
682  };
683  auto noise_bit = [&]() {
684  // see comments in doRhythm()
685  return (rm_noise >> (TEST_MODE ? 0 : (CYCLES + 1))) & 1;
686  };
687  switch (CYCLES) {
688  case 12: { // HH
689  auto b = rm_bit();
690  return (b << 9) | ((b ^ noise_bit()) ? 0xd0 : 0x34);
691  }
692  case 15: { // SD
693  auto rm_hh_bit8 = (rm_hh_bits >> (8 - 2)) & 1;
694  return (rm_hh_bit8 << 9) | ((rm_hh_bit8 ^ noise_bit()) << 8);
695  }
696  case 16: // TC
697  return (rm_bit() << 9) | 0x100;
698  default:
699  break; // suppress warning
700  }
701  }
702  return phase >> 9;
703 }
704 
705 template<uint32_t CYCLES> ALWAYS_INLINE uint32_t YM2413::phaseCalcIncrement(const Patch& patch1) const
706 {
707  constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
708  constexpr uint32_t ch = CH_OFFSET[CYCLES];
709 
710  uint32_t incr = [&]() {
711  // Apply vibrato?
712  if (patch1.vib[mcsel]) {
713  // note: _must_ be '/ 256' rather than '>> 8' because of
714  // round-to-zero for negative values.
715  uint32_t freq = fnum[ch] << 1;
716  freq += (int(freq) * lfo_vib) / 256;
717  return (freq << block[ch]) >> 1;
718  } else {
719  return uint32_t(p_incr[ch]);
720  }
721  }();
722  return (incr * patch1.multi_t[mcsel]) >> 1;
723 }
724 
725 template<uint32_t CYCLES> ALWAYS_INLINE bool YM2413::keyOnEvent() const
726 {
727  bool ismod = ((rhythm & 0x20) && (CYCLES == one_of(12u, 13u)))
728  ? false
729  : (((CYCLES + 4) / 3) & 1);
730  return ismod ? eg_dokon[(CYCLES + 3) % 18]
731  : eg_dokon[CYCLES];
732 }
733 
734 template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE void YM2413::incrementPhase(uint32_t phase_incr, bool key_on_event)
735 {
736  uint32_t pg_phase_next = ((TEST_MODE && (testmode & 4)) || key_on_event)
737  ? 0
738  : pg_phase[CYCLES];
739  pg_phase[CYCLES] = pg_phase_next + phase_incr;
740 }
741 
742 template<uint32_t CYCLES> ALWAYS_INLINE void YM2413::channelOutput(float* out[9 + 5], int32_t ch_out)
743 {
744  switch (CYCLES) {
745  case 4: *out[ 0]++ += ch_out; break;
746  case 5: *out[ 1]++ += ch_out; break;
747  case 6: *out[ 2]++ += ch_out; break;
748  case 10: *out[ 3]++ += ch_out; break;
749  case 11: *out[ 4]++ += ch_out; break;
750  case 12: *out[ 5]++ += ch_out; break;
751  case 14: *out[ 9]++ += (rhythm & 0x20) ? 2 * ch_out : 0; break;
752  case 15: *out[10]++ += delay10;
753  delay10 = (rhythm & 0x20) ? 2 * ch_out : 0; break;
754  case 16: *out[ 6]++ += delay6;
755  *out[11]++ += delay11;
756  delay6 = (rhythm & 0x20) ? 0 : ch_out;
757  delay11 = (rhythm & 0x20) ? 2 * ch_out : 0; break;
758  case 17: *out[ 7]++ += delay7;
759  *out[12]++ += delay12;
760  delay7 = (rhythm & 0x20) ? 0 : ch_out;
761  delay12 = (rhythm & 0x20) ? 2 * ch_out : 0; break;
762  case 0: *out[ 8]++ += (rhythm & 0x20) ? 0 : ch_out;
763  *out[13]++ += (rhythm & 0x20) ? 2 * ch_out : 0; break;
764  default:
765  break; // suppress warning
766  }
767 }
768 
769 template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE uint8_t YM2413::envelopeOutput(uint32_t ksltl, int8_t am_t) const
770 {
771  if (TEST_MODE && (testmode & 1)) {
772  return 0;
773  }
774  int32_t level = eg_level[CYCLES] + ksltl + (am_t & lfo_am_out);
775  return std::min(127, level);
776 }
777 
778 template<uint32_t CYCLES, bool TEST_MODE>
779 ALWAYS_INLINE void YM2413::step(Locals& l)
780 {
781  if (CYCLES == 11) {
782  // the value for 'use_rm_patches' is only meaningful in cycles 11..16
783  // and it remains constant during that time.
784  l.use_rm_patches = rhythm & 0x20;
785  }
786  const Patch& patch1 = preparePatch1<CYCLES>(l.use_rm_patches);
787  uint32_t ksltl = envelopeKSLTL<CYCLES>(patch1, l.use_rm_patches);
788  envelopeTimer1<CYCLES>();
789  bool eg_silent = envelopeGenerate1<CYCLES>();
790  envelopeTimer2<CYCLES, TEST_MODE>(l.eg_timer_carry);
791  envelopeGenerate2<CYCLES>(patch1, l.use_rm_patches);
792  bool key_on_event = keyOnEvent<CYCLES>();
793 
794  doLFO<CYCLES, TEST_MODE>(l.lfo_am_car);
795  doRhythm<CYCLES, TEST_MODE>();
796  uint32_t phaseMod = getPhaseMod<CYCLES>(patch1.fb_t);
797 
798  constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
799  eg_sl[CYCLES & 1] = patch1.sl[mcsel];
800  auto patch2_am_t = patch1.am_t[mcsel];
801 
802  uint32_t phase_incr = phaseCalcIncrement<CYCLES>(patch1);
803  c_dcm[CYCLES % 3] = patch1.dcm;
804 
805  doRegWrite<CYCLES>();
806  doIO<CYCLES>();
807 
808  doOperator<CYCLES>(l.out, eg_silent);
809 
810  uint32_t pg_out = getPhase<CYCLES, TEST_MODE>(l.rm_hh_bits);
811  op_phase[CYCLES & 1] = phaseMod + pg_out;
812  incrementPhase<CYCLES, TEST_MODE>(phase_incr, key_on_event);
813 
814  eg_out[CYCLES & 1] = envelopeOutput<CYCLES, TEST_MODE>(ksltl, patch2_am_t);
815 }
816 
817 void YM2413::generateChannels(float* out_[9 + 5], uint32_t n)
818 {
819  float* out[9 + 5];
820  for (int i = 0; i < 9 + 5; ++i) out[i] = out_[i];
821 
822  // Loop here (instead of in step18) seems faster. (why?)
823  if (unlikely(test_mode_active)) {
824  for (uint32_t i = 0; i < n; ++i) {
825  step18<true>(out);
826  }
827  } else {
828  for (uint32_t i = 0; i < n; ++i) {
829  step18<false>(out);
830  }
831  }
832  test_mode_active = testmode;
833 }
834 
835 template<bool TEST_MODE>
836 NEVER_INLINE void YM2413::step18(float* out[9 + 5])
837 {
838  Locals l;
839  l.out = out;
840  l.use_rm_patches = false; // avoid warning
841  l.lfo_am_car = false; // between cycle 17 and 0 'lfo_am_car' is always =0
842 
843  step< 0, TEST_MODE>(l);
844  step< 1, TEST_MODE>(l);
845  step< 2, TEST_MODE>(l);
846  step< 3, TEST_MODE>(l);
847  step< 4, TEST_MODE>(l);
848  step< 5, TEST_MODE>(l);
849  step< 6, TEST_MODE>(l);
850  step< 7, TEST_MODE>(l);
851  step< 8, TEST_MODE>(l);
852  step< 9, TEST_MODE>(l);
853  step<10, TEST_MODE>(l);
854  step<11, TEST_MODE>(l);
855  step<12, TEST_MODE>(l);
856  step<13, TEST_MODE>(l);
857  step<14, TEST_MODE>(l);
858  step<15, TEST_MODE>(l);
859  step<16, TEST_MODE>(l);
860  step<17, TEST_MODE>(l);
861 
862  allowed_offset = std::max<int>(0, allowed_offset - 18); // see writePort()
863 }
864 
865 void YM2413::writePort(bool port, uint8_t value, int cycle_offset)
866 {
867  // Hack: detect too-fast access and workaround that.
868  // Ideally we'd just pass this too-fast-access to the NukeYKY code,
869  // because it handles it 'fine' (as in "the same as the real
870  // hardware"). Possibly with a warning.
871  // Though currently in openMSX, when running at 'speed > 100%' we keep
872  // emulate the sound devices at 100% speed, but because CPU runs
873  // faster this can result in artificial too-fast-access. We need to
874  // solve this properly, but for now this hack should suffice.
875 
876  while (unlikely(cycle_offset < allowed_offset)) {
877  float d = 0.0f;
878  float* dummy[9 + 5] = {
879  &d, &d, &d, &d, &d, &d, &d, &d, &d,
880  &d, &d, &d, &d, &d,
881  };
882  step18<false>(dummy); // discard result
883  }
884  // Need 12 cycles (@3.57MHz) wait after address-port access, 84 cycles
885  // after data-port access. Divide by 4 to translate to our 18-step
886  // timescale.
887  allowed_offset = ((port ? 84 : 12) / 4) + cycle_offset;
888 
889  writes[cycle_offset] = {port, value};
890  if (port && (write_address == 0xf)) {
891  test_mode_active = true;
892  }
893 
894  // only needed for peekReg()
895  if (port == 0) {
896  latch = value & 63;
897  } else {
898  regs[latch] = value;
899  }
900 }
901 
902 void YM2413::pokeReg(uint8_t reg, uint8_t value)
903 {
904  regs[reg] = value;
905  if (reg < 0x10) {
906  doModeWrite(reg, value);
907  } else {
908  if (auto ch = reg & 0xf; ch < 9) {
909  doRegWrite(reg & 0xf0, ch, value);
910  }
911  }
912 }
913 
914 uint8_t YM2413::peekReg(uint8_t reg) const
915 {
916  return regs[reg & 63];
917 }
918 
920 {
921  return 1.0f / 256.0f;
922 }
923 
924 } // namespace YM2413NukeYKT
925 
926 
927 static std::initializer_list<enum_string<YM2413NukeYKT::YM2413::EgState>> egStateInfo = {
932 };
934 
935 namespace YM2413NukeYKT {
936 
937 template<typename Archive>
938 void YM2413::Write::serialize(Archive& ar, unsigned /*version*/)
939 {
940  ar.serialize("port", port,
941  "value", value);
942 }
943 
944 template<typename Archive>
945 void YM2413::serialize(Archive& ar, unsigned /*version*/)
946 {
947  ar.serialize("writes", writes,
948  "write_data", write_data,
949  "fm_data", fm_data,
950  "write_address", write_address,
951  "write_fm_cycle", write_fm_cycle,
952  "fast_fm_rewrite", fast_fm_rewrite,
953  "test_mode_active", test_mode_active);
954 
955  ar.serialize("eg_timer", eg_timer,
956  "eg_sl", eg_sl,
957  "eg_out", eg_out,
958  "eg_counter_state", eg_counter_state,
959  "eg_timer_shift", eg_timer_shift,
960  "eg_timer_shift_lock", eg_timer_shift_lock,
961  "eg_timer_lock", eg_timer_lock,
962  "eg_state", eg_state,
963  "eg_level", eg_level,
964  "eg_rate", eg_rate,
965  "eg_dokon", eg_dokon,
966  "eg_kon", eg_kon,
967  "eg_off", eg_off,
968  "eg_timer_shift_stop", eg_timer_shift_stop,
969  "pg_phase", pg_phase);
970 
971  ar.serialize("op_fb1", op_fb1,
972  "op_fb2", op_fb2,
973  "op_mod", op_mod,
974  "op_phase", op_phase,
975  "lfo_counter", lfo_counter,
976  "lfo_am_counter", lfo_am_counter,
977  "lfo_vib_counter", lfo_vib_counter,
978  "lfo_am_out", lfo_am_out,
979  "lfo_am_step", lfo_am_step,
980  "lfo_am_dir", lfo_am_dir);
981 
982  ar.serialize("rm_noise", rm_noise,
983  "rm_tc_bits", rm_tc_bits,
984  "c_dcm", c_dcm,
985  "regs", regs,
986  "latch", latch);
987 
988  if (ar.isLoader()) {
989  // restore redundant state
990  attackPtr = attack[eg_timer_shift_lock][eg_timer_lock];
991  auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
992  releasePtr = releaseData[idx];
993 
994  lfo_vib = VIB_TAB[lfo_vib_counter];
995 
996  delay6 = delay7 = delay10 = delay11 = delay12 = 0;
997 
998  // Restore these from register values:
999  // fnum, block, p_ksl, p_incr, p_ksr_freq, sk_on, vol8,
1000  // inst, p_inst, rhythm, testmode, patches[0]
1001  for (int i = 0; i < 64; ++i) {
1002  pokeReg(i, regs[i]);
1003  }
1004  }
1005 }
1006 
1007 } // namespace YM2413NukeYKT
1008 
1009 using YM2413NukeYKT::YM2413;
1012 
1013 } // namespace openmsx
openmsx::YM2413NukeYKT::rm_num_bd1
@ rm_num_bd1
Definition: YM2413NukeYKT.cc:45
Math::findFirstSet
unsigned findFirstSet(unsigned x)
Find the least significant bit that is set.
Definition: Math.hh:256
one_of.hh
openmsx::YM2413NukeYKT::Rom::exp
uint16_t exp[256]
Definition: YM2413NukeYKT.cc:60
openmsx::YM2413NukeYKT::rm_num_bd0
@ rm_num_bd0
Definition: YM2413NukeYKT.cc:42
ALWAYS_INLINE
#define ALWAYS_INLINE
Definition: inline.hh:16
gl::min
vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:274
unlikely
#define unlikely(x)
Definition: likely.hh:15
cstd::round
constexpr double round(double x)
Definition: cstd.hh:318
serialize.hh
cstd.hh
openmsx::SERIALIZE_ENUM
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
openmsx::YM2413NukeYKT::rom
constexpr Rom rom
Definition: YM2413NukeYKT.cc:71
openmsx::YM2413NukeYKT::RmNum
RmNum
Definition: YM2413NukeYKT.cc:41
t
TclObject t
Definition: TclObject_test.cc:264
NEVER_INLINE
#define NEVER_INLINE
Definition: inline.hh:17
openmsx::YM2413NukeYKT::YM2413::writePort
void writePort(bool port, uint8_t value, int cycle_offset) override
Write to the YM2413 register/data port.
Definition: YM2413NukeYKT.cc:865
openmsx::YM2413NukeYKT::YM2413::getAmplificationFactor
float getAmplificationFactor() const override
Returns normalization factor.
Definition: YM2413NukeYKT.cc:919
likely.hh
M_PI
#define M_PI
Definition: Math.hh:27
openmsx::YM2413NukeYKT::rm_for_cycle
constexpr RmNum rm_for_cycle(int cycle)
Definition: YM2413NukeYKT.cc:53
UNREACHABLE
#define UNREACHABLE
Definition: unreachable.hh:38
openmsx::YM2413NukeYKT::YM2413::EgState::release
@ release
one_of
Definition: one_of.hh:7
openmsx::YM2413NukeYKT::Rom::logsin
uint16_t logsin[256]
Definition: YM2413NukeYKT.cc:59
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
openmsx::YM2413NukeYKT::rm_num_tom
@ rm_num_tom
Definition: YM2413NukeYKT.cc:44
openmsx::YM2413NukeYKT::rm_num_sd
@ rm_num_sd
Definition: YM2413NukeYKT.cc:46
openmsx::YM2413NukeYKT::makeRomTables
constexpr Rom makeRomTables()
Definition: YM2413NukeYKT.cc:62
openmsx::YM2413NukeYKT::is_rm_cycle
constexpr bool is_rm_cycle(int cycle)
Definition: YM2413NukeYKT.cc:49
openmsx::YM2413NukeYKT::YM2413::pokeReg
void pokeReg(uint8_t reg, uint8_t value) override
Write to a YM2413 register (for debug).
Definition: YM2413NukeYKT.cc:902
openmsx::YM2413
Definition: YM2413.hh:16
likely
#define likely(x)
Definition: likely.hh:14
openmsx::YM2413NukeYKT::YM2413::reset
void reset() override
Reset this YM2413 core.
Definition: YM2413NukeYKT.cc:127
openmsx::YM2413NukeYKT::rm_num_tc
@ rm_num_tc
Definition: YM2413NukeYKT.cc:47
openmsx::YM2413NukeYKT::YM2413::peekReg
uint8_t peekReg(uint8_t reg) const override
Read from a YM2413 register (for debug).
Definition: YM2413NukeYKT.cc:914
openmsx::YM2413NukeYKT::rm_num_hh
@ rm_num_hh
Definition: YM2413NukeYKT.cc:43
openmsx::YM2413Core
Abstract interface for the YM2413 core.
Definition: YM2413Core.hh:27
gl::max
vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:292
openmsx::YM2413
YM2413
Definition: YM2413.cc:119
openmsx::YM2413NukeYKT::YM2413::serialize
void serialize(Archive &ar, unsigned version)
Definition: YM2413NukeYKT.cc:945
openmsx::YM2413NukeYKT::YM2413::EgState::decay
@ decay
unreachable.hh
openmsx::YM2413NukeYKT::YM2413::EgState::sustain
@ sustain
openmsx::YM2413NukeYKT::YM2413::generateChannels
void generateChannels(float *out[9+5], uint32_t n) override
Definition: YM2413NukeYKT.cc:817
Math.hh
YM2413NukeYKT.hh
openmsx::serialize
void serialize(Archive &ar, T &t, unsigned version)
Definition: serialize_core.hh:41
openmsx::YM2413NukeYKT::YM2413::YM2413
YM2413()
Definition: YM2413NukeYKT.cc:118
openmsx::YM2413NukeYKT::YM2413::EgState
EgState
Definition: YM2413NukeYKT.hh:82
openmsx::YM2413NukeYKT::YM2413::EgState::attack
@ attack
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
openmsx::YM2413NukeYKT::Rom
Definition: YM2413NukeYKT.cc:58
openmsx::REGISTER_POLYMORPHIC_INITIALIZER
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")