OXYGENHUB
◆ main openmsx / src / sound / YM2413Okazaki.cc
48.1 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
/*
2
 * Based on:
3
 *    emu2413.c -- YM2413 emulator written by Mitsutaka Okazaki 2001
4
 * heavily rewritten to fit openMSX structure
5
 */
6
7
#include "YM2413Okazaki.hh"
8
9
#include "Math.hh"
10
#include "cstd.hh"
11
#include "enumerate.hh"
12
#include "inline.hh"
13
#include "narrow.hh"
14
#include "one_of.hh"
15
#include "ranges.hh"
16
#include "serialize.hh"
17
#include "unreachable.hh"
18
#include "xrange.hh"
19
20
#include <algorithm>
21
#include <array>
22
#include <cassert>
23
#include <iostream>
24
25
namespace openmsx {
26
namespace YM2413Okazaki {
27
28
// Number of bits in 'PhaseModulation' fixed point type.
29
static constexpr int PM_FP_BITS =  8;
30
31
// Dynamic range (Accuracy of sin table)
32
static constexpr int DB_BITS = 8;
33
static constexpr int DB_MUTE = 1 << DB_BITS;
34
static constexpr int DBTABLEN = 4 * DB_MUTE; // enough to not have to check for overflow
35
36
static constexpr double DB_STEP = 48.0 / DB_MUTE;
37
static constexpr double EG_STEP = 0.375;
38
static constexpr double TL_STEP = 0.75;
39
40
// Phase increment counter
41
static constexpr int DP_BITS = 18;
42
static constexpr int DP_BASE_BITS = DP_BITS - PG_BITS;
43
44
// Dynamic range of envelope
45
static constexpr int EG_BITS = 7;
46
47
// Bits for linear value
48
static constexpr int DB2LIN_AMP_BITS = 8;
49
static constexpr int SLOT_AMP_BITS = DB2LIN_AMP_BITS;
50
51
// Bits for Amp modulator
52
static constexpr int AM_PG_BITS = 8;
53
static constexpr int AM_PG_WIDTH = 1 << AM_PG_BITS;
54
static constexpr int AM_DP_BITS = 16;
55
static constexpr int AM_DP_WIDTH = 1 << AM_DP_BITS;
56
static constexpr int AM_DP_MASK = AM_DP_WIDTH - 1;
57
58
// LFO Amplitude Modulation table (verified on real YM3812)
59
// 27 output levels (triangle waveform);
60
// 1 level takes one of: 192, 256 or 448 samples
61
//
62
// Length: 210 elements.
63
//  Each of the elements has to be repeated
64
//  exactly 64 times (on 64 consecutive samples).
65
//  The whole table takes: 64 * 210 = 13440 samples.
66
//
67
// Verified on real YM3812 (OPL2), but I believe it's the same for YM2413
68
// because it closely matches the YM2413 AM parameters:
69
//    speed = 3.7Hz
70
//    depth = 4.875dB
71
// Also this approach can be easily implemented in HW, the previous one (see SVN
72
// history) could not.
73
static constexpr unsigned LFO_AM_TAB_ELEMENTS = 210;
74
75
// Extra (derived) constants
76
static constexpr EnvPhaseIndex EG_DP_MAX = EnvPhaseIndex(1 << 7);
77
static constexpr EnvPhaseIndex EG_DP_INF = EnvPhaseIndex(1 << 8); // as long as it's bigger
78
79
// LFO Phase Modulation table (copied from Burczynski core)
80
static constexpr std::array pmTable = {
81
	std::array<int8_t, 8>{0, 0, 0, 0, 0, 0, 0, 0}, // FNUM = 000xxxxxx
82
	std::array<int8_t, 8>{0, 0, 1, 0, 0, 0,-1, 0}, // FNUM = 001xxxxxx
83
	std::array<int8_t, 8>{0, 1, 2, 1, 0,-1,-2,-1}, // FNUM = 010xxxxxx
84
	std::array<int8_t, 8>{0, 1, 3, 1, 0,-1,-3,-1}, // FNUM = 011xxxxxx
85
	std::array<int8_t, 8>{0, 2, 4, 2, 0,-2,-4,-2}, // FNUM = 100xxxxxx
86
	std::array<int8_t, 8>{0, 2, 5, 2, 0,-2,-5,-2}, // FNUM = 101xxxxxx
87
	std::array<int8_t, 8>{0, 3, 6, 3, 0,-3,-6,-3}, // FNUM = 110xxxxxx
88
	std::array<int8_t, 8>{0, 3, 7, 3, 0,-3,-7,-3}, // FNUM = 111xxxxxx
89
};
90
91
// LFO Amplitude Modulation table (verified on real YM3812)
92
static constexpr std::array<uint8_t, LFO_AM_TAB_ELEMENTS> lfo_am_table = {
93
	0,0,0,0,0,0,0,
94
	1,1,1,1,
95
	2,2,2,2,
96
	3,3,3,3,
97
	4,4,4,4,
98
	5,5,5,5,
99
	6,6,6,6,
100
	7,7,7,7,
101
	8,8,8,8,
102
	9,9,9,9,
103
	10,10,10,10,
104
	11,11,11,11,
105
	12,12,12,12,
106
	13,13,13,13,
107
	14,14,14,14,
108
	15,15,15,15,
109
	16,16,16,16,
110
	17,17,17,17,
111
	18,18,18,18,
112
	19,19,19,19,
113
	20,20,20,20,
114
	21,21,21,21,
115
	22,22,22,22,
116
	23,23,23,23,
117
	24,24,24,24,
118
	25,25,25,25,
119
	26,26,26,
120
	25,25,25,25,
121
	24,24,24,24,
122
	23,23,23,23,
123
	22,22,22,22,
124
	21,21,21,21,
125
	20,20,20,20,
126
	19,19,19,19,
127
	18,18,18,18,
128
	17,17,17,17,
129
	16,16,16,16,
130
	15,15,15,15,
131
	14,14,14,14,
132
	13,13,13,13,
133
	12,12,12,12,
134
	11,11,11,11,
135
	10,10,10,10,
136
	9,9,9,9,
137
	8,8,8,8,
138
	7,7,7,7,
139
	6,6,6,6,
140
	5,5,5,5,
141
	4,4,4,4,
142
	3,3,3,3,
143
	2,2,2,2,
144
	1,1,1,1,
145
};
146
147
// ML-table
148
static constexpr std::array<uint8_t, 16> mlTable = {
149
	1,   1*2,  2*2,  3*2,  4*2,  5*2,  6*2,  7*2,
150
	8*2, 9*2, 10*2, 10*2, 12*2, 12*2, 15*2, 15*2
151
};
152
153
// dB to linear table (used by Slot)
154
// dB(0 .. DB_MUTE-1) -> linear(0 .. DB2LIN_AMP_WIDTH)
155
// indices in range:
156
//   [0,        DB_MUTE )    actual values, from max to min
157
//   [DB_MUTE,  DBTABLEN)    filled with min val (to allow some overflow in index)
158
//   [DBTABLEN, 2*DBTABLEN)  as above but for negative output values
159
static constexpr auto dB2LinTab = [] {
160
	std::array<int, 2 * DBTABLEN> result = {};
161
	for (int i : xrange(DB_MUTE - 1)) {
162
		result[i] = int(double((1 << DB2LIN_AMP_BITS) - 1) *
163
		                   cstd::pow<5, 3>(10, -double(i) * DB_STEP / 20));
164
	}
165
	result[DB_MUTE - 1] = 0;
166
	for (auto i : xrange(DB_MUTE, DBTABLEN)) {
167
		result[i] = 0;
168
	}
169
	for (auto i : xrange(DBTABLEN)) {
170
		result[i + DBTABLEN] = -result[i];
171
	}
172
	return result;
173
}();
174
175
// Linear to Log curve conversion table (for Attack rate)
176
static constexpr auto arAdjustTab = [] {
177
	std::array<unsigned, 1 << EG_BITS> result = {};
178
	result[0] = (1 << EG_BITS) - 1;
179
	constexpr double l127 = cstd::log<5, 4>(127.0);
180
	for (int i : xrange(1, 1 << EG_BITS)) {
181
		result[i] = unsigned(double(1 << EG_BITS) - 1 -
182
		         ((1 << EG_BITS) - 1) * cstd::log<5, 4>(double(i)) / l127);
183
	}
184
	return result;
185
}();
186
187
// KSL + TL Table   values are in range [0, 112]
188
static constexpr auto tllTab = [] {
189
	std::array<std::array<uint8_t, 16 * 8>, 4> result = {};
190
191
	// Processed version of Table III-5 from the Application Manual.
192
	constexpr std::array<int, 16> klTable = {
193
		0, 24, 32, 37, 40, 43, 45, 47, 48, 50, 51, 52, 53, 54, 55, 56
194
	};
195
	// Note: KL [0..3] results in {0.0, 1.5, 3.0, 6.0} dB/oct.
196
	// This is different from Y8950 and YMF262 which have {0, 3, 1.5, 6}.
197
	// (2nd and 3rd elements are swapped). Verified on real YM2413.
198
199
	for (auto freq : xrange(16 * 8)) {
200
		int fnum  = freq % 16;
201
		int block = freq / 16;
202
		int tmp = 2 * klTable[fnum] - 16 * (7 - block);
203
		for (auto KL : xrange(4)) {
204
			unsigned t = (tmp <= 0 || KL == 0) ? 0 : (tmp >> (3 - KL));
205
			assert(t <= 112);
206
			result[KL][freq] = narrow<uint8_t>(t);
207
		}
208
	}
209
	return result;
210
}();
211
212
// WaveTable for each envelope amp
213
//  values are in range [0, DB_MUTE)             (for positive values)
214
//                  or  [0, DB_MUTE) + DBTABLEN  (for negative values)
215
static constexpr auto fullSinTable = [] {
216
	auto lin2db = [](double d) {
217
		// lin(+0.0 .. +1.0) to dB(DB_MUTE-1 .. 0)
218
		return (d == 0)
219
			? DB_MUTE - 1
220
			: std::min(-int(20.0 * cstd::log10<5, 2>(d) / DB_STEP), DB_MUTE - 1); // 0 - 127
221
	};
222
223
	std::array<unsigned, PG_WIDTH> result = {};
224
	for (auto i : xrange(PG_WIDTH / 4)) {
225
		result[i] = lin2db(cstd::sin<2>(double(2.0 * Math::pi) * i / PG_WIDTH));
226
	}
227
	for (auto i : xrange(PG_WIDTH / 4)) {
228
		result[PG_WIDTH / 2 - 1 - i] = result[i];
229
	}
230
	for (auto i : xrange(PG_WIDTH / 2)) {
231
		result[PG_WIDTH / 2 + i] = DBTABLEN + result[i];
232
	}
233
	return result;
234
}();
235
static constexpr auto halfSinTable = [] {
236
	std::array<unsigned, PG_WIDTH> result = {};
237
	for (auto i : xrange(PG_WIDTH / 2)) {
238
		result[i] = fullSinTable[i];
239
	}
240
	for (auto i : xrange(PG_WIDTH / 2, PG_WIDTH)) {
241
		result[i] = fullSinTable[0];
242
	}
243
	return result;
244
}();
245
static constexpr std::array<std::span<const unsigned, PG_WIDTH>, 2> waveform = {
246
	fullSinTable, halfSinTable
247
};
248
249
// Phase incr table for attack, decay and release
250
//  note: original code had indices swapped. It also had
251
//        a separate table for attack
252
//  17.15 fixed point
253
static constexpr auto dPhaseDrTab = [] {
254
	std::array<std::array<int, 16>, 16> result = {};
255
	for (auto Rks : xrange(16)) {
256
		result[Rks][0] = 0;
257
		for (auto DR : xrange(1, 16)) {
258
			int RM = std::min(DR + (Rks >> 2), 15);
259
			int RL = Rks & 3;
260
			result[Rks][DR] =
261
				((RL + 4) << EP_FP_BITS) >> (16 - RM);
262
		}
263
	}
264
	return result;
265
}();
266
267
// Sustain level (17.15 fixed point)
268
static constexpr auto slTab = [] {
269
	std::array<unsigned, 16> result = {};
270
	//for (auto [i, r] : enumerate(result)) { msvc bug
271
	for (int i = 0; i < 16; ++i) {
272
		double x = (i == 15) ? 48.0 : (3.0 * i);
273
		result[i] = int(x / EG_STEP) << EP_FP_BITS;
274
	}
275
	return result;
276
}();
277
278
//
279
// Helper functions
280
//
281
static constexpr unsigned EG2DB(unsigned d)
282
{
283
	return d * narrow_cast<unsigned>(EG_STEP / DB_STEP);
284
}
285
static constexpr unsigned TL2EG(unsigned d)
286
{
287
	assert(d < 64); // input is in range [0..63]
288
	return d * narrow_cast<unsigned>(TL_STEP / EG_STEP);
289
}
290
291
static constexpr unsigned DB_POS(double x)
292
{
293
	auto result = int(x / DB_STEP);
294
	assert(0 <= result);
295
	assert(result < DB_MUTE);
296
	return result;
297
}
298
static constexpr unsigned DB_NEG(double x)
299
{
300
	return DBTABLEN + DB_POS(x);
301
}
302
303
// Note: 'int' instead of 'bool' return value to silence clang-warning:
304
//    warning: use of bitwise '&' with boolean operands [-Wbitwise-instead-of-logical]
305
//    note: cast one or both operands to int to silence this warning
306
static constexpr /*bool*/ int BIT(unsigned s, unsigned b)
307
{
308
	return narrow<int>((s >> b) & 1);
309
}
310
311
//
312
// Patch
313
//
314
Patch::Patch()
315
	: WF(waveform[0]), KL(tllTab[0])
316
{
317
	setKR(0);
318
	setML(0);
319
	setTL(0);
320
	setFB(0);
321
	setSL(0);
322
}
323
324
void Patch::initModulator(std::span<const uint8_t, 8> data)
325
{
326
	AMPM = (data[0] >> 6) &  3;
327
	EG   = (data[0] >> 5) &  1;
328
	setKR ((data[0] >> 4) &  1);
329
	setML ((data[0] >> 0) & 15);
330
	setKL ((data[2] >> 6) &  3);
331
	setTL ((data[2] >> 0) & 63);
332
	setWF ((data[3] >> 3) &  1);
333
	setFB ((data[3] >> 0) &  7);
334
	AR   = (data[4] >> 4) & 15;
335
	DR   = (data[4] >> 0) & 15;
336
	setSL ((data[6] >> 4) & 15);
337
	RR   = (data[6] >> 0) & 15;
338
}
339
340
void Patch::initCarrier(std::span<const uint8_t, 8> data)
341
{
342
	AMPM = (data[1] >> 6) &  3;
343
	EG   = (data[1] >> 5) &  1;
344
	setKR ((data[1] >> 4) &  1);
345
	setML ((data[1] >> 0) & 15);
346
	setKL ((data[3] >> 6) &  3);
347
	setTL (0);
348
	setWF ((data[3] >> 4) &  1);
349
	setFB (0);
350
	AR   = (data[5] >> 4) & 15;
351
	DR   = (data[5] >> 0) & 15;
352
	setSL ((data[7] >> 4) & 15);
353
	RR   = (data[7] >> 0) & 15;
354
}
355
356
void Patch::setKR(uint8_t value)
357
{
358
	KR = value ? 8 : 10;
359
}
360
void Patch::setML(uint8_t value)
361
{
362
	ML = mlTable[value];
363
}
364
void Patch::setKL(uint8_t value)
365
{
366
	KL = tllTab[value];
367
}
368
void Patch::setTL(uint8_t value)
369
{
370
	assert(value < 64);
371
	TL = narrow<uint8_t>(TL2EG(value));
372
}
373
void Patch::setWF(uint8_t value)
374
{
375
	WF = waveform[value];
376
}
377
void Patch::setFB(uint8_t value)
378
{
379
	FB = value ? 8 - value : 0;
380
}
381
void Patch::setSL(uint8_t value)
382
{
383
	SL = slTab[value];
384
}
385
386
387
//
388
// Slot
389
//
390
391
Slot::Slot()
392
	: dPhaseDRTableRks(dPhaseDrTab[0])
393
{
394
}
395
396
void Slot::reset()
397
{
398
	cPhase = 0;
399
	std::ranges::fill(dPhase, 0);
400
	output = 0;
401
	feedback = 0;
402
	setEnvelopeState(EnvelopeState::FINISH);
403
	dPhaseDRTableRks = dPhaseDrTab[0];
404
	tll = 0;
405
	sustain = false;
406
	volume = TL2EG(0);
407
	slot_on_flag = 0;
408
}
409
410
void Slot::updatePG(unsigned freq)
411
{
412
	// Pre-calculate all phase-increments. The 8 different values are for
413
	// the 8 steps of the PM stuff (for mod and car phase calculation).
414
	// When PM isn't used then dPhase[0] is used (pmTable[.][0] == 0).
415
	// The original Okazaki core calculated the PM stuff in a different
416
	// way. This algorithm was copied from the Burczynski core because it
417
	// is much more suited for a (cheap) hardware calculation.
418
	unsigned fnum  = freq & 511;
419
	unsigned block = freq / 512;
420
	for (auto [pm, dP] : enumerate(dPhase)) {
421
		unsigned tmp = ((2 * fnum + pmTable[fnum >> 6][pm]) * patch.ML) << block;
422
		dP = tmp >> (21 - DP_BITS);
423
	}
424
}
425
426
void Slot::updateTLL(unsigned freq, bool actAsCarrier)
427
{
428
	tll = patch.KL[freq >> 5] + (actAsCarrier ? volume : patch.TL);
429
}
430
431
void Slot::updateRKS(unsigned freq)
432
{
433
	unsigned rks = freq >> patch.KR;
434
	assert(rks < 16);
435
	dPhaseDRTableRks = dPhaseDrTab[rks];
436
}
437
438
void Slot::updateEG()
439
{
440
	switch (state) {
441
	using enum EnvelopeState;
442
	case ATTACK:
443
		// Original code had separate table for AR, the values in
444
		// this table were 12 times bigger than the values in the
445
		// dPhaseDRTableRks table, expect for the value for AR=15.
446
		// But when AR=15, the value doesn't matter.
447
		//
448
		// This factor 12 can also be seen in the attack/decay rates
449
		// table in the ym2413 application manual (table III-7, page
450
		// 13). For other chips like OPL1, OPL3 this ratio seems to be
451
		// different.
452
		eg_dPhase = EnvPhaseIndex::create(
453
			dPhaseDRTableRks[patch.AR] * 12);
454
		break;
455
	case DECAY:
456
		eg_dPhase = EnvPhaseIndex::create(dPhaseDRTableRks[patch.DR]);
457
		break;
458
	case SUSTAIN:
459
		eg_dPhase = EnvPhaseIndex::create(dPhaseDRTableRks[patch.RR]);
460
		break;
461
	case RELEASE: {
462
		unsigned idx = sustain ? 5
463
		                       : (patch.EG ? patch.RR
464
		                                   : 7);
465
		eg_dPhase = EnvPhaseIndex::create(dPhaseDRTableRks[idx]);
466
		break;
467
	}
468
	case SETTLE:
469
		// Value based on ym2413 application manual:
470
		//  - p10: (envelope graph)
471
		//         DP: 10ms
472
		//  - p13: (table III-7 attack and decay rates)
473
		//         Rate 12-0 -> 10.22ms
474
		//         Rate 12-1 ->  8.21ms
475
		//         Rate 12-2 ->  6.84ms
476
		//         Rate 12-3 ->  5.87ms
477
		// The datasheet doesn't say anything about key-scaling for
478
		// this state (in fact it doesn't say much at all about this
479
		// state). Experiments showed that the with key-scaling the
480
		// output matches closer the real HW. Also all other states use
481
		// key-scaling.
482
		eg_dPhase = EnvPhaseIndex::create(dPhaseDRTableRks[12]);
483
		break;
484
	case SUSHOLD:
485
	case FINISH:
486
		eg_dPhase = EnvPhaseIndex(0);
487
		break;
488
	}
489
}
490
491
void Slot::updateAll(unsigned freq, bool actAsCarrier)
492
{
493
	updatePG(freq);
494
	updateTLL(freq, actAsCarrier);
495
	updateRKS(freq);
496
	updateEG(); // EG should be updated last
497
}
498
499
void Slot::setEnvelopeState(EnvelopeState state_)
500
{
501
	state = state_;
502
	switch (state) {
503
	using enum EnvelopeState;
504
	case ATTACK:
505
		eg_phase_max = (patch.AR == 15) ? EnvPhaseIndex(0) : EG_DP_MAX;
506
		break;
507
	case DECAY:
508
		eg_phase_max = EnvPhaseIndex::create(narrow<int>(patch.SL));
509
		break;
510
	case SUSHOLD:
511
		eg_phase_max = EG_DP_INF;
512
		break;
513
	case SETTLE:
514
	case SUSTAIN:
515
	case RELEASE:
516
		eg_phase_max = EG_DP_MAX;
517
		break;
518
	case FINISH:
519
		eg_phase = EG_DP_MAX;
520
		eg_phase_max = EG_DP_INF;
521
		break;
522
	}
523
	updateEG();
524
}
525
526
bool Slot::isActive() const
527
{
528
	return state != EnvelopeState::FINISH;
529
}
530
531
// Slot key on
532
void Slot::slotOn()
533
{
534
	setEnvelopeState(EnvelopeState::ATTACK);
535
	eg_phase = EnvPhaseIndex(0);
536
	cPhase = 0;
537
}
538
539
// Slot key on, without resetting the phase
540
void Slot::slotOn2()
541
{
542
	setEnvelopeState(EnvelopeState::ATTACK);
543
	eg_phase = EnvPhaseIndex(0);
544
}
545
546
// Slot key off
547
void Slot::slotOff()
548
{
549
	if (state == EnvelopeState::FINISH) return; // already in off state
550
	if (state == EnvelopeState::ATTACK) {
551
		eg_phase = EnvPhaseIndex(arAdjustTab[eg_phase.toInt()]);
552
	}
553
	setEnvelopeState(EnvelopeState::RELEASE);
554
}
555
556
557
// Change a rhythm voice
558
void Slot::setPatch(const Patch& newPatch)
559
{
560
	patch = newPatch; // copy data
561
	if ((state == EnvelopeState::SUSHOLD) && (patch.EG == 0)) {
562
		setEnvelopeState(EnvelopeState::SUSTAIN);
563
	}
564
	setEnvelopeState(state); // recalculate eg_phase_max
565
}
566
567
// Set new volume based on 4-bit register value (0-15).
568
void Slot::setVolume(unsigned value)
569
{
570
	// '<< 2' to transform 4 bits to the same range as the 6 bits TL field
571
	volume = TL2EG(value << 2);
572
}
573
574
575
//
576
// Channel
577
//
578
579
Channel::Channel()
580
{
581
	car.sibling = &mod;    // car needs a pointer to its sibling
582
	mod.sibling = nullptr; // mod doesn't need this pointer
583
}
584
585
void Channel::reset(YM2413& ym2413)
586
{
587
	mod.reset();
588
	car.reset();
589
	setPatch(0, ym2413);
590
}
591
592
// Change a voice
593
void Channel::setPatch(unsigned num, YM2413& ym2413)
594
{
595
	mod.setPatch(ym2413.getPatch(num, false));
596
	car.setPatch(ym2413.getPatch(num, true));
597
}
598
599
// Set sustain parameter
600
void Channel::setSustain(bool sustain, bool modActAsCarrier)
601
{
602
	car.sustain = sustain;
603
	if (modActAsCarrier) {
604
		mod.sustain = sustain;
605
	}
606
}
607
608
// Channel key on
609
void Channel::keyOn()
610
{
611
	// TODO Should we also test mod.slot_on_flag?
612
	//      Should we    set    mod.slot_on_flag?
613
	//      Can make a difference for channel 7/8 in rythm mode.
614
	if (!car.slot_on_flag) {
615
		car.setEnvelopeState(Slot::EnvelopeState::SETTLE);
616
		// this will shortly set both car and mod to ATTACK state
617
	}
618
	car.slot_on_flag |= 1;
619
	mod.slot_on_flag |= 1;
620
}
621
622
// Channel key off
623
void Channel::keyOff()
624
{
625
	// Note: no mod.slotOff() in original code!!!
626
	if (car.slot_on_flag) {
627
		car.slot_on_flag &= ~1;
628
		mod.slot_on_flag &= ~1;
629
		if (!car.slot_on_flag) {
630
			car.slotOff();
631
		}
632
	}
633
}
634
635
636
//
637
// YM2413
638
//
639
640
static constexpr std::array inst_data = {
641
	std::array<uint8_t, 8>{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // user instrument
642
	std::array<uint8_t, 8>{ 0x61,0x61,0x1e,0x17,0xf0,0x7f,0x00,0x17 }, // violin
643
	std::array<uint8_t, 8>{ 0x13,0x41,0x16,0x0e,0xfd,0xf4,0x23,0x23 }, // guitar
644
	std::array<uint8_t, 8>{ 0x03,0x01,0x9a,0x04,0xf3,0xf3,0x13,0xf3 }, // piano
645
	std::array<uint8_t, 8>{ 0x11,0x61,0x0e,0x07,0xfa,0x64,0x70,0x17 }, // flute
646
	std::array<uint8_t, 8>{ 0x22,0x21,0x1e,0x06,0xf0,0x76,0x00,0x28 }, // clarinet
647
	std::array<uint8_t, 8>{ 0x21,0x22,0x16,0x05,0xf0,0x71,0x00,0x18 }, // oboe
648
	std::array<uint8_t, 8>{ 0x21,0x61,0x1d,0x07,0x82,0x80,0x17,0x17 }, // trumpet
649
	std::array<uint8_t, 8>{ 0x23,0x21,0x2d,0x16,0x90,0x90,0x00,0x07 }, // organ
650
	std::array<uint8_t, 8>{ 0x21,0x21,0x1b,0x06,0x64,0x65,0x10,0x17 }, // horn
651
	std::array<uint8_t, 8>{ 0x21,0x21,0x0b,0x1a,0x85,0xa0,0x70,0x07 }, // synthesizer
652
	std::array<uint8_t, 8>{ 0x23,0x01,0x83,0x10,0xff,0xb4,0x10,0xf4 }, // harpsichord
653
	std::array<uint8_t, 8>{ 0x97,0xc1,0x20,0x07,0xff,0xf4,0x22,0x22 }, // vibraphone
654
	std::array<uint8_t, 8>{ 0x61,0x00,0x0c,0x05,0xc2,0xf6,0x40,0x44 }, // synthesizer bass
655
	std::array<uint8_t, 8>{ 0x01,0x01,0x56,0x03,0x94,0xc2,0x03,0x12 }, // acoustic bass
656
	std::array<uint8_t, 8>{ 0x21,0x01,0x89,0x03,0xf1,0xe4,0xf0,0x23 }, // electric guitar
657
	std::array<uint8_t, 8>{ 0x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8 },
658
	std::array<uint8_t, 8>{ 0x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7 },
659
	std::array<uint8_t, 8>{ 0x25,0x11,0x00,0x00,0xf8,0xfa,0xf8,0x55 }
660
};
661
662
YM2413::YM2413()
663
{
664
	if (false) {
665
		for (const auto& e : dB2LinTab) std::cout << e << ' ';
666
		std::cout << '\n';
667
668
		for (const auto& e : arAdjustTab) std::cout << e << ' ';
669
		std::cout << '\n';
670
671
		for (auto i : xrange(4)) {
672
			for (auto j : xrange(16 * 8)) {
673
				std::cout << int(tllTab[i][j]) << ' ';
674
			}
675
			std::cout << '\n';
676
		}
677
		std::cout << '\n';
678
679
		for (const auto& e : fullSinTable) std::cout << e << ' ';
680
		std::cout << '\n';
681
		for (const auto& e : halfSinTable) std::cout << e << ' ';
682
		std::cout << '\n';
683
684
		for (auto i : xrange(16)) {
685
			for (auto j : xrange(16)) {
686
				std::cout << dPhaseDrTab[i][j] << ' ';
687
			}
688
			std::cout << '\n';
689
		}
690
		std::cout << '\n';
691
692
		for (const auto& e : slTab) std::cout << e << ' ';
693
		std::cout << '\n';
694
	}
695
696
	std::ranges::fill(reg, 0); // avoid UMR
697
698
	for (auto i : xrange(16 + 3)) {
699
		patches[i][0].initModulator(inst_data[i]);
700
		patches[i][1].initCarrier  (inst_data[i]);
701
	}
702
703
	reset();
704
}
705
706
// Reset whole of OPLL except patch data
707
void YM2413::reset()
708
{
709
	pm_phase = 0;
710
	am_phase = 0;
711
	noise_seed = 0xFFFF;
712
713
	for (auto& ch : channels) {
714
		ch.reset(*this);
715
	}
716
	for (auto i : xrange(uint8_t(0x40))) {
717
		writeReg(i, 0);
718
	}
719
	registerLatch = 0;
720
}
721
722
// Drum key on
723
void YM2413::keyOn_BD()
724
{
725
	Channel& ch6 = channels[6];
726
	if (!ch6.car.slot_on_flag) {
727
		ch6.car.setEnvelopeState(Slot::EnvelopeState::SETTLE);
728
		// this will shortly set both car and mod to ATTACK state
729
	}
730
	ch6.car.slot_on_flag |= 2;
731
	ch6.mod.slot_on_flag |= 2;
732
}
733
void YM2413::keyOn_HH()
734
{
735
	// TODO do these also use the SETTLE stuff?
736
	Channel& ch7 = channels[7];
737
	if (!ch7.mod.slot_on_flag) {
738
		ch7.mod.slotOn2();
739
	}
740
	ch7.mod.slot_on_flag |= 2;
741
}
742
void YM2413::keyOn_SD()
743
{
744
	Channel& ch7 = channels[7];
745
	if (!ch7.car.slot_on_flag) {
746
		ch7.car.slotOn();
747
	}
748
	ch7.car.slot_on_flag |= 2;
749
}
750
void YM2413::keyOn_TOM()
751
{
752
	Channel& ch8 = channels[8];
753
	if (!ch8.mod.slot_on_flag) {
754
		ch8.mod.slotOn();
755
	}
756
	ch8.mod.slot_on_flag |= 2;
757
}
758
void YM2413::keyOn_CYM()
759
{
760
	Channel& ch8 = channels[8];
761
	if (!ch8.car.slot_on_flag) {
762
		ch8.car.slotOn2();
763
	}
764
	ch8.car.slot_on_flag |= 2;
765
}
766
767
// Drum key off
768
void YM2413::keyOff_BD()
769
{
770
	Channel& ch6 = channels[6];
771
	if (ch6.car.slot_on_flag) {
772
		ch6.car.slot_on_flag &= ~2;
773
		ch6.mod.slot_on_flag &= ~2;
774
		if (!ch6.car.slot_on_flag) {
775
			ch6.car.slotOff();
776
		}
777
	}
778
}
779
void YM2413::keyOff_HH()
780
{
781
	Channel& ch7 = channels[7];
782
	if (ch7.mod.slot_on_flag) {
783
		ch7.mod.slot_on_flag &= ~2;
784
		if (!ch7.mod.slot_on_flag) {
785
			ch7.mod.slotOff();
786
		}
787
	}
788
}
789
void YM2413::keyOff_SD()
790
{
791
	Channel& ch7 = channels[7];
792
	if (ch7.car.slot_on_flag) {
793
		ch7.car.slot_on_flag &= ~2;
794
		if (!ch7.car.slot_on_flag) {
795
			ch7.car.slotOff();
796
		}
797
	}
798
}
799
void YM2413::keyOff_TOM()
800
{
801
	Channel& ch8 = channels[8];
802
	if (ch8.mod.slot_on_flag) {
803
		ch8.mod.slot_on_flag &= ~2;
804
		if (!ch8.mod.slot_on_flag) {
805
			ch8.mod.slotOff();
806
		}
807
	}
808
}
809
void YM2413::keyOff_CYM()
810
{
811
	Channel& ch8 = channels[8];
812
	if (ch8.car.slot_on_flag) {
813
		ch8.car.slot_on_flag &= ~2;
814
		if (!ch8.car.slot_on_flag) {
815
			ch8.car.slotOff();
816
		}
817
	}
818
}
819
820
void YM2413::setRhythmFlags(uint8_t old)
821
{
822
	Channel& ch6 = channels[6];
823
	Channel& ch7 = channels[7];
824
	Channel& ch8 = channels[8];
825
826
	// flags = X | X | mode | BD | SD | TOM | TC | HH
827
	uint8_t flags = reg[0x0E];
828
	if ((flags ^ old) & 0x20) {
829
		if (flags & 0x20) {
830
			// OFF -> ON
831
			ch6.setPatch(16, *this);
832
			ch7.setPatch(17, *this);
833
			ch7.mod.setVolume(reg[0x37] >> 4);
834
			ch8.setPatch(18, *this);
835
			ch8.mod.setVolume(reg[0x38] >> 4);
836
		} else {
837
			// ON -> OFF
838
			ch6.setPatch(reg[0x36] >> 4, *this);
839
			keyOff_BD();
840
			ch7.setPatch(reg[0x37] >> 4, *this);
841
			keyOff_SD();
842
			keyOff_HH();
843
			ch8.setPatch(reg[0x38] >> 4, *this);
844
			keyOff_TOM();
845
			keyOff_CYM();
846
		}
847
	}
848
	if (flags & 0x20) {
849
		if (flags & 0x10) keyOn_BD();  else keyOff_BD();
850
		if (flags & 0x08) keyOn_SD();  else keyOff_SD();
851
		if (flags & 0x04) keyOn_TOM(); else keyOff_TOM();
852
		if (flags & 0x02) keyOn_CYM(); else keyOff_CYM();
853
		if (flags & 0x01) keyOn_HH();  else keyOff_HH();
854
	}
855
856
	unsigned freq6 = getFreq(6);
857
	ch6.mod.updateAll(freq6, false);
858
	ch6.car.updateAll(freq6, true);
859
	unsigned freq7 = getFreq(7);
860
	ch7.mod.updateAll(freq7, isRhythm());
861
	ch7.car.updateAll(freq7, true);
862
	unsigned freq8 = getFreq(8);
863
	ch8.mod.updateAll(freq8, isRhythm());
864
	ch8.car.updateAll(freq8, true);
865
}
866
867
void YM2413::update_key_status()
868
{
869
	for (auto [i, ch] : enumerate(channels)) {
870
		uint8_t slot_on = (reg[0x20 + i] & 0x10) ? 1 : 0;
871
		ch.mod.slot_on_flag = slot_on;
872
		ch.car.slot_on_flag = slot_on;
873
	}
874
	if (isRhythm()) {
875
		Channel& ch6 = channels[6];
876
		ch6.mod.slot_on_flag |= uint8_t((reg[0x0e] & 0x10) ? 2 : 0); // BD1
877
		ch6.car.slot_on_flag |= uint8_t((reg[0x0e] & 0x10) ? 2 : 0); // BD2
878
		Channel& ch7 = channels[7];
879
		ch7.mod.slot_on_flag |= uint8_t((reg[0x0e] & 0x01) ? 2 : 0); // HH
880
		ch7.car.slot_on_flag |= uint8_t((reg[0x0e] & 0x08) ? 2 : 0); // SD
881
		Channel& ch8 = channels[8];
882
		ch8.mod.slot_on_flag |= uint8_t((reg[0x0e] & 0x04) ? 2 : 0); // TOM
883
		ch8.car.slot_on_flag |= uint8_t((reg[0x0e] & 0x02) ? 2 : 0); // CYM
884
	}
885
}
886
887
// Convert Amp(0 to EG_HEIGHT) to Phase(0 to 8PI)
888
static constexpr int wave2_8pi(int e)
889
{
890
	int shift = SLOT_AMP_BITS - PG_BITS - 2;
891
	if (shift > 0) {
892
		return e >> shift;
893
	} else {
894
		return e << -shift;
895
	}
896
}
897
898
// PG
899
ALWAYS_INLINE unsigned Slot::calc_phase(unsigned lfo_pm)
900
{
901
	cPhase += dPhase[lfo_pm];
902
	return cPhase >> DP_BASE_BITS;
903
}
904
905
// EG
906
void Slot::calc_envelope_outline(unsigned& out)
907
{
908
	switch (state) {
909
	using enum EnvelopeState;
910
	case ATTACK:
911
		out = 0;
912
		eg_phase = EnvPhaseIndex(0);
913
		setEnvelopeState(DECAY);
914
		break;
915
	case DECAY:
916
		eg_phase = eg_phase_max;
917
		setEnvelopeState(patch.EG ? SUSHOLD : SUSTAIN);
918
		break;
919
	case SUSTAIN:
920
	case RELEASE:
921
		setEnvelopeState(FINISH);
922
		break;
923
	case SETTLE:
924
		// Comment copied from Burczynski code (didn't verify myself):
925
		//   When CARRIER envelope gets down to zero level, phases in
926
		//   BOTH operators are reset (at the same time?).
927
		slotOn();
928
		sibling->slotOn();
929
		break;
930
	case SUSHOLD:
931
	case FINISH:
932
	default:
933
		UNREACHABLE;
934
	}
935
}
936
template<bool HAS_AM, bool FIXED_ENV>
937
ALWAYS_INLINE unsigned Slot::calc_envelope(int lfo_am, unsigned fixed_env)
938
{
939
	assert(!FIXED_ENV || (state == one_of(EnvelopeState::SUSHOLD, EnvelopeState::FINISH)));
940
941
	if constexpr (FIXED_ENV) {
942
		unsigned out = fixed_env;
943
		if constexpr (HAS_AM) {
944
			out += lfo_am; // [0, 768)
945
			out |= 3;
946
		} else {
947
			// out |= 3   is already done in calc_fixed_env()
948
		}
949
		return out;
950
	} else {
951
		unsigned out = eg_phase.toInt(); // in range [0, 128]
952
		if (state == EnvelopeState::ATTACK) {
953
			out = arAdjustTab[out]; // [0, 128]
954
		}
955
		eg_phase += eg_dPhase;
956
		if (eg_phase >= eg_phase_max) {
957
			calc_envelope_outline(out);
958
		}
959
		out = EG2DB(out + tll); // [0, 732]
960
		if constexpr (HAS_AM) {
961
			out += lfo_am; // [0, 758]
962
		}
963
		return out | 3;
964
	}
965
}
966
template<bool HAS_AM> unsigned Slot::calc_fixed_env() const
967
{
968
	assert(state == one_of(EnvelopeState::SUSHOLD, EnvelopeState::FINISH));
969
	assert(eg_dPhase == EnvPhaseIndex(0));
970
	unsigned out = eg_phase.toInt(); // in range [0, 128)
971
	out = EG2DB(out + tll); // [0, 480)
972
	if constexpr (!HAS_AM) {
973
		out |= 3;
974
	}
975
	return out;
976
}
977
978
// CARRIER
979
template<bool HAS_AM, bool FIXED_ENV>
980
ALWAYS_INLINE int Slot::calc_slot_car(unsigned lfo_pm, int lfo_am, int fm, unsigned fixed_env)
981
{
982
	int phase = narrow<int>(calc_phase(lfo_pm)) + wave2_8pi(fm);
983
	unsigned egOut = calc_envelope<HAS_AM, FIXED_ENV>(lfo_am, fixed_env);
984
	int newOutput = dB2LinTab[patch.WF[phase & PG_MASK] + egOut];
985
	output = (output + newOutput) >> 1;
986
	return output;
987
}
988
989
// MODULATOR
990
template<bool HAS_AM, bool HAS_FB, bool FIXED_ENV>
991
ALWAYS_INLINE int Slot::calc_slot_mod(unsigned lfo_pm, int lfo_am, unsigned fixed_env)
992
{
993
	assert((patch.FB != 0) == HAS_FB);
994
	unsigned phase = calc_phase(lfo_pm);
995
	unsigned egOut = calc_envelope<HAS_AM, FIXED_ENV>(lfo_am, fixed_env);
996
	if constexpr (HAS_FB) {
997
		phase += wave2_8pi(feedback) >> patch.FB;
998
	}
999
	int newOutput = dB2LinTab[patch.WF[phase & PG_MASK] + egOut];
1000
	feedback = (output + newOutput) >> 1;
1001
	output = newOutput;
1002
	return feedback;
1003
}
1004
1005
// TOM (ch8 mod)
1006
ALWAYS_INLINE int Slot::calc_slot_tom()
1007
{
1008
	unsigned phase = calc_phase(0);
1009
	unsigned egOut = calc_envelope<false, false>(0, 0);
1010
	return dB2LinTab[patch.WF[phase & PG_MASK] + egOut];
1011
}
1012
1013
// SNARE (ch7 car)
1014
ALWAYS_INLINE int Slot::calc_slot_snare(bool noise)
1015
{
1016
	unsigned phase = calc_phase(0);
1017
	unsigned egOut = calc_envelope<false, false>(0, 0);
1018
	return BIT(phase, 7)
1019
		? dB2LinTab[(noise ? DB_POS(0.0) : DB_POS(15.0)) + egOut]
1020
		: dB2LinTab[(noise ? DB_NEG(0.0) : DB_NEG(15.0)) + egOut];
1021
}
1022
1023
// TOP-CYM (ch8 car)
1024
ALWAYS_INLINE int Slot::calc_slot_cym(unsigned phase7, unsigned phase8)
1025
{
1026
	unsigned egOut = calc_envelope<false, false>(0, 0);
1027
	unsigned dbOut = (((BIT(phase7, PG_BITS - 8) ^
1028
	                    BIT(phase7, PG_BITS - 1)) |
1029
	                   BIT(phase7, PG_BITS - 7)) ^
1030
	                  ( BIT(phase8, PG_BITS - 7) &
1031
	                   !BIT(phase8, PG_BITS - 5)))
1032
	               ? DB_NEG(3.0)
1033
	               : DB_POS(3.0);
1034
	return dB2LinTab[dbOut + egOut];
1035
}
1036
1037
// HI-HAT (ch7 mod)
1038
ALWAYS_INLINE int Slot::calc_slot_hat(unsigned phase7, unsigned phase8, bool noise)
1039
{
1040
	unsigned egOut = calc_envelope<false, false>(0, 0);
1041
	unsigned dbOut = (((BIT(phase7, PG_BITS - 8) ^
1042
	                    BIT(phase7, PG_BITS - 1)) |
1043
	                   BIT(phase7, PG_BITS - 7)) ^
1044
	                  ( BIT(phase8, PG_BITS - 7) &
1045
	                   !BIT(phase8, PG_BITS - 5)))
1046
	               ? (noise ? DB_NEG(12.0) : DB_NEG(24.0))
1047
	               : (noise ? DB_POS(12.0) : DB_POS(24.0));
1048
	return dB2LinTab[dbOut + egOut];
1049
}
1050
1051
float YM2413::getAmplificationFactor() const
1052
{
1053
	return 1.0f / (1 << DB2LIN_AMP_BITS);
1054
}
1055
1056
bool YM2413::isRhythm() const
1057
{
1058
	return (reg[0x0E] & 0x20) != 0;
1059
}
1060
1061
unsigned YM2413::getFreq(unsigned channel) const
1062
{
1063
	// combined fnum (=9bit) and block (=3bit)
1064
	assert(channel < 9);
1065
	return reg[0x10 + channel] | ((reg[0x20 + channel] & 0x0F) << 8);
1066
}
1067
1068
Patch& YM2413::getPatch(unsigned instrument, bool carrier)
1069
{
1070
	return patches[instrument][carrier];
1071
}
1072
1073
template<unsigned FLAGS>
1074
ALWAYS_INLINE void YM2413::calcChannel(Channel& ch, std::span<float> buf)
1075
{
1076
	// VC++ requires explicit conversion to bool. Compiler bug??
1077
	const bool HAS_CAR_PM = (FLAGS &  1) != 0;
1078
	const bool HAS_CAR_AM = (FLAGS &  2) != 0;
1079
	const bool HAS_MOD_PM = (FLAGS &  4) != 0;
1080
	const bool HAS_MOD_AM = (FLAGS &  8) != 0;
1081
	const bool HAS_MOD_FB = (FLAGS & 16) != 0;
1082
	const bool HAS_CAR_FIXED_ENV = (FLAGS & 32) != 0;
1083
	const bool HAS_MOD_FIXED_ENV = (FLAGS & 64) != 0;
1084
1085
	assert(((ch.car.patch.AMPM & 1) != 0) == HAS_CAR_PM);
1086
	assert(((ch.car.patch.AMPM & 2) != 0) == HAS_CAR_AM);
1087
	assert(((ch.mod.patch.AMPM & 1) != 0) == HAS_MOD_PM);
1088
	assert(((ch.mod.patch.AMPM & 2) != 0) == HAS_MOD_AM);
1089
1090
	unsigned tmp_pm_phase = pm_phase;
1091
	unsigned tmp_am_phase = am_phase;
1092
	unsigned car_fixed_env = 0; // dummy
1093
	unsigned mod_fixed_env = 0; // dummy
1094
	if constexpr (HAS_CAR_FIXED_ENV) {
1095
		car_fixed_env = ch.car.calc_fixed_env<HAS_CAR_AM>();
1096
	}
1097
	if constexpr (HAS_MOD_FIXED_ENV) {
1098
		mod_fixed_env = ch.mod.calc_fixed_env<HAS_MOD_AM>();
1099
	}
1100
1101
	for (auto& b : buf) {
1102
		unsigned lfo_pm = 0;
1103
		if constexpr (HAS_CAR_PM || HAS_MOD_PM) {
1104
			// Copied from Burczynski:
1105
			//  There are only 8 different steps for PM, and each
1106
			//  step lasts for 1024 samples. This results in a PM
1107
			//  freq of 6.1Hz (but datasheet says it's 6.4Hz).
1108
			++tmp_pm_phase;
1109
			lfo_pm = (tmp_pm_phase >> 10) & 7;
1110
		}
1111
		int lfo_am = 0; // avoid warning
1112
		if constexpr (HAS_CAR_AM || HAS_MOD_AM) {
1113
			++tmp_am_phase;
1114
			if (tmp_am_phase == (LFO_AM_TAB_ELEMENTS * 64)) {
1115
				tmp_am_phase = 0;
1116
			}
1117
			lfo_am = lfo_am_table[tmp_am_phase / 64];
1118
		}
1119
		int fm = ch.mod.calc_slot_mod<HAS_MOD_AM, HAS_MOD_FB, HAS_MOD_FIXED_ENV>(
1120
		                      HAS_MOD_PM ? lfo_pm : 0, lfo_am, mod_fixed_env);
1121
		b += narrow_cast<float>(ch.car.calc_slot_car<HAS_CAR_AM, HAS_CAR_FIXED_ENV>(
1122
		                      HAS_CAR_PM ? lfo_pm : 0, lfo_am, fm, car_fixed_env));
1123
	}
1124
}
1125
1126
void YM2413::generateChannels(std::span<float*, 9 + 5> bufs, unsigned num)
1127
{
1128
	assert(num != 0);
1129
1130
	for (auto i : xrange(isRhythm() ? 6 : 9)) {
1131
		Channel& ch = channels[i];
1132
		if (ch.car.isActive()) {
1133
			// Below we choose between 128 specialized versions of
1134
			// calcChannel(). This allows to move a lot of
1135
			// conditional code out of the inner-loop.
1136
			using enum Slot::EnvelopeState;
1137
			bool carFixedEnv = ch.car.state == one_of(SUSHOLD, FINISH);
1138
			bool modFixedEnv = ch.mod.state == one_of(SUSHOLD, FINISH);
1139
			if (ch.car.state == SETTLE) {
1140
				modFixedEnv = false;
1141
			}
1142
			unsigned flags = ( ch.car.patch.AMPM     << 0) |
1143
			                 ( ch.mod.patch.AMPM     << 2) |
1144
			                 ((ch.mod.patch.FB != 0) << 4) |
1145
			                 ( carFixedEnv           << 5) |
1146
			                 ( modFixedEnv           << 6);
1147
			switch (flags) {
1148
			case   0: calcChannel<  0>(ch, {bufs[i], num}); break;
1149
			case   1: calcChannel<  1>(ch, {bufs[i], num}); break;
1150
			case   2: calcChannel<  2>(ch, {bufs[i], num}); break;
1151
			case   3: calcChannel<  3>(ch, {bufs[i], num}); break;
1152
			case   4: calcChannel<  4>(ch, {bufs[i], num}); break;
1153
			case   5: calcChannel<  5>(ch, {bufs[i], num}); break;
1154
			case   6: calcChannel<  6>(ch, {bufs[i], num}); break;
1155
			case   7: calcChannel<  7>(ch, {bufs[i], num}); break;
1156
			case   8: calcChannel<  8>(ch, {bufs[i], num}); break;
1157
			case   9: calcChannel<  9>(ch, {bufs[i], num}); break;
1158
			case  10: calcChannel< 10>(ch, {bufs[i], num}); break;
1159
			case  11: calcChannel< 11>(ch, {bufs[i], num}); break;
1160
			case  12: calcChannel< 12>(ch, {bufs[i], num}); break;
1161
			case  13: calcChannel< 13>(ch, {bufs[i], num}); break;
1162
			case  14: calcChannel< 14>(ch, {bufs[i], num}); break;
1163
			case  15: calcChannel< 15>(ch, {bufs[i], num}); break;
1164
			case  16: calcChannel< 16>(ch, {bufs[i], num}); break;
1165
			case  17: calcChannel< 17>(ch, {bufs[i], num}); break;
1166
			case  18: calcChannel< 18>(ch, {bufs[i], num}); break;
1167
			case  19: calcChannel< 19>(ch, {bufs[i], num}); break;
1168
			case  20: calcChannel< 20>(ch, {bufs[i], num}); break;
1169
			case  21: calcChannel< 21>(ch, {bufs[i], num}); break;
1170
			case  22: calcChannel< 22>(ch, {bufs[i], num}); break;
1171
			case  23: calcChannel< 23>(ch, {bufs[i], num}); break;
1172
			case  24: calcChannel< 24>(ch, {bufs[i], num}); break;
1173
			case  25: calcChannel< 25>(ch, {bufs[i], num}); break;
1174
			case  26: calcChannel< 26>(ch, {bufs[i], num}); break;
1175
			case  27: calcChannel< 27>(ch, {bufs[i], num}); break;
1176
			case  28: calcChannel< 28>(ch, {bufs[i], num}); break;
1177
			case  29: calcChannel< 29>(ch, {bufs[i], num}); break;
1178
			case  30: calcChannel< 30>(ch, {bufs[i], num}); break;
1179
			case  31: calcChannel< 31>(ch, {bufs[i], num}); break;
1180
			case  32: calcChannel< 32>(ch, {bufs[i], num}); break;
1181
			case  33: calcChannel< 33>(ch, {bufs[i], num}); break;
1182
			case  34: calcChannel< 34>(ch, {bufs[i], num}); break;
1183
			case  35: calcChannel< 35>(ch, {bufs[i], num}); break;
1184
			case  36: calcChannel< 36>(ch, {bufs[i], num}); break;
1185
			case  37: calcChannel< 37>(ch, {bufs[i], num}); break;
1186
			case  38: calcChannel< 38>(ch, {bufs[i], num}); break;
1187
			case  39: calcChannel< 39>(ch, {bufs[i], num}); break;
1188
			case  40: calcChannel< 40>(ch, {bufs[i], num}); break;
1189
			case  41: calcChannel< 41>(ch, {bufs[i], num}); break;
1190
			case  42: calcChannel< 42>(ch, {bufs[i], num}); break;
1191
			case  43: calcChannel< 43>(ch, {bufs[i], num}); break;
1192
			case  44: calcChannel< 44>(ch, {bufs[i], num}); break;
1193
			case  45: calcChannel< 45>(ch, {bufs[i], num}); break;
1194
			case  46: calcChannel< 46>(ch, {bufs[i], num}); break;
1195
			case  47: calcChannel< 47>(ch, {bufs[i], num}); break;
1196
			case  48: calcChannel< 48>(ch, {bufs[i], num}); break;
1197
			case  49: calcChannel< 49>(ch, {bufs[i], num}); break;
1198
			case  50: calcChannel< 50>(ch, {bufs[i], num}); break;
1199
			case  51: calcChannel< 51>(ch, {bufs[i], num}); break;
1200
			case  52: calcChannel< 52>(ch, {bufs[i], num}); break;
1201
			case  53: calcChannel< 53>(ch, {bufs[i], num}); break;
1202
			case  54: calcChannel< 54>(ch, {bufs[i], num}); break;
1203
			case  55: calcChannel< 55>(ch, {bufs[i], num}); break;
1204
			case  56: calcChannel< 56>(ch, {bufs[i], num}); break;
1205
			case  57: calcChannel< 57>(ch, {bufs[i], num}); break;
1206
			case  58: calcChannel< 58>(ch, {bufs[i], num}); break;
1207
			case  59: calcChannel< 59>(ch, {bufs[i], num}); break;
1208
			case  60: calcChannel< 60>(ch, {bufs[i], num}); break;
1209
			case  61: calcChannel< 61>(ch, {bufs[i], num}); break;
1210
			case  62: calcChannel< 62>(ch, {bufs[i], num}); break;
1211
			case  63: calcChannel< 63>(ch, {bufs[i], num}); break;
1212
			case  64: calcChannel< 64>(ch, {bufs[i], num}); break;
1213
			case  65: calcChannel< 65>(ch, {bufs[i], num}); break;
1214
			case  66: calcChannel< 66>(ch, {bufs[i], num}); break;
1215
			case  67: calcChannel< 67>(ch, {bufs[i], num}); break;
1216
			case  68: calcChannel< 68>(ch, {bufs[i], num}); break;
1217
			case  69: calcChannel< 69>(ch, {bufs[i], num}); break;
1218
			case  70: calcChannel< 70>(ch, {bufs[i], num}); break;
1219
			case  71: calcChannel< 71>(ch, {bufs[i], num}); break;
1220
			case  72: calcChannel< 72>(ch, {bufs[i], num}); break;
1221
			case  73: calcChannel< 73>(ch, {bufs[i], num}); break;
1222
			case  74: calcChannel< 74>(ch, {bufs[i], num}); break;
1223
			case  75: calcChannel< 75>(ch, {bufs[i], num}); break;
1224
			case  76: calcChannel< 76>(ch, {bufs[i], num}); break;
1225
			case  77: calcChannel< 77>(ch, {bufs[i], num}); break;
1226
			case  78: calcChannel< 78>(ch, {bufs[i], num}); break;
1227
			case  79: calcChannel< 79>(ch, {bufs[i], num}); break;
1228
			case  80: calcChannel< 80>(ch, {bufs[i], num}); break;
1229
			case  81: calcChannel< 81>(ch, {bufs[i], num}); break;
1230
			case  82: calcChannel< 82>(ch, {bufs[i], num}); break;
1231
			case  83: calcChannel< 83>(ch, {bufs[i], num}); break;
1232
			case  84: calcChannel< 84>(ch, {bufs[i], num}); break;
1233
			case  85: calcChannel< 85>(ch, {bufs[i], num}); break;
1234
			case  86: calcChannel< 86>(ch, {bufs[i], num}); break;
1235
			case  87: calcChannel< 87>(ch, {bufs[i], num}); break;
1236
			case  88: calcChannel< 88>(ch, {bufs[i], num}); break;
1237
			case  89: calcChannel< 89>(ch, {bufs[i], num}); break;
1238
			case  90: calcChannel< 90>(ch, {bufs[i], num}); break;
1239
			case  91: calcChannel< 91>(ch, {bufs[i], num}); break;
1240
			case  92: calcChannel< 92>(ch, {bufs[i], num}); break;
1241
			case  93: calcChannel< 93>(ch, {bufs[i], num}); break;
1242
			case  94: calcChannel< 94>(ch, {bufs[i], num}); break;
1243
			case  95: calcChannel< 95>(ch, {bufs[i], num}); break;
1244
			case  96: calcChannel< 96>(ch, {bufs[i], num}); break;
1245
			case  97: calcChannel< 97>(ch, {bufs[i], num}); break;
1246
			case  98: calcChannel< 98>(ch, {bufs[i], num}); break;
1247
			case  99: calcChannel< 99>(ch, {bufs[i], num}); break;
1248
			case 100: calcChannel<100>(ch, {bufs[i], num}); break;
1249
			case 101: calcChannel<101>(ch, {bufs[i], num}); break;
1250
			case 102: calcChannel<102>(ch, {bufs[i], num}); break;
1251
			case 103: calcChannel<103>(ch, {bufs[i], num}); break;
1252
			case 104: calcChannel<104>(ch, {bufs[i], num}); break;
1253
			case 105: calcChannel<105>(ch, {bufs[i], num}); break;
1254
			case 106: calcChannel<106>(ch, {bufs[i], num}); break;
1255
			case 107: calcChannel<107>(ch, {bufs[i], num}); break;
1256
			case 108: calcChannel<108>(ch, {bufs[i], num}); break;
1257
			case 109: calcChannel<109>(ch, {bufs[i], num}); break;
1258
			case 110: calcChannel<110>(ch, {bufs[i], num}); break;
1259
			case 111: calcChannel<111>(ch, {bufs[i], num}); break;
1260
			case 112: calcChannel<112>(ch, {bufs[i], num}); break;
1261
			case 113: calcChannel<113>(ch, {bufs[i], num}); break;
1262
			case 114: calcChannel<114>(ch, {bufs[i], num}); break;
1263
			case 115: calcChannel<115>(ch, {bufs[i], num}); break;
1264
			case 116: calcChannel<116>(ch, {bufs[i], num}); break;
1265
			case 117: calcChannel<117>(ch, {bufs[i], num}); break;
1266
			case 118: calcChannel<118>(ch, {bufs[i], num}); break;
1267
			case 119: calcChannel<119>(ch, {bufs[i], num}); break;
1268
			case 120: calcChannel<120>(ch, {bufs[i], num}); break;
1269
			case 121: calcChannel<121>(ch, {bufs[i], num}); break;
1270
			case 122: calcChannel<122>(ch, {bufs[i], num}); break;
1271
			case 123: calcChannel<123>(ch, {bufs[i], num}); break;
1272
			case 124: calcChannel<124>(ch, {bufs[i], num}); break;
1273
			case 125: calcChannel<125>(ch, {bufs[i], num}); break;
1274
			case 126: calcChannel<126>(ch, {bufs[i], num}); break;
1275
			case 127: calcChannel<127>(ch, {bufs[i], num}); break;
1276
			default: UNREACHABLE;
1277
			}
1278
		} else {
1279
			bufs[i] = nullptr;
1280
		}
1281
	}
1282
	// update AM, PM unit
1283
	pm_phase += num;
1284
	am_phase = (am_phase + num) % (LFO_AM_TAB_ELEMENTS * 64);
1285
1286
	if (isRhythm()) {
1287
		bufs[6] = nullptr;
1288
		bufs[7] = nullptr;
1289
		bufs[8] = nullptr;
1290
1291
		Channel& ch6 = channels[6];
1292
		Channel& ch7 = channels[7];
1293
		Channel& ch8 = channels[8];
1294
1295
		unsigned old_noise = noise_seed;
1296
		unsigned old_cPhase7 = ch7.mod.cPhase;
1297
		unsigned old_cPhase8 = ch8.car.cPhase;
1298
1299
		if (ch6.car.isActive()) {
1300
			for (auto sample : xrange(num)) {
1301
				bufs[ 9][sample] += narrow_cast<float>(
1302
				    2 * ch6.car.calc_slot_car<false, false>(
1303
				        0, 0, ch6.mod.calc_slot_mod<
1304
				                false, false, false>(0, 0, 0), 0));
1305
			}
1306
		} else {
1307
			bufs[9] = nullptr;
1308
		}
1309
1310
		if (ch7.car.isActive()) {
1311
			for (auto sample : xrange(num)) {
1312
				noise_seed >>= 1;
1313
				bool noise_bit = noise_seed & 1;
1314
				if (noise_bit) noise_seed ^= 0x8003020;
1315
				bufs[10][sample] += narrow_cast<float>(
1316
					-2 * ch7.car.calc_slot_snare(noise_bit));
1317
			}
1318
		} else {
1319
			bufs[10] = nullptr;
1320
		}
1321
1322
		if (ch8.car.isActive()) {
1323
			for (auto sample : xrange(num)) {
1324
				unsigned phase7 = ch7.mod.calc_phase(0);
1325
				unsigned phase8 = ch8.car.calc_phase(0);
1326
				bufs[11][sample] += narrow_cast<float>(
1327
					-2 * ch8.car.calc_slot_cym(phase7, phase8));
1328
			}
1329
		} else {
1330
			bufs[11] = nullptr;
1331
		}
1332
1333
		if (ch7.mod.isActive()) {
1334
			// restore noise, ch7/8 cPhase
1335
			noise_seed = old_noise;
1336
			ch7.mod.cPhase = old_cPhase7;
1337
			ch8.car.cPhase = old_cPhase8;
1338
			for (auto sample : xrange(num)) {
1339
				noise_seed >>= 1;
1340
				bool noise_bit = noise_seed & 1;
1341
				if (noise_bit) noise_seed ^= 0x8003020;
1342
				unsigned phase7 = ch7.mod.calc_phase(0);
1343
				unsigned phase8 = ch8.car.calc_phase(0);
1344
				bufs[12][sample] += narrow_cast<float>(
1345
					2 * ch7.mod.calc_slot_hat(phase7, phase8, noise_bit));
1346
			}
1347
		} else {
1348
			bufs[12] = nullptr;
1349
		}
1350
1351
		if (ch8.mod.isActive()) {
1352
			for (auto sample : xrange(num)) {
1353
				bufs[13][sample] += narrow_cast<float>(
1354
					2 * ch8.mod.calc_slot_tom());
1355
			}
1356
		} else {
1357
			bufs[13] = nullptr;
1358
		}
1359
	} else {
1360
		bufs[ 9] = nullptr;
1361
		bufs[10] = nullptr;
1362
		bufs[11] = nullptr;
1363
		bufs[12] = nullptr;
1364
		bufs[13] = nullptr;
1365
	}
1366
}
1367
1368
void YM2413::writePort(bool port, uint8_t value, int /*offset*/)
1369
{
1370
	if (port == 0) {
1371
		registerLatch = value;
1372
	} else {
1373
		writeReg(registerLatch & 0x3f, value);
1374
	}
1375
}
1376
1377
void YM2413::pokeReg(uint8_t r, uint8_t data)
1378
{
1379
	writeReg(r, data);
1380
}
1381
1382
void YM2413::writeReg(uint8_t r, uint8_t data)
1383
{
1384
	assert(r < 0x40);
1385
1386
	switch (r) {
1387
	using enum Slot::EnvelopeState;
1388
	case 0x00: {
1389
		reg[r] = data;
1390
		patches[0][0].AMPM = (data >> 6) & 3;
1391
		patches[0][0].EG   = (data >> 5) & 1;
1392
		patches[0][0].setKR ((data >> 4) & 1);
1393
		patches[0][0].setML ((data >> 0) & 15);
1394
		for (auto i : xrange(isRhythm() ? 6 : 9)) {
1395
			if ((reg[0x30 + i] & 0xF0) == 0) {
1396
				Channel& ch = channels[i];
1397
				ch.setPatch(0, *this); // TODO optimize
1398
				unsigned freq = getFreq(i);
1399
				ch.mod.updatePG (freq);
1400
				ch.mod.updateRKS(freq);
1401
				ch.mod.updateEG();
1402
			}
1403
		}
1404
		break;
1405
	}
1406
	case 0x01: {
1407
		reg[r] = data;
1408
		patches[0][1].AMPM = (data >> 6) & 3;
1409
		patches[0][1].EG   = (data >> 5) & 1;
1410
		patches[0][1].setKR ((data >> 4) & 1);
1411
		patches[0][1].setML ((data >> 0) & 15);
1412
		for (auto i : xrange(isRhythm() ? 6 : 9)) {
1413
			if ((reg[0x30 + i] & 0xF0) == 0) {
1414
				Channel& ch = channels[i];
1415
				ch.setPatch(0, *this); // TODO optimize
1416
				unsigned freq = getFreq(i);
1417
				ch.car.updatePG (freq);
1418
				ch.car.updateRKS(freq);
1419
				ch.car.updateEG();
1420
			}
1421
		}
1422
		break;
1423
	}
1424
	case 0x02: {
1425
		reg[r] = data;
1426
		patches[0][0].setKL((data >> 6) &  3);
1427
		patches[0][0].setTL((data >> 0) & 63);
1428
		for (auto i : xrange(isRhythm() ? 6 : 9)) {
1429
			if ((reg[0x30 + i] & 0xF0) == 0) {
1430
				Channel& ch = channels[i];
1431
				ch.setPatch(0, *this); // TODO optimize
1432
				bool actAsCarrier = (i >= 7) && isRhythm();
1433
				assert(!actAsCarrier); (void)actAsCarrier;
1434
				ch.mod.updateTLL(getFreq(i), false);
1435
			}
1436
		}
1437
		break;
1438
	}
1439
	case 0x03: {
1440
		reg[r] = data;
1441
		patches[0][1].setKL((data >> 6) & 3);
1442
		patches[0][1].setWF((data >> 4) & 1);
1443
		patches[0][0].setWF((data >> 3) & 1);
1444
		patches[0][0].setFB((data >> 0) & 7);
1445
		for (auto i : xrange(isRhythm() ? 6 : 9)) {
1446
			if ((reg[0x30 + i] & 0xF0) == 0) {
1447
				Channel& ch = channels[i];
1448
				ch.setPatch(0, *this); // TODO optimize
1449
			}
1450
		}
1451
		break;
1452
	}
1453
	case 0x04: {
1454
		reg[r] = data;
1455
		patches[0][0].AR = (data >> 4) & 15;
1456
		patches[0][0].DR = (data >> 0) & 15;
1457
		for (auto i : xrange(isRhythm() ? 6 : 9)) {
1458
			if ((reg[0x30 + i] & 0xF0) == 0) {
1459
				Channel& ch = channels[i];
1460
				ch.setPatch(0, *this); // TODO optimize
1461
				ch.mod.updateEG();
1462
				if (ch.mod.state == ATTACK) {
1463
					ch.mod.setEnvelopeState(ATTACK);
1464
				}
1465
			}
1466
		}
1467
		break;
1468
	}
1469
	case 0x05: {
1470
		reg[r] = data;
1471
		patches[0][1].AR = (data >> 4) & 15;
1472
		patches[0][1].DR = (data >> 0) & 15;
1473
		for (auto i : xrange(isRhythm() ? 6 : 9)) {
1474
			if ((reg[0x30 + i] & 0xF0) == 0) {
1475
				Channel& ch = channels[i];
1476
				ch.setPatch(0, *this); // TODO optimize
1477
				ch.car.updateEG();
1478
				if (ch.car.state == ATTACK) {
1479
					ch.car.setEnvelopeState(ATTACK);
1480
				}
1481
			}
1482
		}
1483
		break;
1484
	}
1485
	case 0x06: {
1486
		reg[r] = data;
1487
		patches[0][0].setSL((data >> 4) & 15);
1488
		patches[0][0].RR  = (data >> 0) & 15;
1489
		for (auto i : xrange(isRhythm() ? 6 : 9)) {
1490
			if ((reg[0x30 + i] & 0xF0) == 0) {
1491
				Channel& ch = channels[i];
1492
				ch.setPatch(0, *this); // TODO optimize
1493
				ch.mod.updateEG();
1494
				if (ch.mod.state == DECAY) {
1495
					ch.mod.setEnvelopeState(DECAY);
1496
				}
1497
			}
1498
		}
1499
		break;
1500
	}
1501
	case 0x07: {
1502
		reg[r] = data;
1503
		patches[0][1].setSL((data >> 4) & 15);
1504
		patches[0][1].RR  = (data >> 0) & 15;
1505
		for (auto i : xrange(isRhythm() ? 6 : 9)) {
1506
			if ((reg[0x30 + i] & 0xF0) == 0) {
1507
				Channel& ch = channels[i];
1508
				ch.setPatch(0, *this); // TODO optimize
1509
				ch.car.updateEG();
1510
				if (ch.car.state == DECAY) {
1511
					ch.car.setEnvelopeState(DECAY);
1512
				}
1513
			}
1514
		}
1515
		break;
1516
	}
1517
	case 0x0E: {
1518
		uint8_t old = reg[r];
1519
		reg[r] = data;
1520
		setRhythmFlags(old);
1521
		break;
1522
	}
1523
	case 0x19: case 0x1A: case 0x1B: case 0x1C:
1524
	case 0x1D: case 0x1E: case 0x1F:
1525
		r -= 9; // verified on real YM2413
1526
		[[fallthrough]];
1527
	case 0x10: case 0x11: case 0x12: case 0x13: case 0x14:
1528
	case 0x15: case 0x16: case 0x17: case 0x18: {
1529
		reg[r] = data;
1530
		unsigned cha = r & 0x0F; assert(cha < 9);
1531
		Channel& ch = channels[cha];
1532
		bool actAsCarrier = (cha >= 7) && isRhythm();
1533
		unsigned freq = getFreq(cha);
1534
		ch.mod.updateAll(freq, actAsCarrier);
1535
		ch.car.updateAll(freq, true);
1536
		break;
1537
	}
1538
	case 0x29: case 0x2A: case 0x2B: case 0x2C:
1539
	case 0x2D: case 0x2E: case 0x2F:
1540
		r -= 9; // verified on real YM2413
1541
		[[fallthrough]];
1542
	case 0x20: case 0x21: case 0x22: case 0x23: case 0x24:
1543
	case 0x25: case 0x26: case 0x27: case 0x28: {
1544
		reg[r] = data;
1545
		unsigned cha = r & 0x0F; assert(cha < 9);
1546
		Channel& ch = channels[cha];
1547
		bool modActAsCarrier = (cha >= 7) && isRhythm();
1548
		ch.setSustain((data >> 5) & 1, modActAsCarrier);
1549
		if (data & 0x10) {
1550
			ch.keyOn();
1551
		} else {
1552
			ch.keyOff();
1553
		}
1554
		unsigned freq = getFreq(cha);
1555
		ch.mod.updateAll(freq, modActAsCarrier);
1556
		ch.car.updateAll(freq, true);
1557
		break;
1558
	}
1559
	case 0x39: case 0x3A: case 0x3B: case 0x3C:
1560
	case 0x3D: case 0x3E: case 0x3F:
1561
		r -= 9; // verified on real YM2413
1562
		[[fallthrough]];
1563
	case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
1564
	case 0x35: case 0x36: case 0x37: case 0x38: {
1565
		reg[r] = data;
1566
		unsigned cha = r & 0x0F; assert(cha < 9);
1567
		Channel& ch = channels[cha];
1568
		if (isRhythm() && (cha >= 6)) {
1569
			if (cha > 6) {
1570
				// channel 7 or 8 in rythm mode
1571
				ch.mod.setVolume(data >> 4);
1572
			}
1573
		} else {
1574
			ch.setPatch(data >> 4, *this);
1575
		}
1576
		ch.car.setVolume(data & 15);
1577
		bool actAsCarrier = (cha >= 7) && isRhythm();
1578
		unsigned freq = getFreq(cha);
1579
		ch.mod.updateAll(freq, actAsCarrier);
1580
		ch.car.updateAll(freq, true);
1581
		break;
1582
	}
1583
	default:
1584
		break;
1585
	}
1586
}
1587
1588
std::span<const uint8_t, 64> YM2413::peekRegs() const
1589
{
1590
	return reg;
1591
}
1592
1593
} // namespace YM2413Okazaki
1594
1595
static constexpr auto envelopeStateInfo = std::to_array<enum_string<YM2413Okazaki::Slot::EnvelopeState>>({
1596
	{ "ATTACK",  YM2413Okazaki::Slot::EnvelopeState::ATTACK  },
1597
	{ "DECAY",   YM2413Okazaki::Slot::EnvelopeState::DECAY   },
1598
	{ "SUSHOLD", YM2413Okazaki::Slot::EnvelopeState::SUSHOLD },
1599
	{ "SUSTAIN", YM2413Okazaki::Slot::EnvelopeState::SUSTAIN },
1600
	{ "RELEASE", YM2413Okazaki::Slot::EnvelopeState::RELEASE },
1601
	{ "SETTLE",  YM2413Okazaki::Slot::EnvelopeState::SETTLE  },
1602
	{ "FINISH",  YM2413Okazaki::Slot::EnvelopeState::FINISH  },
1603
});
1604
SERIALIZE_ENUM(YM2413Okazaki::Slot::EnvelopeState, envelopeStateInfo);
1605
1606
namespace YM2413Okazaki {
1607
1608
// version 1: initial version
1609
// version 2: don't serialize "type / actAsCarrier" anymore, it's now
1610
//            a calculated value
1611
// version 3: don't serialize slot_on_flag anymore
1612
// version 4: don't serialize volume anymore
1613
template<typename Archive>
1614
void Slot::serialize(Archive& ar, unsigned /*version*/)
1615
{
1616
	ar.serialize("feedback", feedback,
1617
	             "output",   output,
1618
	             "cphase",   cPhase,
1619
	             "state",    state,
1620
	             "eg_phase", eg_phase,
1621
	             "sustain",  sustain);
1622
1623
	// These are restored by calls to
1624
	//  updateAll():         eg_dPhase, dPhaseDRTableRks, tll, dPhase
1625
	//  setEnvelopeState():  eg_phase_max
1626
	//  setPatch():          patch
1627
	//  setVolume():         volume
1628
	//  update_key_status(): slot_on_flag
1629
}
1630
1631
// version 1: initial version
1632
// version 2: removed patch_number, freq
1633
template<typename Archive>
1634
void Channel::serialize(Archive& ar, unsigned /*version*/)
1635
{
1636
	ar.serialize("mod", mod,
1637
	             "car", car);
1638
}
1639
1640
1641
// version 1: initial version
1642
// version 2: 'registers' are moved here (no longer serialized in base class)
1643
// version 3: no longer serialize 'user_patch_mod' and 'user_patch_car'
1644
// version 4: added 'registerLatch'
1645
template<typename Archive>
1646
void YM2413::serialize(Archive& ar, unsigned version)
1647
{
1648
	if (ar.versionBelow(version, 2)) ar.beginTag("YM2413Core");
1649
	ar.serialize("registers", reg);
1650
	if (ar.versionBelow(version, 2)) ar.endTag("YM2413Core");
1651
1652
	// no need to serialize patches[]
1653
	//   patches[0] is restored from registers, the others are read-only
1654
	ar.serialize("channels",   channels,
1655
	             "pm_phase",   pm_phase,
1656
	             "am_phase",   am_phase,
1657
	             "noise_seed", noise_seed);
1658
1659
	if constexpr (Archive::IS_LOADER) {
1660
		patches[0][0].initModulator(subspan<8>(reg));
1661
		patches[0][1].initCarrier  (subspan<8>(reg));
1662
		for (auto [i, ch] : enumerate(channels)) {
1663
			// restore patch
1664
			unsigned p = ((i >= 6) && isRhythm())
1665
			           ? unsigned(16 + (i - 6))
1666
			           : (reg[0x30 + i] >> 4);
1667
			ch.setPatch(p, *this); // before updateAll()
1668
			// restore volume
1669
			ch.car.setVolume(reg[0x30 + i] & 15);
1670
			if (isRhythm() && (i >= 7)) { // ch 7/8 rythm
1671
				ch.mod.setVolume(reg[0x30 + i] >> 4);
1672
			}
1673
			// sync various variables
1674
			bool actAsCarrier = (i >= 7) && isRhythm();
1675
			unsigned freq = getFreq(unsigned(i));
1676
			ch.mod.updateAll(freq, actAsCarrier);
1677
			ch.car.updateAll(freq, true);
1678
			ch.mod.setEnvelopeState(ch.mod.state);
1679
			ch.car.setEnvelopeState(ch.car.state);
1680
		}
1681
		update_key_status();
1682
	}
1683
	if (ar.versionAtLeast(version, 4)) {
1684
		ar.serialize("registerLatch", registerLatch);
1685
	} else {
1686
		// could be restored from MSXMusicBase, worth the effort?
1687
	}
1688
}
1689
1690
} // namespace YM2413Okazaki
1691
1692
using YM2413Okazaki::YM2413;
1693
INSTANTIATE_SERIALIZE_METHODS(YM2413);
1694
REGISTER_POLYMORPHIC_INITIALIZER(YM2413Core, YM2413, "YM2413-Okazaki");
1695
1696
} // namespace openmsx