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