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