openMSX
Y8950.cc
Go to the documentation of this file.
1 /*
2  * Based on:
3  * emu8950.c -- Y8950 emulator written by Mitsutaka Okazaki 2001
4  * heavily rewritten to fit openMSX structure
5  */
6 
7 #include "Y8950.hh"
8 #include "Y8950Periphery.hh"
9 #include "MSXAudio.hh"
10 #include "DeviceConfig.hh"
11 #include "MSXMotherBoard.hh"
12 #include "Math.hh"
13 #include "cstd.hh"
14 #include "enumerate.hh"
15 #include "outer.hh"
16 #include "ranges.hh"
17 #include "serialize.hh"
18 #include "xrange.hh"
19 #include <algorithm>
20 #include <array>
21 #include <cmath>
22 #include <iostream>
23 
24 namespace openmsx {
25 
26 constexpr unsigned EG_MUTE = 1 << Y8950::EG_BITS;
28 
29 constexpr unsigned MOD = 0;
30 constexpr unsigned CAR = 1;
31 
32 constexpr double EG_STEP = 0.1875; // 3/16
33 constexpr double SL_STEP = 3.0;
34 constexpr double TL_STEP = 0.75; // 12/16
35 constexpr double DB_STEP = 0.1875; // 3/16
36 
37 constexpr unsigned SL_PER_EG = 16; // SL_STEP / EG_STEP
38 constexpr unsigned TL_PER_EG = 4; // TL_STEP / EG_STEP
39 constexpr unsigned EG_PER_DB = 1; // EG_STEP / DB_STEP
40 
41 // PM speed(Hz) and depth(cent)
42 constexpr double PM_SPEED = 6.4;
43 constexpr double PM_DEPTH = 13.75 / 2;
44 constexpr double PM_DEPTH2 = 13.75;
45 
46 // Dynamic range of sustain level
47 constexpr int SL_BITS = 4;
48 constexpr int SL_MUTE = 1 << SL_BITS;
49 // Size of Sintable ( 1 -- 18 can be used, but 7 -- 14 recommended.)
50 constexpr int PG_BITS = 10;
51 constexpr int PG_WIDTH = 1 << PG_BITS;
52 constexpr int PG_MASK = PG_WIDTH - 1;
53 // Phase increment counter
54 constexpr int DP_BITS = 19;
55 constexpr int DP_BASE_BITS = DP_BITS - PG_BITS;
56 
57 // Dynamic range
58 constexpr int DB_BITS = 9;
59 constexpr int DB_MUTE = 1 << DB_BITS;
60 // PM table is calcurated by PM_AMP * exp2(PM_DEPTH * sin(x) / 1200)
61 constexpr int PM_AMP_BITS = 8;
62 constexpr int PM_AMP = 1 << PM_AMP_BITS;
63 
64 // Bits for liner value
65 constexpr int DB2LIN_AMP_BITS = 11;
67 
68 // Bits for Pitch and Amp modulator
69 constexpr int PM_PG_BITS = 8;
70 constexpr int PM_PG_WIDTH = 1 << PM_PG_BITS;
71 constexpr int PM_DP_BITS = 16;
72 constexpr int PM_DP_WIDTH = 1 << PM_DP_BITS;
73 constexpr int AM_PG_BITS = 8;
74 constexpr int AM_PG_WIDTH = 1 << AM_PG_BITS;
75 constexpr int AM_DP_BITS = 16;
76 constexpr int AM_DP_WIDTH = 1 << AM_DP_BITS;
77 
78 // LFO Table
79 constexpr unsigned PM_DPHASE = unsigned(PM_SPEED * PM_DP_WIDTH / (Y8950::CLOCK_FREQ / double(Y8950::CLOCK_FREQ_DIV)));
80 
81 
82 // LFO Amplitude Modulation table (verified on real YM3812)
83 // 27 output levels (triangle waveform);
84 // 1 level takes one of: 192, 256 or 448 samples
85 //
86 // Length: 210 elements.
87 // Each of the elements has to be repeated
88 // exactly 64 times (on 64 consecutive samples).
89 // The whole table takes: 64 * 210 = 13440 samples.
90 //
91 // Verified on real YM3812 (OPL2), but I believe it's the same for Y8950
92 // because it closely matches the Y8950 AM parameters:
93 // speed = 3.7Hz
94 // depth = 4.875dB
95 // Also this approach can be easily implemented in HW, the previous one (see SVN
96 // history) could not.
97 constexpr unsigned LFO_AM_TAB_ELEMENTS = 210;
99 {
100  0,0,0,0,0,0,0,
101  1,1,1,1,
102  2,2,2,2,
103  3,3,3,3,
104  4,4,4,4,
105  5,5,5,5,
106  6,6,6,6,
107  7,7,7,7,
108  8,8,8,8,
109  9,9,9,9,
110  10,10,10,10,
111  11,11,11,11,
112  12,12,12,12,
113  13,13,13,13,
114  14,14,14,14,
115  15,15,15,15,
116  16,16,16,16,
117  17,17,17,17,
118  18,18,18,18,
119  19,19,19,19,
120  20,20,20,20,
121  21,21,21,21,
122  22,22,22,22,
123  23,23,23,23,
124  24,24,24,24,
125  25,25,25,25,
126  26,26,26,
127  25,25,25,25,
128  24,24,24,24,
129  23,23,23,23,
130  22,22,22,22,
131  21,21,21,21,
132  20,20,20,20,
133  19,19,19,19,
134  18,18,18,18,
135  17,17,17,17,
136  16,16,16,16,
137  15,15,15,15,
138  14,14,14,14,
139  13,13,13,13,
140  12,12,12,12,
141  11,11,11,11,
142  10,10,10,10,
143  9,9,9,9,
144  8,8,8,8,
145  7,7,7,7,
146  6,6,6,6,
147  5,5,5,5,
148  4,4,4,4,
149  3,3,3,3,
150  2,2,2,2,
151  1,1,1,1
152 };
153 
154 //**************************************************//
155 // //
156 // Helper functions //
157 // //
158 //**************************************************//
159 
160 static constexpr unsigned DB_POS(int x)
161 {
162  int result = int(x / DB_STEP);
163  assert(result < DB_MUTE);
164  assert(result >= 0);
165  return result;
166 }
167 static constexpr unsigned DB_NEG(int x)
168 {
169  return 2 * DB_MUTE + DB_POS(x);
170 }
171 
172 //**************************************************//
173 // //
174 // Create tables //
175 // //
176 //**************************************************//
177 
178 // Linear to Log curve conversion table (for Attack rate) and vice versa.
179 // values are in the range [0 .. EG_MUTE]
180 // adjustAR[] and adjustRA[] are each others inverse, IOW
181 // adjustRA[adjustAR[x]] == x
182 // (except for rounding errors).
183 constexpr auto adjustAR = [] {
184  std::array<unsigned, EG_MUTE> result = {};
185  result[0] = EG_MUTE;
186  auto log_eg_mute = cstd::log<6, 5>(EG_MUTE);
187  for (int i : xrange(1, int(EG_MUTE))) {
188  result[i] = (EG_MUTE - 1 - EG_MUTE * cstd::log<6, 5>(i) / log_eg_mute) / 2;
189  assert(0 <= int(result[i]));
190  assert(result[i] <= EG_MUTE);
191  }
192  return result;
193 }();
194 constexpr auto adjustRA = [] {
195  std::array<unsigned, EG_MUTE + 1> result = {};
196  result[0] = EG_MUTE;
197  for (int i : xrange(1, int(EG_MUTE))) {
198  result[i] = cstd::pow<6, 5>(EG_MUTE, (double(EG_MUTE) - 1 - 2 * i) / EG_MUTE);
199  assert(0 <= int(result[i]));
200  assert(result[i] <= EG_MUTE);
201  }
202  result[EG_MUTE] = 0;
203  return result;
204 }();
205 
206 // Table for dB(0 -- (1<<DB_BITS)) to Liner(0 -- DB2LIN_AMP_WIDTH)
207 constexpr auto dB2LinTab = [] {
208  std::array<int, (2 * DB_MUTE) * 2> result = {};
209  for (int i : xrange(DB_MUTE)) {
210  result[i] = int(double((1 << DB2LIN_AMP_BITS) - 1) *
211  cstd::pow<7, 3>(10, -double(i) * DB_STEP / 20.0));
212  }
213  assert(result[DB_MUTE - 1] == 0);
214  for (auto i : xrange(DB_MUTE, 2 * DB_MUTE)) {
215  result[i] = 0;
216  }
217  for (auto i : xrange(2 * DB_MUTE)) {
218  result[i + 2 * DB_MUTE] = -result[i];
219  }
220  return result;
221 }();
222 
223 // WaveTable for each envelope amp.
224 // values are in range[ 0, DB_MUTE) (for positive values)
225 // or [2*DB_MUTE, 3*DB_MUTE) (for negative values)
226 constexpr auto sinTable = [] {
227  // Linear(+0.0 ... +1.0) to dB(DB_MUTE-1 ... 0)
228  auto lin2db = [](double d) {
229  if (d < 1e-4) { // (almost) zero
230  return DB_MUTE - 1;
231  }
232  int tmp = -int(20.0 * cstd::log10<6, 2>(d) / DB_STEP);
233  int result = std::min(tmp, DB_MUTE - 1);
234  assert(result >= 0);
235  assert(result <= DB_MUTE - 1);
236  return result;
237  };
238 
239  std::array<unsigned, PG_WIDTH> result = {};
240  for (int i : xrange(PG_WIDTH / 4)) {
241  result[i] = lin2db(cstd::sin<2>(2.0 * M_PI * i / PG_WIDTH));
242  }
243  for (auto i : xrange(PG_WIDTH / 4)) {
244  result[PG_WIDTH / 2 - 1 - i] = result[i];
245  }
246  for (auto i : xrange(PG_WIDTH / 2)) {
247  result[PG_WIDTH / 2 + i] = 2 * DB_MUTE + result[i];
248  }
249  return result;
250 }();
251 
252 // Table for Pitch Modulator
253 constexpr auto pmTable = [] {
254  std::array<std::array<int, PM_PG_WIDTH>, 2> result = {};
255  for (int i : xrange(PM_PG_WIDTH)) {
256  auto s = cstd::sin<5>(2.0 * M_PI * i / PM_PG_WIDTH) / 1200;
257  result[0][i] = int(PM_AMP * cstd::exp2<2>(PM_DEPTH * s));
258  result[1][i] = int(PM_AMP * cstd::exp2<2>(PM_DEPTH2 * s));
259  }
260  return result;
261 }();
262 
263 // TL Table.
264 constexpr auto tllTable = [] {
265  // Processed version of Table 3.5 from the Application Manual
266  constexpr unsigned klTable[16] = {
267  0, 24, 32, 37, 40, 43, 45, 47, 48, 50, 51, 52, 53, 54, 55, 56
268  };
269  // This is indeed {0.0, 3.0, 1.5, 6.0} dB/oct, verified on real Y8950.
270  // Note the illogical order of 2nd and 3rd element.
271  constexpr unsigned shift[4] = { 31, 1, 2, 0 };
272 
273  std::array<std::array<int, 4>, 16 * 8> result = {};
274  for (auto freq : xrange(16 * 8u)) {
275  unsigned fnum = freq % 16;
276  unsigned block = freq / 16;
277  int tmp = 4 * klTable[fnum] - 32 * (7 - block);
278  for (auto KL : xrange(4)) {
279  result[freq][KL] = (tmp <= 0) ? 0 : (tmp >> shift[KL]);
280  }
281  }
282  return result;
283 }();
284 
285 // Phase incr table for Attack.
286 constexpr auto dPhaseArTable = [] {
287  std::array<std::array<Y8950::EnvPhaseIndex, 16>, 16> result = {};
288  for (auto Rks : xrange(16)) {
289  result[Rks][0] = Y8950::EnvPhaseIndex(0);
290  for (auto AR : xrange(1, 15)) {
291  unsigned RM = std::min(AR + (Rks >> 2), 15);
292  unsigned RL = Rks & 3;
293  result[Rks][AR] =
294  Y8950::EnvPhaseIndex(12 * (RL + 4)) >> (15 - RM);
295  }
296  result[Rks][15] = EG_DP_MAX;
297  }
298  return result;
299 }();
300 
301 // Phase incr table for Decay and Release.
302 constexpr auto dPhaseDrTable = [] {
303  std::array<std::array<Y8950::EnvPhaseIndex, 16>, 16> result = {};
304  for (auto Rks : xrange(16)) {
305  result[Rks][0] = Y8950::EnvPhaseIndex(0);
306  for (auto DR : xrange(1, 16)) {
307  unsigned RM = std::min(DR + (Rks >> 2), 15);
308  unsigned RL = Rks & 3;
309  result[Rks][DR] =
310  Y8950::EnvPhaseIndex(RL + 4) >> (15 - RM);
311  }
312  }
313  return result;
314 }();
315 
316 
317 // class Y8950::Patch
318 
319 Y8950::Patch::Patch()
320 {
321  reset();
322 }
323 
324 void Y8950::Patch::reset()
325 {
326  AM = false;
327  PM = false;
328  EG = false;
329  ML = 0;
330  KL = 0;
331  TL = 0;
332  AR = 0;
333  DR = 0;
334  SL = 0;
335  RR = 0;
336  setKeyScaleRate(false);
337  setFeedbackShift(0);
338 }
339 
340 
341 // class Y8950::Slot
342 
343 void Y8950::Slot::reset()
344 {
345  phase = 0;
346  output = 0;
347  feedback = 0;
348  eg_mode = FINISH;
349  eg_phase = EG_DP_MAX;
350  key = 0;
351  patch.reset();
352 
353  // this initializes:
354  // dPhase, tll, dPhaseARTableRks, dPhaseDRTableRks, eg_dPhase
355  updateAll(0);
356 }
357 
358 void Y8950::Slot::updatePG(unsigned freq)
359 {
360  static constexpr int mlTable[16] = {
361  1, 1*2, 2*2, 3*2, 4*2, 5*2, 6*2 , 7*2,
362  8*2, 9*2, 10*2, 10*2, 12*2, 12*2, 15*2, 15*2
363  };
364 
365  unsigned fnum = freq % 1024;
366  unsigned block = freq / 1024;
367  dPhase = ((fnum * mlTable[patch.ML]) << block) >> (21 - DP_BITS);
368 }
369 
370 void Y8950::Slot::updateTLL(unsigned freq)
371 {
372  tll = tllTable[freq >> 6][patch.KL] + patch.TL * TL_PER_EG;
373 }
374 
375 void Y8950::Slot::updateRKS(unsigned freq)
376 {
377  unsigned rks = freq >> patch.KR;
378  assert(rks < 16);
379  dPhaseARTableRks = dPhaseArTable[rks].data();
380  dPhaseDRTableRks = dPhaseDrTable[rks].data();
381 }
382 
383 void Y8950::Slot::updateEG()
384 {
385  switch (eg_mode) {
386  case ATTACK:
387  eg_dPhase = dPhaseARTableRks[patch.AR];
388  break;
389  case DECAY:
390  eg_dPhase = dPhaseDRTableRks[patch.DR];
391  break;
392  case SUSTAIN:
393  case RELEASE:
394  eg_dPhase = dPhaseDRTableRks[patch.RR];
395  break;
396  case FINISH:
397  eg_dPhase = Y8950::EnvPhaseIndex(0);
398  break;
399  }
400 }
401 
402 void Y8950::Slot::updateAll(unsigned freq)
403 {
404  updatePG(freq);
405  updateTLL(freq);
406  updateRKS(freq);
407  updateEG(); // EG should be last
408 }
409 
410 bool Y8950::Slot::isActive() const
411 {
412  return eg_mode != FINISH;
413 }
414 
415 // Slot key on
416 void Y8950::Slot::slotOn(KeyPart part)
417 {
418  if (!key) {
419  eg_mode = ATTACK;
420  phase = 0;
421  eg_phase = Y8950::EnvPhaseIndex(adjustRA[eg_phase.toInt()]);
422  }
423  key |= part;
424 }
425 
426 // Slot key off
427 void Y8950::Slot::slotOff(KeyPart part)
428 {
429  if (key) {
430  key &= ~part;
431  if (!key) {
432  if (eg_mode == ATTACK) {
433  eg_phase = Y8950::EnvPhaseIndex(adjustAR[eg_phase.toInt()]);
434  }
435  eg_mode = RELEASE;
436  }
437  }
438 }
439 
440 
441 // class Y8950::Channel
442 
443 Y8950::Channel::Channel()
444 {
445  reset();
446 }
447 
448 void Y8950::Channel::reset()
449 {
450  setFreq(0);
451  slot[MOD].reset();
452  slot[CAR].reset();
453  alg = false;
454 }
455 
456 // Set frequency (combined F-Number (10bit) and Block (3bit))
457 void Y8950::Channel::setFreq(unsigned freq_)
458 {
459  freq = freq_;
460 }
461 
462 void Y8950::Channel::keyOn(KeyPart part)
463 {
464  slot[MOD].slotOn(part);
465  slot[CAR].slotOn(part);
466 }
467 
468 void Y8950::Channel::keyOff(KeyPart part)
469 {
470  slot[MOD].slotOff(part);
471  slot[CAR].slotOff(part);
472 }
473 
474 constexpr auto INPUT_RATE = unsigned(cstd::round(Y8950::CLOCK_FREQ / double(Y8950::CLOCK_FREQ_DIV)));
475 
476 Y8950::Y8950(const std::string& name_, const DeviceConfig& config,
477  unsigned sampleRam, EmuTime::param time, MSXAudio& audio)
478  : ResampledSoundDevice(config.getMotherBoard(), name_, "MSX-AUDIO", 9 + 5 + 1, INPUT_RATE, false)
479  , motherBoard(config.getMotherBoard())
480  , periphery(audio.createPeriphery(getName()))
481  , adpcm(*this, config, name_, sampleRam)
482  , connector(motherBoard.getPluggingController())
483  , dac13(name_ + " DAC", "MSX-AUDIO 13-bit DAC", config)
484  , debuggable(motherBoard, getName())
485  , timer1(EmuTimer::createOPL3_1(motherBoard.getScheduler(), *this))
486  , timer2(EmuTimer::createOPL3_2(motherBoard.getScheduler(), *this))
487  , irq(motherBoard, getName() + ".IRQ")
488  , enabled(true)
489 {
490  // For debugging: print out tables to be able to compare before/after
491  // when the calculation changes.
492  if (false) {
493  for (auto i : xrange(PM_PG_WIDTH)) {
494  std::cout << pmTable[0][i] << ' '
495  << pmTable[1][i] << '\n';
496  }
497  std::cout << '\n';
498 
499  for (auto i : xrange(EG_MUTE)) {
500  std::cout << adjustRA[i] << ' '
501  << adjustAR[i] << '\n';
502  }
503  std::cout << adjustRA[EG_MUTE] << "\n\n";
504 
505  for (const auto& e : dB2LinTab) std::cout << e << '\n';
506  std::cout << '\n';
507 
508  for (auto i : xrange(16 * 8)) {
509  for (auto j : xrange(4)) {
510  std::cout << tllTable[i][j] << ' ';
511  }
512  std::cout << '\n';
513  }
514  std::cout << '\n';
515 
516  for (const auto& e : sinTable) std::cout << e << '\n';
517  std::cout << '\n';
518 
519  for (auto i : xrange(16)) {
520  for (auto j : xrange(16)) {
521  std::cout << dPhaseArTable[i][j].getRawValue() << ' ';
522  }
523  std::cout << '\n';
524  }
525  std::cout << '\n';
526 
527  for (auto i : xrange(16)) {
528  for (auto j : xrange(16)) {
529  std::cout << dPhaseDrTable[i][j].getRawValue() << ' ';
530  }
531  std::cout << '\n';
532  }
533  std::cout << '\n';
534  }
535 
536  reset(time);
537  registerSound(config);
538 }
539 
541 {
542  unregisterSound();
543 }
544 
546 {
547  adpcm.clearRam();
548 }
549 
550 // Reset whole of opl except patch data.
551 void Y8950::reset(EmuTime::param time)
552 {
553  for (auto& c : ch) c.reset();
554 
555  rythm_mode = false;
556  am_mode = false;
557  pm_mode = false;
558  pm_phase = 0;
559  am_phase = 0;
560  noise_seed = 0xffff;
561  noiseA_phase = 0;
562  noiseB_phase = 0;
563  noiseA_dPhase = 0;
564  noiseB_dPhase = 0;
565 
566  // update the output buffer before changing the register
567  updateStream(time);
568  ranges::fill(reg, 0x00);
569 
570  reg[0x04] = 0x18;
571  reg[0x19] = 0x0F; // fixes 'Thunderbirds are Go'
572  status = 0x00;
573  statusMask = 0;
574  irq.reset();
575 
576  adpcm.reset(time);
577 }
578 
579 
580 // Drum key on
581 void Y8950::keyOn_BD() { ch[6].keyOn(KEY_RHYTHM); }
582 void Y8950::keyOn_HH() { ch[7].slot[MOD].slotOn(KEY_RHYTHM); }
583 void Y8950::keyOn_SD() { ch[7].slot[CAR].slotOn(KEY_RHYTHM); }
584 void Y8950::keyOn_TOM() { ch[8].slot[MOD].slotOn(KEY_RHYTHM); }
585 void Y8950::keyOn_CYM() { ch[8].slot[CAR].slotOn(KEY_RHYTHM); }
586 
587 // Drum key off
588 void Y8950::keyOff_BD() { ch[6].keyOff(KEY_RHYTHM); }
589 void Y8950::keyOff_HH() { ch[7].slot[MOD].slotOff(KEY_RHYTHM); }
590 void Y8950::keyOff_SD() { ch[7].slot[CAR].slotOff(KEY_RHYTHM); }
591 void Y8950::keyOff_TOM(){ ch[8].slot[MOD].slotOff(KEY_RHYTHM); }
592 void Y8950::keyOff_CYM(){ ch[8].slot[CAR].slotOff(KEY_RHYTHM); }
593 
594 // Change Rhythm Mode
595 void Y8950::setRythmMode(int data)
596 {
597  bool newMode = (data & 32) != 0;
598  if (rythm_mode != newMode) {
599  rythm_mode = newMode;
600  if (!rythm_mode) {
601  // ON->OFF
602  keyOff_BD(); // TODO keyOff() or immediately to FINISH?
603  keyOff_HH(); // other variants use keyOff(), but
604  keyOff_SD(); // verify on real HW
605  keyOff_TOM();
606  keyOff_CYM();
607  }
608  }
609 }
610 
611 // recalculate 'key' from register settings
612 void Y8950::update_key_status()
613 {
614  for (auto [i, c] : enumerate(ch)) {
615  int main = (reg[0xb0 + i] & 0x20) ? KEY_MAIN : 0;
616  c.slot[MOD].key = main;
617  c.slot[CAR].key = main;
618  }
619  if (rythm_mode) {
620  ch[6].slot[MOD].key |= (reg[0xbd] & 0x10) ? KEY_RHYTHM : 0; // BD1
621  ch[6].slot[CAR].key |= (reg[0xbd] & 0x10) ? KEY_RHYTHM : 0; // BD2
622  ch[7].slot[MOD].key |= (reg[0xbd] & 0x01) ? KEY_RHYTHM : 0; // HH
623  ch[7].slot[CAR].key |= (reg[0xbd] & 0x08) ? KEY_RHYTHM : 0; // SD
624  ch[8].slot[MOD].key |= (reg[0xbd] & 0x04) ? KEY_RHYTHM : 0; // TOM
625  ch[8].slot[CAR].key |= (reg[0xbd] & 0x02) ? KEY_RHYTHM : 0; // CYM
626  }
627 }
628 
629 
630 //
631 // Generate wave data
632 //
633 
634 // Convert Amp(0 to EG_HEIGHT) to Phase(0 to 8PI).
635 static constexpr int wave2_8pi(int e)
636 {
637  int shift = SLOT_AMP_BITS - PG_BITS - 2;
638  return (shift > 0) ? (e >> shift) : (e << -shift);
639 }
640 
641 unsigned Y8950::Slot::calc_phase(int lfo_pm)
642 {
643  if (patch.PM) {
644  phase += (dPhase * lfo_pm) >> PM_AMP_BITS;
645  } else {
646  phase += dPhase;
647  }
648  return phase >> DP_BASE_BITS;
649 }
650 
651 static constexpr auto S2E(int x) {
652  return Y8950::EnvPhaseIndex(int(x / EG_STEP));
653 }
654 constexpr Y8950::EnvPhaseIndex SL[16] = {
655  S2E( 0), S2E( 3), S2E( 6), S2E( 9), S2E(12), S2E(15), S2E(18), S2E(21),
656  S2E(24), S2E(27), S2E(30), S2E(33), S2E(36), S2E(39), S2E(42), S2E(93)
657 };
658 unsigned Y8950::Slot::calc_envelope(int lfo_am)
659 {
660  unsigned egOut = 0;
661  switch (eg_mode) {
662  case ATTACK:
663  eg_phase += eg_dPhase;
664  if (eg_phase >= EG_DP_MAX) {
665  egOut = 0;
666  eg_phase = Y8950::EnvPhaseIndex(0);
667  eg_mode = DECAY;
668  updateEG();
669  } else {
670  egOut = adjustAR[eg_phase.toInt()];
671  }
672  break;
673 
674  case DECAY:
675  eg_phase += eg_dPhase;
676  if (eg_phase >= SL[patch.SL]) {
677  eg_phase = SL[patch.SL];
678  eg_mode = SUSTAIN;
679  updateEG();
680  }
681  egOut = eg_phase.toInt();
682  break;
683 
684  case SUSTAIN:
685  if (!patch.EG) {
686  eg_phase += eg_dPhase;
687  }
688  egOut = eg_phase.toInt();
689  if (egOut >= EG_MUTE) {
690  eg_phase = EG_DP_MAX;
691  eg_mode = FINISH;
692  egOut = EG_MUTE - 1;
693  }
694  break;
695 
696  case RELEASE:
697  eg_phase += eg_dPhase;
698  egOut = eg_phase.toInt();
699  if (egOut >= EG_MUTE) {
700  eg_phase = EG_DP_MAX;
701  eg_mode = FINISH;
702  egOut = EG_MUTE - 1;
703  }
704  break;
705 
706  case FINISH:
707  egOut = EG_MUTE - 1;
708  break;
709  }
710 
711  egOut = ((egOut + tll) * EG_PER_DB);
712  if (patch.AM) {
713  egOut += lfo_am;
714  }
715  return std::min<unsigned>(egOut, DB_MUTE - 1);
716 }
717 
718 int Y8950::Slot::calc_slot_car(int lfo_pm, int lfo_am, int fm)
719 {
720  unsigned egOut = calc_envelope(lfo_am);
721  int pgout = calc_phase(lfo_pm) + wave2_8pi(fm);
722  return dB2LinTab[sinTable[pgout & PG_MASK] + egOut];
723 }
724 
725 int Y8950::Slot::calc_slot_mod(int lfo_pm, int lfo_am)
726 {
727  unsigned egOut = calc_envelope(lfo_am);
728  unsigned pgout = calc_phase(lfo_pm);
729 
730  if (patch.FB != 0) {
731  pgout += wave2_8pi(feedback) >> patch.FB;
732  }
733  int newOutput = dB2LinTab[sinTable[pgout & PG_MASK] + egOut];
734  feedback = (output + newOutput) >> 1;
735  output = newOutput;
736  return feedback;
737 }
738 
739 int Y8950::Slot::calc_slot_tom(int lfo_pm, int lfo_am)
740 {
741  unsigned egOut = calc_envelope(lfo_am);
742  unsigned pgout = calc_phase(lfo_pm);
743  return dB2LinTab[sinTable[pgout & PG_MASK] + egOut];
744 }
745 
746 int Y8950::Slot::calc_slot_snare(int lfo_pm, int lfo_am, int whitenoise)
747 {
748  unsigned egOut = calc_envelope(lfo_am);
749  unsigned pgout = calc_phase(lfo_pm);
750  unsigned tmp = (pgout & (1 << (PG_BITS - 1))) ? 0 : 2 * DB_MUTE;
751  return (dB2LinTab[tmp + egOut] + dB2LinTab[egOut + whitenoise]) >> 1;
752 }
753 
754 int Y8950::Slot::calc_slot_cym(int lfo_am, int a, int b)
755 {
756  unsigned egOut = calc_envelope(lfo_am);
757  return (dB2LinTab[egOut + a] + dB2LinTab[egOut + b]) >> 1;
758 }
759 
760 // HI-HAT
761 int Y8950::Slot::calc_slot_hat(int lfo_am, int a, int b, int whitenoise)
762 {
763  unsigned egOut = calc_envelope(lfo_am);
764  return (dB2LinTab[egOut + whitenoise] +
765  dB2LinTab[egOut + a] +
766  dB2LinTab[egOut + b]) >> 2;
767 }
768 
769 float Y8950::getAmplificationFactorImpl() const
770 {
771  return 1.0f / (1 << DB2LIN_AMP_BITS);
772 }
773 
774 void Y8950::setEnabled(bool enabled_, EmuTime::param time)
775 {
776  updateStream(time);
777  enabled = enabled_;
778 }
779 
780 bool Y8950::checkMuteHelper()
781 {
782  if (!enabled) {
783  return true;
784  }
785  for (auto i : xrange(6)) {
786  if (ch[i].slot[CAR].isActive()) return false;
787  }
788  if (!rythm_mode) {
789  for (auto i : xrange(6, 9)) {
790  if (ch[i].slot[CAR].isActive()) return false;
791  }
792  } else {
793  if (ch[6].slot[CAR].isActive()) return false;
794  if (ch[7].slot[MOD].isActive()) return false;
795  if (ch[7].slot[CAR].isActive()) return false;
796  if (ch[8].slot[MOD].isActive()) return false;
797  if (ch[8].slot[CAR].isActive()) return false;
798  }
799 
800  return adpcm.isMuted();
801 }
802 
803 void Y8950::generateChannels(float** bufs, unsigned num)
804 {
805  // TODO implement per-channel mute (instead of all-or-nothing)
806  if (checkMuteHelper()) {
807  // TODO update internal state even when muted
808  // during mute pm_phase, am_phase, noiseA_phase, noiseB_phase
809  // and noise_seed aren't updated, probably ok
810  std::fill_n(bufs, 9 + 5 + 1, nullptr);
811  return;
812  }
813 
814  for (auto sample : xrange(num)) {
815  // Amplitude modulation: 27 output levels (triangle waveform);
816  // 1 level takes one of: 192, 256 or 448 samples
817  // One entry from LFO_AM_TABLE lasts for 64 samples
818  // lfo_am_table is 210 elements long
819  ++am_phase;
820  if (am_phase == (LFO_AM_TAB_ELEMENTS * 64)) am_phase = 0;
821  unsigned tmp = lfo_am_table[am_phase / 64];
822  int lfo_am = am_mode ? tmp : tmp / 4;
823 
824  pm_phase = (pm_phase + PM_DPHASE) & (PM_DP_WIDTH - 1);
825  int lfo_pm = pmTable[pm_mode][pm_phase >> (PM_DP_BITS - PM_PG_BITS)];
826 
827  if (noise_seed & 1) {
828  noise_seed ^= 0x24000;
829  }
830  noise_seed >>= 1;
831  int whitenoise = noise_seed & 1 ? DB_POS(6) : DB_NEG(6);
832 
833  noiseA_phase += noiseA_dPhase;
834  noiseA_phase &= (0x40 << 11) - 1;
835  if ((noiseA_phase >> 11) == 0x3f) {
836  noiseA_phase = 0;
837  }
838  int noiseA = noiseA_phase & (0x03 << 11) ? DB_POS(6) : DB_NEG(6);
839 
840  noiseB_phase += noiseB_dPhase;
841  noiseB_phase &= (0x10 << 11) - 1;
842  int noiseB = noiseB_phase & (0x0A << 11) ? DB_POS(6) : DB_NEG(6);
843 
844  for (auto i : xrange(rythm_mode ? 6 : 9)) {
845  if (ch[i].slot[CAR].isActive()) {
846  bufs[i][sample] += ch[i].alg
847  ? ch[i].slot[CAR].calc_slot_car(lfo_pm, lfo_am, 0) +
848  ch[i].slot[MOD].calc_slot_mod(lfo_pm, lfo_am)
849  : ch[i].slot[CAR].calc_slot_car(lfo_pm, lfo_am,
850  ch[i].slot[MOD].calc_slot_mod(lfo_pm, lfo_am));
851  } else {
852  //bufs[i][sample] += 0;
853  }
854  }
855  if (rythm_mode) {
856  //bufs[6][sample] += 0;
857  //bufs[7][sample] += 0;
858  //bufs[8][sample] += 0;
859 
860  // TODO wasn't in original source either
861  (void)ch[7].slot[MOD].calc_phase(lfo_pm);
862  (void)ch[8].slot[CAR].calc_phase(lfo_pm);
863 
864  bufs[ 9][sample] += (ch[6].slot[CAR].isActive())
865  ? 2 * ch[6].slot[CAR].calc_slot_car(lfo_pm, lfo_am,
866  ch[6].slot[MOD].calc_slot_mod(lfo_pm, lfo_am))
867  : 0;
868  bufs[10][sample] += (ch[7].slot[CAR].isActive())
869  ? 2 * ch[7].slot[CAR].calc_slot_snare(lfo_pm, lfo_am, whitenoise)
870  : 0;
871  bufs[11][sample] += (ch[8].slot[CAR].isActive())
872  ? 2 * ch[8].slot[CAR].calc_slot_cym(lfo_am, noiseA, noiseB)
873  : 0;
874  bufs[12][sample] += (ch[7].slot[MOD].isActive())
875  ? 2 * ch[7].slot[MOD].calc_slot_hat(lfo_am, noiseA, noiseB, whitenoise)
876  : 0;
877  bufs[13][sample] += (ch[8].slot[MOD].isActive())
878  ? 2 * ch[8].slot[MOD].calc_slot_tom(lfo_pm, lfo_am)
879  : 0;
880  } else {
881  //bufs[ 9] += 0;
882  //bufs[10] += 0;
883  //bufs[11] += 0;
884  //bufs[12] += 0;
885  //bufs[13] += 0;
886  }
887 
888  bufs[14][sample] += adpcm.calcSample();
889  }
890 }
891 
892 //
893 // I/O Ctrl
894 //
895 
896 void Y8950::writeReg(byte rg, byte data, EmuTime::param time)
897 {
898  int sTbl[32] = {
899  0, 2, 4, 1, 3, 5, -1, -1,
900  6, 8, 10, 7, 9, 11, -1, -1,
901  12, 14, 16, 13, 15, 17, -1, -1,
902  -1, -1, -1, -1, -1, -1, -1, -1
903  };
904 
905  // TODO only for registers that influence sound
906  // TODO also ADPCM
907  //if (rg >= 0x20) {
908  // update the output buffer before changing the register
909  updateStream(time);
910  //}
911 
912  switch (rg & 0xe0) {
913  case 0x00: {
914  switch (rg) {
915  case 0x01: // TEST
916  // TODO
917  // Y8950 MSX-AUDIO Test register $01 (write only)
918  //
919  // Bit Description
920  //
921  // 7 Reset LFOs - seems to force the LFOs to their initial
922  // values (eg. maximum amplitude, zero phase deviation)
923  //
924  // 6 something to do with ADPCM - bit 0 of the status
925  // register is affected by setting this bit (PCM BSY)
926  //
927  // 5 No effect? - Waveform select enable in YM3812 OPL2 so seems
928  // reasonable that this bit wouldn't have been used in OPL
929  //
930  // 4 No effect?
931  //
932  // 3 Faster LFOs - increases the frequencies of the LFOs and
933  // (maybe) the timers (cf. YM2151 test register)
934  //
935  // 2 Reset phase generators - No phase generator output, but
936  // envelope generators still work (can hear a transient
937  // when they are gated)
938  //
939  // 1 No effect?
940  //
941  // 0 Reset envelopes - Envelope generator outputs forced
942  // to maximum, so all enabled voices sound at maximum
943  reg[rg] = data;
944  break;
945 
946  case 0x02: // TIMER1 (resolution 80us)
947  timer1->setValue(data);
948  reg[rg] = data;
949  break;
950 
951  case 0x03: // TIMER2 (resolution 320us)
952  timer2->setValue(data);
953  reg[rg] = data;
954  break;
955 
956  case 0x04: // FLAG CONTROL
957  if (data & Y8950::R04_IRQ_RESET) {
958  resetStatus(0x78); // reset all flags
959  } else {
960  changeStatusMask((~data) & 0x78);
961  timer1->setStart((data & Y8950::R04_ST1) != 0, time);
962  timer2->setStart((data & Y8950::R04_ST2) != 0, time);
963  reg[rg] = data;
964  }
965  adpcm.resetStatus();
966  break;
967 
968  case 0x06: // (KEYBOARD OUT)
969  connector.write(data, time);
970  reg[rg] = data;
971  break;
972 
973  case 0x07: // START/REC/MEM DATA/REPEAT/SP-OFF/-/-/RESET
974  periphery.setSPOFF((data & 8) != 0, time); // bit 3
975  [[fallthrough]];
976 
977  case 0x08: // CSM/KEY BOARD SPLIT/-/-/SAMPLE/DA AD/64K/ROM
978  case 0x09: // START ADDRESS (L)
979  case 0x0A: // START ADDRESS (H)
980  case 0x0B: // STOP ADDRESS (L)
981  case 0x0C: // STOP ADDRESS (H)
982  case 0x0D: // PRESCALE (L)
983  case 0x0E: // PRESCALE (H)
984  case 0x0F: // ADPCM-DATA
985  case 0x10: // DELTA-N (L)
986  case 0x11: // DELTA-N (H)
987  case 0x12: // ENVELOP CONTROL
988  case 0x1A: // PCM-DATA
989  reg[rg] = data;
990  adpcm.writeReg(rg, data, time);
991  break;
992 
993  case 0x15: // DAC-DATA (bit9-2)
994  reg[rg] = data;
995  if (reg[0x08] & 0x04) {
996  int tmp = static_cast<signed char>(reg[0x15]) * 256
997  + reg[0x16];
998  tmp = (tmp * 4) >> (7 - reg[0x17]);
999  tmp = Math::clipIntToShort(tmp);
1000  dac13.writeDAC(tmp, time);
1001  }
1002  break;
1003  case 0x16: // (bit1-0)
1004  reg[rg] = data & 0xC0;
1005  break;
1006  case 0x17: // (exponent)
1007  reg[rg] = data & 0x07;
1008  break;
1009 
1010  case 0x18: // I/O-CONTROL (bit3-0)
1011  // 0 -> input
1012  // 1 -> output
1013  reg[rg] = data;
1014  periphery.write(reg[0x18], reg[0x19], time);
1015  break;
1016 
1017  case 0x19: // I/O-DATA (bit3-0)
1018  reg[rg] = data;
1019  periphery.write(reg[0x18], reg[0x19], time);
1020  break;
1021  }
1022  break;
1023  }
1024  case 0x20: {
1025  int s = sTbl[rg & 0x1f];
1026  if (s >= 0) {
1027  auto& chan = ch[s / 2];
1028  auto& slot = chan.slot[s & 1];
1029  slot.patch.AM = (data >> 7) & 1;
1030  slot.patch.PM = (data >> 6) & 1;
1031  slot.patch.EG = (data >> 5) & 1;
1032  slot.patch.setKeyScaleRate((data & 0x10) != 0);
1033  slot.patch.ML = (data >> 0) & 15;
1034  slot.updateAll(chan.freq);
1035  }
1036  reg[rg] = data;
1037  break;
1038  }
1039  case 0x40: {
1040  int s = sTbl[rg & 0x1f];
1041  if (s >= 0) {
1042  auto& chan = ch[s / 2];
1043  auto& slot = chan.slot[s & 1];
1044  slot.patch.KL = (data >> 6) & 3;
1045  slot.patch.TL = (data >> 0) & 63;
1046  slot.updateAll(chan.freq);
1047  }
1048  reg[rg] = data;
1049  break;
1050  }
1051  case 0x60: {
1052  int s = sTbl[rg & 0x1f];
1053  if (s >= 0) {
1054  auto& slot = ch[s / 2].slot[s & 1];
1055  slot.patch.AR = (data >> 4) & 15;
1056  slot.patch.DR = (data >> 0) & 15;
1057  slot.updateEG();
1058  }
1059  reg[rg] = data;
1060  break;
1061  }
1062  case 0x80: {
1063  int s = sTbl[rg & 0x1f];
1064  if (s >= 0) {
1065  auto& slot = ch[s / 2].slot[s & 1];
1066  slot.patch.SL = (data >> 4) & 15;
1067  slot.patch.RR = (data >> 0) & 15;
1068  slot.updateEG();
1069  }
1070  reg[rg] = data;
1071  break;
1072  }
1073  case 0xa0: {
1074  if (rg == 0xbd) {
1075  am_mode = (data & 0x80) != 0;
1076  pm_mode = (data & 0x40) != 0;
1077 
1078  setRythmMode(data);
1079  if (rythm_mode) {
1080  if (data & 0x10) keyOn_BD(); else keyOff_BD();
1081  if (data & 0x08) keyOn_SD(); else keyOff_SD();
1082  if (data & 0x04) keyOn_TOM(); else keyOff_TOM();
1083  if (data & 0x02) keyOn_CYM(); else keyOff_CYM();
1084  if (data & 0x01) keyOn_HH(); else keyOff_HH();
1085  }
1086  ch[6].slot[MOD].updateAll(ch[6].freq);
1087  ch[6].slot[CAR].updateAll(ch[6].freq);
1088  ch[7].slot[MOD].updateAll(ch[7].freq);
1089  ch[7].slot[CAR].updateAll(ch[7].freq);
1090  ch[8].slot[MOD].updateAll(ch[8].freq);
1091  ch[8].slot[CAR].updateAll(ch[8].freq);
1092 
1093  reg[rg] = data;
1094  break;
1095  }
1096  unsigned c = rg & 0x0f;
1097  if (c > 8) {
1098  // 0xa9-0xaf 0xb9-0xbf
1099  break;
1100  }
1101  unsigned freq = [&] {
1102  if (!(rg & 0x10)) {
1103  // 0xa0-0xa8
1104  return data | ((reg[rg + 0x10] & 0x1F) << 8);
1105  } else {
1106  // 0xb0-0xb8
1107  if (data & 0x20) {
1108  ch[c].keyOn (KEY_MAIN);
1109  } else {
1110  ch[c].keyOff(KEY_MAIN);
1111  }
1112  return reg[rg - 0x10] | ((data & 0x1F) << 8);
1113  }
1114  }();
1115  ch[c].setFreq(freq);
1116  unsigned fNum = freq % 1024;
1117  unsigned block = freq / 1024;
1118  switch (c) {
1119  case 7: noiseA_dPhase = fNum << block;
1120  break;
1121  case 8: noiseB_dPhase = fNum << block;
1122  break;
1123  }
1124  ch[c].slot[CAR].updateAll(freq);
1125  ch[c].slot[MOD].updateAll(freq);
1126  reg[rg] = data;
1127  break;
1128  }
1129  case 0xc0: {
1130  if (rg > 0xc8)
1131  break;
1132  int c = rg - 0xC0;
1133  ch[c].slot[MOD].patch.setFeedbackShift((data >> 1) & 7);
1134  ch[c].alg = data & 1;
1135  reg[rg] = data;
1136  }
1137  }
1138 }
1139 
1140 byte Y8950::readReg(byte rg, EmuTime::param time)
1141 {
1142  updateStream(time); // TODO only when necessary
1143 
1144  switch (rg) {
1145  case 0x0F: // ADPCM-DATA
1146  case 0x13: // ???
1147  case 0x14: // ???
1148  case 0x1A: // PCM-DATA
1149  return adpcm.readReg(rg, time);
1150  default:
1151  return peekReg(rg, time);
1152  }
1153 }
1154 
1155 byte Y8950::peekReg(byte rg, EmuTime::param time) const
1156 {
1157  switch (rg) {
1158  case 0x05: // (KEYBOARD IN)
1159  return connector.peek(time);
1160 
1161  case 0x0F: // ADPCM-DATA
1162  case 0x13: // ???
1163  case 0x14: // ???
1164  case 0x1A: // PCM-DATA
1165  return adpcm.peekReg(rg, time);
1166 
1167  case 0x19: { // I/O DATA
1168  byte input = periphery.read(time);
1169  byte output = reg[0x19];
1170  byte enable = reg[0x18];
1171  return (output & enable) | (input & ~enable) | 0xF0;
1172  }
1173  default:
1174  return reg[rg];
1175  }
1176 }
1177 
1178 byte Y8950::readStatus(EmuTime::param time) const
1179 {
1180  byte result = peekStatus(time);
1181  //std::cout << "status: " << (int)result << '\n';
1182  return result;
1183 }
1184 
1185 byte Y8950::peekStatus(EmuTime::param time) const
1186 {
1187  const_cast<Y8950Adpcm&>(adpcm).sync(time);
1188  return (status & (0x87 | statusMask)) | 0x06; // bit 1 and 2 are always 1
1189 }
1190 
1191 void Y8950::callback(byte flag)
1192 {
1193  setStatus(flag);
1194 }
1195 
1196 void Y8950::setStatus(byte flags)
1197 {
1198  status |= flags;
1199  if (status & statusMask) {
1200  status |= 0x80;
1201  irq.set();
1202  }
1203 }
1204 void Y8950::resetStatus(byte flags)
1205 {
1206  status &= ~flags;
1207  if (!(status & statusMask)) {
1208  status &= 0x7f;
1209  irq.reset();
1210  }
1211 }
1213 {
1214  return status;
1215 }
1216 void Y8950::changeStatusMask(byte newMask)
1217 {
1218  statusMask = newMask;
1219  status &= 0x87 | statusMask;
1220  if (status & statusMask) {
1221  status |= 0x80;
1222  irq.set();
1223  } else {
1224  status &= 0x7f;
1225  irq.reset();
1226  }
1227 }
1228 
1229 
1230 template<typename Archive>
1231 void Y8950::Patch::serialize(Archive& ar, unsigned /*version*/)
1232 {
1233  ar.serialize("AM", AM,
1234  "PM", PM,
1235  "EG", EG,
1236  "KR", KR,
1237  "ML", ML,
1238  "KL", KL,
1239  "TL", TL,
1240  "FB", FB,
1241  "AR", AR,
1242  "DR", DR,
1243  "SL", SL,
1244  "RR", RR);
1245 }
1246 
1247 static constexpr std::initializer_list<enum_string<Y8950::EnvelopeState>> envelopeStateInfo = {
1248  { "ATTACK", Y8950::ATTACK },
1249  { "DECAY", Y8950::DECAY },
1250  { "SUSTAIN", Y8950::SUSTAIN },
1251  { "RELEASE", Y8950::RELEASE },
1252  { "FINISH", Y8950::FINISH }
1253 };
1255 
1256 // version 1: initial version
1257 // version 2: 'slotStatus' is replaced with 'key' and no longer serialized
1258 // instead it's recalculated via update_key_status()
1259 // version 3: serialize 'eg_mode' as an enum instead of an int, also merged
1260 // the 2 enum values SUSHOLD and SUSTINE into SUSTAIN
1261 template<typename Archive>
1262 void Y8950::Slot::serialize(Archive& ar, unsigned version)
1263 {
1264  ar.serialize("feedback", feedback,
1265  "output", output,
1266  "phase", phase,
1267  "eg_phase", eg_phase,
1268  "patch", patch);
1269  if (ar.versionAtLeast(version, 3)) {
1270  ar.serialize("eg_mode", eg_mode);
1271  } else {
1272  assert(Archive::IS_LOADER);
1273  int tmp = 0; // dummy init to avoid warning
1274  ar.serialize("eg_mode", tmp);
1275  switch (tmp) {
1276  case 0: eg_mode = ATTACK; break;
1277  case 1: eg_mode = DECAY; break;
1278  case 2: eg_mode = SUSTAIN; break; // was SUSHOLD
1279  case 3: eg_mode = SUSTAIN; break; // was SUSTINE
1280  case 4: eg_mode = RELEASE; break;
1281  default: eg_mode = FINISH; break;
1282  }
1283  }
1284 
1285  // These are restored by call to updateAll() in Y8950::Channel::serialize()
1286  // dPhase, tll, dPhaseARTableRks, dPhaseDRTableRks, eg_dPhase
1287  // These are restored by update_key_status():
1288  // key
1289 }
1290 
1291 template<typename Archive>
1292 void Y8950::Channel::serialize(Archive& ar, unsigned /*version*/)
1293 {
1294  ar.serialize("mod", slot[MOD],
1295  "car", slot[CAR],
1296  "freq", freq,
1297  "alg", alg);
1298 
1299  if constexpr (Archive::IS_LOADER) {
1300  slot[MOD].updateAll(freq);
1301  slot[CAR].updateAll(freq);
1302  }
1303 }
1304 
1305 template<typename Archive>
1306 void Y8950::serialize(Archive& ar, unsigned /*version*/)
1307 {
1308  ar.serialize("keyboardConnector", connector,
1309  "adpcm", adpcm,
1310  "timer1", *timer1,
1311  "timer2", *timer2,
1312  "irq", irq);
1313  ar.serialize_blob("registers", reg, sizeof(reg));
1314  ar.serialize("pm_phase", pm_phase,
1315  "am_phase", am_phase,
1316  "noise_seed", noise_seed,
1317  "noiseA_phase", noiseA_phase,
1318  "noiseB_phase", noiseB_phase,
1319  "noiseA_dphase", noiseA_dPhase,
1320  "noiseB_dphase", noiseB_dPhase,
1321  "channels", ch,
1322  "status", status,
1323  "statusMask", statusMask,
1324  "rythm_mode", rythm_mode,
1325  "am_mode", am_mode,
1326  "pm_mode", pm_mode,
1327  "enabled", enabled);
1328 
1329  if constexpr (Archive::IS_LOADER) {
1330  // TODO restore more state from registers
1331  static constexpr byte rewriteRegs[] = {
1332  6, // connector
1333  15, // dac13
1334  };
1335 
1336  update_key_status();
1337  EmuTime::param time = motherBoard.getCurrentTime();
1338  for (auto r : rewriteRegs) {
1339  writeReg(r, reg[r], time);
1340  }
1341  }
1342 }
1343 
1344 
1345 // SimpleDebuggable
1346 
1347 Y8950::Debuggable::Debuggable(MSXMotherBoard& motherBoard_,
1348  const std::string& name_)
1349  : SimpleDebuggable(motherBoard_, name_ + " regs", "MSX-AUDIO", 0x100)
1350 {
1351 }
1352 
1353 byte Y8950::Debuggable::read(unsigned address, EmuTime::param time)
1354 {
1355  auto& y8950 = OUTER(Y8950, debuggable);
1356  return y8950.peekReg(address, time);
1357 }
1358 
1359 void Y8950::Debuggable::write(unsigned address, byte value, EmuTime::param time)
1360 {
1361  auto& y8950 = OUTER(Y8950, debuggable);
1362  y8950.writeReg(address, value, time);
1363 }
1364 
1366 SERIALIZE_CLASS_VERSION(Y8950::Slot, 3);
1367 
1368 } // namespace openmsx
#define M_PI
Definition: Math.hh:27
void writeDAC(int16_t value, EmuTime::param time)
Definition: DACSound16S.cc:34
void set()
Set the interrupt request on the bus.
Definition: IRQHelper.hh:87
void reset()
Reset the interrupt request on the bus.
Definition: IRQHelper.hh:96
EmuTime::param getCurrentTime()
Convenience method: This is the same as getScheduler().getCurrentTime().
void updateStream(EmuTime::param time)
Definition: SoundDevice.cc:141
void unregisterSound()
Unregisters this sound device with the Mixer.
Definition: SoundDevice.cc:136
void registerSound(const DeviceConfig &config)
Registers this sound device with the Mixer.
Definition: SoundDevice.cc:92
byte readReg(byte rg, EmuTime::param time)
Definition: Y8950Adpcm.cc:301
bool isMuted() const
Definition: Y8950Adpcm.cc:89
byte peekReg(byte rg, EmuTime::param time) const
Definition: Y8950Adpcm.cc:310
void writeReg(byte rg, byte data, EmuTime::param time)
Definition: Y8950Adpcm.cc:151
void reset(EmuTime::param time)
Definition: Y8950Adpcm.cc:63
void write(byte data, EmuTime::param time)
byte peek(EmuTime::param time) const
virtual void write(nibble outputs, nibble values, EmuTime::param time)=0
Write to (some of) the pins.
virtual void setSPOFF(bool value, EmuTime::param time)
SP-OFF bit (bit 3 in Y8950 register 7)
virtual nibble read(EmuTime::param time)=0
Read from (some of) the pins Some of the pins might be programmed as output, but this method doesn't ...
void reset(EmuTime::param time)
Definition: Y8950.cc:551
byte peekRawStatus() const
Definition: Y8950.cc:1212
byte readStatus(EmuTime::param time) const
Definition: Y8950.cc:1178
void setEnabled(bool enabled, EmuTime::param time)
Definition: Y8950.cc:774
static constexpr int CLOCK_FREQ_DIV
Definition: Y8950.hh:27
Y8950(const std::string &name, const DeviceConfig &config, unsigned sampleRam, EmuTime::param time, MSXAudio &audio)
Definition: Y8950.cc:476
static constexpr int R04_IRQ_RESET
Definition: Y8950.hh:45
FixedPoint< EG_DP_BITS - EG_BITS > EnvPhaseIndex
Definition: Y8950.hh:105
byte peekReg(byte rg, EmuTime::param time) const
Definition: Y8950.cc:1155
static constexpr int R04_ST2
Definition: Y8950.hh:33
void serialize(Archive &ar, unsigned version)
Definition: Y8950.cc:1306
void clearRam()
Definition: Y8950.cc:545
void resetStatus(byte flags)
Definition: Y8950.cc:1204
static constexpr int R04_ST1
Definition: Y8950.hh:31
void writeReg(byte rg, byte data, EmuTime::param time)
Definition: Y8950.cc:896
static constexpr int CLOCK_FREQ
Definition: Y8950.hh:26
static constexpr int EG_BITS
Definition: Y8950.hh:101
byte readReg(byte rg, EmuTime::param time)
Definition: Y8950.cc:1140
void setStatus(byte flags)
Definition: Y8950.cc:1196
byte peekStatus(EmuTime::param time) const
Definition: Y8950.cc:1185
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
Definition: enumerate.hh:28
int main(int argc, char **argv)
Definition: main.cc:173
int16_t clipIntToShort(int x)
Clip x to range [-32768,32767].
Definition: Math.hh:100
constexpr double round(double x)
Definition: cstd.hh:355
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:269
string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:742
constexpr uint8_t mlTable[16]
This file implemented 3 utility functions:
Definition: Autofire.cc:9
constexpr Y8950::EnvPhaseIndex EG_DP_MAX
Definition: Y8950.cc:27
constexpr unsigned TL_PER_EG
Definition: Y8950.cc:38
constexpr int PG_WIDTH
Definition: Y8950.cc:51
constexpr int PM_PG_BITS
Definition: Y8950.cc:69
constexpr int AM_DP_BITS
Definition: Y8950.cc:75
constexpr int PM_DP_BITS
Definition: Y8950.cc:71
constexpr unsigned LFO_AM_TAB_ELEMENTS
Definition: Y8950.cc:97
constexpr int DP_BITS
Definition: Y8950.cc:54
constexpr int PM_PG_WIDTH
Definition: Y8950.cc:70
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
constexpr int DP_BASE_BITS
Definition: Y8950.cc:55
constexpr double PM_DEPTH2
Definition: Y8950.cc:44
constexpr int AM_PG_WIDTH
Definition: Y8950.cc:74
constexpr Y8950::EnvPhaseIndex SL[16]
Definition: Y8950.cc:654
constexpr auto dB2LinTab
Definition: Y8950.cc:207
constexpr auto adjustRA
Definition: Y8950.cc:194
constexpr int AM_PG_BITS
Definition: Y8950.cc:73
constexpr int SL_MUTE
Definition: Y8950.cc:48
constexpr unsigned MOD
Definition: Y8950.cc:29
constexpr unsigned PM_DPHASE
Definition: Y8950.cc:79
constexpr int PG_BITS
Definition: Y8950.cc:50
constexpr double TL_STEP
Definition: Y8950.cc:34
constexpr unsigned EG_PER_DB
Definition: Y8950.cc:39
constexpr double PM_DEPTH
Definition: Y8950.cc:43
constexpr unsigned SL_PER_EG
Definition: Y8950.cc:37
constexpr double DB_STEP
Definition: Y8950.cc:35
constexpr int PG_MASK
Definition: Y8950.cc:52
constexpr auto sinTable
Definition: Y8950.cc:226
constexpr unsigned CAR
Definition: Y8950.cc:30
constexpr int SLOT_AMP_BITS
Definition: Y8950.cc:66
constexpr int DB_BITS
Definition: Y8950.cc:58
constexpr int PM_DP_WIDTH
Definition: Y8950.cc:72
constexpr double EG_STEP
Definition: Y8950.cc:32
constexpr auto tllTable
Definition: Y8950.cc:264
SERIALIZE_CLASS_VERSION(CassettePlayer, 2)
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:124
void serialize(Archive &ar, T &t, unsigned version)
constexpr auto adjustAR
Definition: Y8950.cc:183
constexpr int DB2LIN_AMP_BITS
Definition: Y8950.cc:65
constexpr int SL_BITS
Definition: Y8950.cc:47
constexpr auto dPhaseArTable
Definition: Y8950.cc:286
constexpr int AM_DP_WIDTH
Definition: Y8950.cc:76
constexpr double SL_STEP
Definition: Y8950.cc:33
constexpr int PM_AMP
Definition: Y8950.cc:62
constexpr double PM_SPEED
Definition: Y8950.cc:42
constexpr int PM_AMP_BITS
Definition: Y8950.cc:61
constexpr byte lfo_am_table[LFO_AM_TAB_ELEMENTS]
Definition: Y8950.cc:98
constexpr unsigned EG_MUTE
Definition: Y8950.cc:26
constexpr int DB_MUTE
Definition: Y8950.cc:59
constexpr auto dPhaseDrTable
Definition: Y8950.cc:302
constexpr auto pmTable
Definition: Y8950.cc:253
void fill(ForwardRange &&range, const T &value)
Definition: ranges.hh:197
#define OUTER(type, member)
Definition: outer.hh:41
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:983
constexpr auto xrange(T e)
Definition: xrange.hh:155