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