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