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