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