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 int result = int(x / DB_STEP);
291 assert(0 <= result);
292 assert(result < DB_MUTE);
293 return result;
294}
295static constexpr unsigned DB_NEG(double x)
296{
297 return DBTABLEN + DB_POS(x);
298}
299
300// Note: 'int' instead of 'bool' return value to silence clang-warning:
301// warning: use of bitwise '&' with boolean operands [-Wbitwise-instead-of-logical]
302// note: cast one or both operands to int to silence this warning
303static constexpr /*bool*/ int BIT(unsigned s, unsigned b)
304{
305 return narrow<int>((s >> b) & 1);
306}
307
308//
309// Patch
310//
312 : WF(waveform[0]), KL(tllTab[0])
313{
314 setKR(0);
315 setML(0);
316 setTL(0);
317 setFB(0);
318 setSL(0);
319}
320
321void Patch::initModulator(std::span<const uint8_t, 8> data)
322{
323 AMPM = (data[0] >> 6) & 3;
324 EG = (data[0] >> 5) & 1;
325 setKR ((data[0] >> 4) & 1);
326 setML ((data[0] >> 0) & 15);
327 setKL ((data[2] >> 6) & 3);
328 setTL ((data[2] >> 0) & 63);
329 setWF ((data[3] >> 3) & 1);
330 setFB ((data[3] >> 0) & 7);
331 AR = (data[4] >> 4) & 15;
332 DR = (data[4] >> 0) & 15;
333 setSL ((data[6] >> 4) & 15);
334 RR = (data[6] >> 0) & 15;
335}
336
337void Patch::initCarrier(std::span<const uint8_t, 8> data)
338{
339 AMPM = (data[1] >> 6) & 3;
340 EG = (data[1] >> 5) & 1;
341 setKR ((data[1] >> 4) & 1);
342 setML ((data[1] >> 0) & 15);
343 setKL ((data[3] >> 6) & 3);
344 setTL (0);
345 setWF ((data[3] >> 4) & 1);
346 setFB (0);
347 AR = (data[5] >> 4) & 15;
348 DR = (data[5] >> 0) & 15;
349 setSL ((data[7] >> 4) & 15);
350 RR = (data[7] >> 0) & 15;
351}
352
353void Patch::setKR(uint8_t value)
354{
355 KR = value ? 8 : 10;
356}
357void Patch::setML(uint8_t value)
358{
359 ML = mlTable[value];
360}
361void Patch::setKL(uint8_t value)
362{
363 KL = tllTab[value];
364}
365void Patch::setTL(uint8_t value)
366{
367 assert(value < 64);
368 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
536{
539}
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 break;
929 }
930}
931template<bool HAS_AM, bool FIXED_ENV>
932ALWAYS_INLINE unsigned Slot::calc_envelope(int lfo_am, unsigned fixed_env)
933{
934 assert(!FIXED_ENV || (state == one_of(SUSHOLD, FINISH)));
935
936 if constexpr (FIXED_ENV) {
937 unsigned out = fixed_env;
938 if constexpr (HAS_AM) {
939 out += lfo_am; // [0, 768)
940 out |= 3;
941 } else {
942 // out |= 3 is already done in calc_fixed_env()
943 }
944 return out;
945 } else {
946 unsigned out = eg_phase.toInt(); // in range [0, 128]
947 if (state == ATTACK) {
948 out = arAdjustTab[out]; // [0, 128]
949 }
951 if (eg_phase >= eg_phase_max) {
953 }
954 out = EG2DB(out + tll); // [0, 732]
955 if constexpr (HAS_AM) {
956 out += lfo_am; // [0, 758]
957 }
958 return out | 3;
959 }
960}
961template<bool HAS_AM> unsigned Slot::calc_fixed_env() const
962{
963 assert(state == one_of(SUSHOLD, FINISH));
964 assert(eg_dPhase == EnvPhaseIndex(0));
965 unsigned out = eg_phase.toInt(); // in range [0, 128)
966 out = EG2DB(out + tll); // [0, 480)
967 if constexpr (!HAS_AM) {
968 out |= 3;
969 }
970 return out;
971}
972
973// CARRIER
974template<bool HAS_AM, bool FIXED_ENV>
975ALWAYS_INLINE int Slot::calc_slot_car(unsigned lfo_pm, int lfo_am, int fm, unsigned fixed_env)
976{
977 int phase = narrow<int>(calc_phase(lfo_pm)) + wave2_8pi(fm);
978 unsigned egOut = calc_envelope<HAS_AM, FIXED_ENV>(lfo_am, fixed_env);
979 int newOutput = dB2LinTab[patch.WF[phase & PG_MASK] + egOut];
980 output = (output + newOutput) >> 1;
981 return output;
982}
983
984// MODULATOR
985template<bool HAS_AM, bool HAS_FB, bool FIXED_ENV>
986ALWAYS_INLINE int Slot::calc_slot_mod(unsigned lfo_pm, int lfo_am, unsigned fixed_env)
987{
988 assert((patch.FB != 0) == HAS_FB);
989 unsigned phase = calc_phase(lfo_pm);
990 unsigned egOut = calc_envelope<HAS_AM, FIXED_ENV>(lfo_am, fixed_env);
991 if constexpr (HAS_FB) {
992 phase += wave2_8pi(feedback) >> patch.FB;
993 }
994 int newOutput = dB2LinTab[patch.WF[phase & PG_MASK] + egOut];
995 feedback = (output + newOutput) >> 1;
996 output = newOutput;
997 return feedback;
998}
999
1000// TOM (ch8 mod)
1002{
1003 unsigned phase = calc_phase(0);
1004 unsigned egOut = calc_envelope<false, false>(0, 0);
1005 return dB2LinTab[patch.WF[phase & PG_MASK] + egOut];
1006}
1007
1008// SNARE (ch7 car)
1010{
1011 unsigned phase = calc_phase(0);
1012 unsigned egOut = calc_envelope<false, false>(0, 0);
1013 return BIT(phase, 7)
1014 ? dB2LinTab[(noise ? DB_POS(0.0) : DB_POS(15.0)) + egOut]
1015 : dB2LinTab[(noise ? DB_NEG(0.0) : DB_NEG(15.0)) + egOut];
1016}
1017
1018// TOP-CYM (ch8 car)
1019ALWAYS_INLINE int Slot::calc_slot_cym(unsigned phase7, unsigned phase8)
1020{
1021 unsigned egOut = calc_envelope<false, false>(0, 0);
1022 unsigned dbOut = (((BIT(phase7, PG_BITS - 8) ^
1023 BIT(phase7, PG_BITS - 1)) |
1024 BIT(phase7, PG_BITS - 7)) ^
1025 ( BIT(phase8, PG_BITS - 7) &
1026 !BIT(phase8, PG_BITS - 5)))
1027 ? DB_NEG(3.0)
1028 : DB_POS(3.0);
1029 return dB2LinTab[dbOut + egOut];
1030}
1031
1032// HI-HAT (ch7 mod)
1033ALWAYS_INLINE int Slot::calc_slot_hat(unsigned phase7, unsigned phase8, bool noise)
1034{
1035 unsigned egOut = calc_envelope<false, false>(0, 0);
1036 unsigned dbOut = (((BIT(phase7, PG_BITS - 8) ^
1037 BIT(phase7, PG_BITS - 1)) |
1038 BIT(phase7, PG_BITS - 7)) ^
1039 ( BIT(phase8, PG_BITS - 7) &
1040 !BIT(phase8, PG_BITS - 5)))
1041 ? (noise ? DB_NEG(12.0) : DB_NEG(24.0))
1042 : (noise ? DB_POS(12.0) : DB_POS(24.0));
1043 return dB2LinTab[dbOut + egOut];
1044}
1045
1047{
1048 return 1.0f / (1 << DB2LIN_AMP_BITS);
1049}
1050
1051bool YM2413::isRhythm() const
1052{
1053 return (reg[0x0E] & 0x20) != 0;
1054}
1055
1056unsigned YM2413::getFreq(unsigned channel) const
1057{
1058 // combined fnum (=9bit) and block (=3bit)
1059 assert(channel < 9);
1060 return reg[0x10 + channel] | ((reg[0x20 + channel] & 0x0F) << 8);
1061}
1062
1063Patch& YM2413::getPatch(unsigned instrument, bool carrier)
1064{
1065 return patches[instrument][carrier];
1066}
1067
1068template<unsigned FLAGS>
1069ALWAYS_INLINE void YM2413::calcChannel(Channel& ch, std::span<float> buf)
1070{
1071 // VC++ requires explicit conversion to bool. Compiler bug??
1072 const bool HAS_CAR_PM = (FLAGS & 1) != 0;
1073 const bool HAS_CAR_AM = (FLAGS & 2) != 0;
1074 const bool HAS_MOD_PM = (FLAGS & 4) != 0;
1075 const bool HAS_MOD_AM = (FLAGS & 8) != 0;
1076 const bool HAS_MOD_FB = (FLAGS & 16) != 0;
1077 const bool HAS_CAR_FIXED_ENV = (FLAGS & 32) != 0;
1078 const bool HAS_MOD_FIXED_ENV = (FLAGS & 64) != 0;
1079
1080 assert(((ch.car.patch.AMPM & 1) != 0) == HAS_CAR_PM);
1081 assert(((ch.car.patch.AMPM & 2) != 0) == HAS_CAR_AM);
1082 assert(((ch.mod.patch.AMPM & 1) != 0) == HAS_MOD_PM);
1083 assert(((ch.mod.patch.AMPM & 2) != 0) == HAS_MOD_AM);
1084
1085 unsigned tmp_pm_phase = pm_phase;
1086 unsigned tmp_am_phase = am_phase;
1087 unsigned car_fixed_env = 0; // dummy
1088 unsigned mod_fixed_env = 0; // dummy
1089 if constexpr (HAS_CAR_FIXED_ENV) {
1090 car_fixed_env = ch.car.calc_fixed_env<HAS_CAR_AM>();
1091 }
1092 if constexpr (HAS_MOD_FIXED_ENV) {
1093 mod_fixed_env = ch.mod.calc_fixed_env<HAS_MOD_AM>();
1094 }
1095
1096 for (auto& b : buf) {
1097 unsigned lfo_pm = 0;
1098 if constexpr (HAS_CAR_PM || HAS_MOD_PM) {
1099 // Copied from Burczynski:
1100 // There are only 8 different steps for PM, and each
1101 // step lasts for 1024 samples. This results in a PM
1102 // freq of 6.1Hz (but datasheet says it's 6.4Hz).
1103 ++tmp_pm_phase;
1104 lfo_pm = (tmp_pm_phase >> 10) & 7;
1105 }
1106 int lfo_am = 0; // avoid warning
1107 if constexpr (HAS_CAR_AM || HAS_MOD_AM) {
1108 ++tmp_am_phase;
1109 if (tmp_am_phase == (LFO_AM_TAB_ELEMENTS * 64)) {
1110 tmp_am_phase = 0;
1111 }
1112 lfo_am = lfo_am_table[tmp_am_phase / 64];
1113 }
1114 int fm = ch.mod.calc_slot_mod<HAS_MOD_AM, HAS_MOD_FB, HAS_MOD_FIXED_ENV>(
1115 HAS_MOD_PM ? lfo_pm : 0, lfo_am, mod_fixed_env);
1116 b += narrow_cast<float>(ch.car.calc_slot_car<HAS_CAR_AM, HAS_CAR_FIXED_ENV>(
1117 HAS_CAR_PM ? lfo_pm : 0, lfo_am, fm, car_fixed_env));
1118 }
1119}
1120
1121void YM2413::generateChannels(std::span<float*, 9 + 5> bufs, unsigned num)
1122{
1123 assert(num != 0);
1124
1125 for (auto i : xrange(isRhythm() ? 6 : 9)) {
1126 Channel& ch = channels[i];
1127 if (ch.car.isActive()) {
1128 // Below we choose between 128 specialized versions of
1129 // calcChannel(). This allows to move a lot of
1130 // conditional code out of the inner-loop.
1131 bool carFixedEnv = ch.car.state == one_of(SUSHOLD, FINISH);
1132 bool modFixedEnv = ch.mod.state == one_of(SUSHOLD, FINISH);
1133 if (ch.car.state == SETTLE) {
1134 modFixedEnv = false;
1135 }
1136 unsigned flags = ( ch.car.patch.AMPM << 0) |
1137 ( ch.mod.patch.AMPM << 2) |
1138 ((ch.mod.patch.FB != 0) << 4) |
1139 ( carFixedEnv << 5) |
1140 ( modFixedEnv << 6);
1141 switch (flags) {
1142 case 0: calcChannel< 0>(ch, {bufs[i], num}); break;
1143 case 1: calcChannel< 1>(ch, {bufs[i], num}); break;
1144 case 2: calcChannel< 2>(ch, {bufs[i], num}); break;
1145 case 3: calcChannel< 3>(ch, {bufs[i], num}); break;
1146 case 4: calcChannel< 4>(ch, {bufs[i], num}); break;
1147 case 5: calcChannel< 5>(ch, {bufs[i], num}); break;
1148 case 6: calcChannel< 6>(ch, {bufs[i], num}); break;
1149 case 7: calcChannel< 7>(ch, {bufs[i], num}); break;
1150 case 8: calcChannel< 8>(ch, {bufs[i], num}); break;
1151 case 9: calcChannel< 9>(ch, {bufs[i], num}); break;
1152 case 10: calcChannel< 10>(ch, {bufs[i], num}); break;
1153 case 11: calcChannel< 11>(ch, {bufs[i], num}); break;
1154 case 12: calcChannel< 12>(ch, {bufs[i], num}); break;
1155 case 13: calcChannel< 13>(ch, {bufs[i], num}); break;
1156 case 14: calcChannel< 14>(ch, {bufs[i], num}); break;
1157 case 15: calcChannel< 15>(ch, {bufs[i], num}); break;
1158 case 16: calcChannel< 16>(ch, {bufs[i], num}); break;
1159 case 17: calcChannel< 17>(ch, {bufs[i], num}); break;
1160 case 18: calcChannel< 18>(ch, {bufs[i], num}); break;
1161 case 19: calcChannel< 19>(ch, {bufs[i], num}); break;
1162 case 20: calcChannel< 20>(ch, {bufs[i], num}); break;
1163 case 21: calcChannel< 21>(ch, {bufs[i], num}); break;
1164 case 22: calcChannel< 22>(ch, {bufs[i], num}); break;
1165 case 23: calcChannel< 23>(ch, {bufs[i], num}); break;
1166 case 24: calcChannel< 24>(ch, {bufs[i], num}); break;
1167 case 25: calcChannel< 25>(ch, {bufs[i], num}); break;
1168 case 26: calcChannel< 26>(ch, {bufs[i], num}); break;
1169 case 27: calcChannel< 27>(ch, {bufs[i], num}); break;
1170 case 28: calcChannel< 28>(ch, {bufs[i], num}); break;
1171 case 29: calcChannel< 29>(ch, {bufs[i], num}); break;
1172 case 30: calcChannel< 30>(ch, {bufs[i], num}); break;
1173 case 31: calcChannel< 31>(ch, {bufs[i], num}); break;
1174 case 32: calcChannel< 32>(ch, {bufs[i], num}); break;
1175 case 33: calcChannel< 33>(ch, {bufs[i], num}); break;
1176 case 34: calcChannel< 34>(ch, {bufs[i], num}); break;
1177 case 35: calcChannel< 35>(ch, {bufs[i], num}); break;
1178 case 36: calcChannel< 36>(ch, {bufs[i], num}); break;
1179 case 37: calcChannel< 37>(ch, {bufs[i], num}); break;
1180 case 38: calcChannel< 38>(ch, {bufs[i], num}); break;
1181 case 39: calcChannel< 39>(ch, {bufs[i], num}); break;
1182 case 40: calcChannel< 40>(ch, {bufs[i], num}); break;
1183 case 41: calcChannel< 41>(ch, {bufs[i], num}); break;
1184 case 42: calcChannel< 42>(ch, {bufs[i], num}); break;
1185 case 43: calcChannel< 43>(ch, {bufs[i], num}); break;
1186 case 44: calcChannel< 44>(ch, {bufs[i], num}); break;
1187 case 45: calcChannel< 45>(ch, {bufs[i], num}); break;
1188 case 46: calcChannel< 46>(ch, {bufs[i], num}); break;
1189 case 47: calcChannel< 47>(ch, {bufs[i], num}); break;
1190 case 48: calcChannel< 48>(ch, {bufs[i], num}); break;
1191 case 49: calcChannel< 49>(ch, {bufs[i], num}); break;
1192 case 50: calcChannel< 50>(ch, {bufs[i], num}); break;
1193 case 51: calcChannel< 51>(ch, {bufs[i], num}); break;
1194 case 52: calcChannel< 52>(ch, {bufs[i], num}); break;
1195 case 53: calcChannel< 53>(ch, {bufs[i], num}); break;
1196 case 54: calcChannel< 54>(ch, {bufs[i], num}); break;
1197 case 55: calcChannel< 55>(ch, {bufs[i], num}); break;
1198 case 56: calcChannel< 56>(ch, {bufs[i], num}); break;
1199 case 57: calcChannel< 57>(ch, {bufs[i], num}); break;
1200 case 58: calcChannel< 58>(ch, {bufs[i], num}); break;
1201 case 59: calcChannel< 59>(ch, {bufs[i], num}); break;
1202 case 60: calcChannel< 60>(ch, {bufs[i], num}); break;
1203 case 61: calcChannel< 61>(ch, {bufs[i], num}); break;
1204 case 62: calcChannel< 62>(ch, {bufs[i], num}); break;
1205 case 63: calcChannel< 63>(ch, {bufs[i], num}); break;
1206 case 64: calcChannel< 64>(ch, {bufs[i], num}); break;
1207 case 65: calcChannel< 65>(ch, {bufs[i], num}); break;
1208 case 66: calcChannel< 66>(ch, {bufs[i], num}); break;
1209 case 67: calcChannel< 67>(ch, {bufs[i], num}); break;
1210 case 68: calcChannel< 68>(ch, {bufs[i], num}); break;
1211 case 69: calcChannel< 69>(ch, {bufs[i], num}); break;
1212 case 70: calcChannel< 70>(ch, {bufs[i], num}); break;
1213 case 71: calcChannel< 71>(ch, {bufs[i], num}); break;
1214 case 72: calcChannel< 72>(ch, {bufs[i], num}); break;
1215 case 73: calcChannel< 73>(ch, {bufs[i], num}); break;
1216 case 74: calcChannel< 74>(ch, {bufs[i], num}); break;
1217 case 75: calcChannel< 75>(ch, {bufs[i], num}); break;
1218 case 76: calcChannel< 76>(ch, {bufs[i], num}); break;
1219 case 77: calcChannel< 77>(ch, {bufs[i], num}); break;
1220 case 78: calcChannel< 78>(ch, {bufs[i], num}); break;
1221 case 79: calcChannel< 79>(ch, {bufs[i], num}); break;
1222 case 80: calcChannel< 80>(ch, {bufs[i], num}); break;
1223 case 81: calcChannel< 81>(ch, {bufs[i], num}); break;
1224 case 82: calcChannel< 82>(ch, {bufs[i], num}); break;
1225 case 83: calcChannel< 83>(ch, {bufs[i], num}); break;
1226 case 84: calcChannel< 84>(ch, {bufs[i], num}); break;
1227 case 85: calcChannel< 85>(ch, {bufs[i], num}); break;
1228 case 86: calcChannel< 86>(ch, {bufs[i], num}); break;
1229 case 87: calcChannel< 87>(ch, {bufs[i], num}); break;
1230 case 88: calcChannel< 88>(ch, {bufs[i], num}); break;
1231 case 89: calcChannel< 89>(ch, {bufs[i], num}); break;
1232 case 90: calcChannel< 90>(ch, {bufs[i], num}); break;
1233 case 91: calcChannel< 91>(ch, {bufs[i], num}); break;
1234 case 92: calcChannel< 92>(ch, {bufs[i], num}); break;
1235 case 93: calcChannel< 93>(ch, {bufs[i], num}); break;
1236 case 94: calcChannel< 94>(ch, {bufs[i], num}); break;
1237 case 95: calcChannel< 95>(ch, {bufs[i], num}); break;
1238 case 96: calcChannel< 96>(ch, {bufs[i], num}); break;
1239 case 97: calcChannel< 97>(ch, {bufs[i], num}); break;
1240 case 98: calcChannel< 98>(ch, {bufs[i], num}); break;
1241 case 99: calcChannel< 99>(ch, {bufs[i], num}); break;
1242 case 100: calcChannel<100>(ch, {bufs[i], num}); break;
1243 case 101: calcChannel<101>(ch, {bufs[i], num}); break;
1244 case 102: calcChannel<102>(ch, {bufs[i], num}); break;
1245 case 103: calcChannel<103>(ch, {bufs[i], num}); break;
1246 case 104: calcChannel<104>(ch, {bufs[i], num}); break;
1247 case 105: calcChannel<105>(ch, {bufs[i], num}); break;
1248 case 106: calcChannel<106>(ch, {bufs[i], num}); break;
1249 case 107: calcChannel<107>(ch, {bufs[i], num}); break;
1250 case 108: calcChannel<108>(ch, {bufs[i], num}); break;
1251 case 109: calcChannel<109>(ch, {bufs[i], num}); break;
1252 case 110: calcChannel<110>(ch, {bufs[i], num}); break;
1253 case 111: calcChannel<111>(ch, {bufs[i], num}); break;
1254 case 112: calcChannel<112>(ch, {bufs[i], num}); break;
1255 case 113: calcChannel<113>(ch, {bufs[i], num}); break;
1256 case 114: calcChannel<114>(ch, {bufs[i], num}); break;
1257 case 115: calcChannel<115>(ch, {bufs[i], num}); break;
1258 case 116: calcChannel<116>(ch, {bufs[i], num}); break;
1259 case 117: calcChannel<117>(ch, {bufs[i], num}); break;
1260 case 118: calcChannel<118>(ch, {bufs[i], num}); break;
1261 case 119: calcChannel<119>(ch, {bufs[i], num}); break;
1262 case 120: calcChannel<120>(ch, {bufs[i], num}); break;
1263 case 121: calcChannel<121>(ch, {bufs[i], num}); break;
1264 case 122: calcChannel<122>(ch, {bufs[i], num}); break;
1265 case 123: calcChannel<123>(ch, {bufs[i], num}); break;
1266 case 124: calcChannel<124>(ch, {bufs[i], num}); break;
1267 case 125: calcChannel<125>(ch, {bufs[i], num}); break;
1268 case 126: calcChannel<126>(ch, {bufs[i], num}); break;
1269 case 127: calcChannel<127>(ch, {bufs[i], num}); break;
1270 default: UNREACHABLE;
1271 }
1272 } else {
1273 bufs[i] = nullptr;
1274 }
1275 }
1276 // update AM, PM unit
1277 pm_phase += num;
1278 am_phase = (am_phase + num) % (LFO_AM_TAB_ELEMENTS * 64);
1279
1280 if (isRhythm()) {
1281 bufs[6] = nullptr;
1282 bufs[7] = nullptr;
1283 bufs[8] = nullptr;
1284
1285 Channel& ch6 = channels[6];
1286 Channel& ch7 = channels[7];
1287 Channel& ch8 = channels[8];
1288
1289 unsigned old_noise = noise_seed;
1290 unsigned old_cPhase7 = ch7.mod.cPhase;
1291 unsigned old_cPhase8 = ch8.car.cPhase;
1292
1293 if (ch6.car.isActive()) {
1294 for (auto sample : xrange(num)) {
1295 bufs[ 9][sample] += narrow_cast<float>(
1296 2 * ch6.car.calc_slot_car<false, false>(
1297 0, 0, ch6.mod.calc_slot_mod<
1298 false, false, false>(0, 0, 0), 0));
1299 }
1300 } else {
1301 bufs[9] = nullptr;
1302 }
1303
1304 if (ch7.car.isActive()) {
1305 for (auto sample : xrange(num)) {
1306 noise_seed >>= 1;
1307 bool noise_bit = noise_seed & 1;
1308 if (noise_bit) noise_seed ^= 0x8003020;
1309 bufs[10][sample] += narrow_cast<float>(
1310 -2 * ch7.car.calc_slot_snare(noise_bit));
1311 }
1312 } else {
1313 bufs[10] = nullptr;
1314 }
1315
1316 if (ch8.car.isActive()) {
1317 for (auto sample : xrange(num)) {
1318 unsigned phase7 = ch7.mod.calc_phase(0);
1319 unsigned phase8 = ch8.car.calc_phase(0);
1320 bufs[11][sample] += narrow_cast<float>(
1321 -2 * ch8.car.calc_slot_cym(phase7, phase8));
1322 }
1323 } else {
1324 bufs[11] = nullptr;
1325 }
1326
1327 if (ch7.mod.isActive()) {
1328 // restore noise, ch7/8 cPhase
1329 noise_seed = old_noise;
1330 ch7.mod.cPhase = old_cPhase7;
1331 ch8.car.cPhase = old_cPhase8;
1332 for (auto sample : xrange(num)) {
1333 noise_seed >>= 1;
1334 bool noise_bit = noise_seed & 1;
1335 if (noise_bit) noise_seed ^= 0x8003020;
1336 unsigned phase7 = ch7.mod.calc_phase(0);
1337 unsigned phase8 = ch8.car.calc_phase(0);
1338 bufs[12][sample] += narrow_cast<float>(
1339 2 * ch7.mod.calc_slot_hat(phase7, phase8, noise_bit));
1340 }
1341 } else {
1342 bufs[12] = nullptr;
1343 }
1344
1345 if (ch8.mod.isActive()) {
1346 for (auto sample : xrange(num)) {
1347 bufs[13][sample] += narrow_cast<float>(
1348 2 * ch8.mod.calc_slot_tom());
1349 }
1350 } else {
1351 bufs[13] = nullptr;
1352 }
1353 } else {
1354 bufs[ 9] = nullptr;
1355 bufs[10] = nullptr;
1356 bufs[11] = nullptr;
1357 bufs[12] = nullptr;
1358 bufs[13] = nullptr;
1359 }
1360}
1361
1362void YM2413::writePort(bool port, uint8_t value, int /*offset*/)
1363{
1364 if (port == 0) {
1365 registerLatch = value;
1366 } else {
1367 writeReg(registerLatch & 0x3f, value);
1368 }
1369}
1370
1371void YM2413::pokeReg(uint8_t r, uint8_t data)
1372{
1373 writeReg(r, data);
1374}
1375
1376void YM2413::writeReg(uint8_t r, uint8_t data)
1377{
1378 assert(r < 0x40);
1379
1380 switch (r) {
1381 case 0x00: {
1382 reg[r] = data;
1383 patches[0][0].AMPM = (data >> 6) & 3;
1384 patches[0][0].EG = (data >> 5) & 1;
1385 patches[0][0].setKR ((data >> 4) & 1);
1386 patches[0][0].setML ((data >> 0) & 15);
1387 for (auto i : xrange(isRhythm() ? 6 : 9)) {
1388 if ((reg[0x30 + i] & 0xF0) == 0) {
1389 Channel& ch = channels[i];
1390 ch.setPatch(0, *this); // TODO optimize
1391 unsigned freq = getFreq(i);
1392 ch.mod.updatePG (freq);
1393 ch.mod.updateRKS(freq);
1394 ch.mod.updateEG();
1395 }
1396 }
1397 break;
1398 }
1399 case 0x01: {
1400 reg[r] = data;
1401 patches[0][1].AMPM = (data >> 6) & 3;
1402 patches[0][1].EG = (data >> 5) & 1;
1403 patches[0][1].setKR ((data >> 4) & 1);
1404 patches[0][1].setML ((data >> 0) & 15);
1405 for (auto i : xrange(isRhythm() ? 6 : 9)) {
1406 if ((reg[0x30 + i] & 0xF0) == 0) {
1407 Channel& ch = channels[i];
1408 ch.setPatch(0, *this); // TODO optimize
1409 unsigned freq = getFreq(i);
1410 ch.car.updatePG (freq);
1411 ch.car.updateRKS(freq);
1412 ch.car.updateEG();
1413 }
1414 }
1415 break;
1416 }
1417 case 0x02: {
1418 reg[r] = data;
1419 patches[0][0].setKL((data >> 6) & 3);
1420 patches[0][0].setTL((data >> 0) & 63);
1421 for (auto i : xrange(isRhythm() ? 6 : 9)) {
1422 if ((reg[0x30 + i] & 0xF0) == 0) {
1423 Channel& ch = channels[i];
1424 ch.setPatch(0, *this); // TODO optimize
1425 bool actAsCarrier = (i >= 7) && isRhythm();
1426 assert(!actAsCarrier); (void)actAsCarrier;
1427 ch.mod.updateTLL(getFreq(i), false);
1428 }
1429 }
1430 break;
1431 }
1432 case 0x03: {
1433 reg[r] = data;
1434 patches[0][1].setKL((data >> 6) & 3);
1435 patches[0][1].setWF((data >> 4) & 1);
1436 patches[0][0].setWF((data >> 3) & 1);
1437 patches[0][0].setFB((data >> 0) & 7);
1438 for (auto i : xrange(isRhythm() ? 6 : 9)) {
1439 if ((reg[0x30 + i] & 0xF0) == 0) {
1440 Channel& ch = channels[i];
1441 ch.setPatch(0, *this); // TODO optimize
1442 }
1443 }
1444 break;
1445 }
1446 case 0x04: {
1447 reg[r] = data;
1448 patches[0][0].AR = (data >> 4) & 15;
1449 patches[0][0].DR = (data >> 0) & 15;
1450 for (auto i : xrange(isRhythm() ? 6 : 9)) {
1451 if ((reg[0x30 + i] & 0xF0) == 0) {
1452 Channel& ch = channels[i];
1453 ch.setPatch(0, *this); // TODO optimize
1454 ch.mod.updateEG();
1455 if (ch.mod.state == ATTACK) {
1456 ch.mod.setEnvelopeState(ATTACK);
1457 }
1458 }
1459 }
1460 break;
1461 }
1462 case 0x05: {
1463 reg[r] = data;
1464 patches[0][1].AR = (data >> 4) & 15;
1465 patches[0][1].DR = (data >> 0) & 15;
1466 for (auto i : xrange(isRhythm() ? 6 : 9)) {
1467 if ((reg[0x30 + i] & 0xF0) == 0) {
1468 Channel& ch = channels[i];
1469 ch.setPatch(0, *this); // TODO optimize
1470 ch.car.updateEG();
1471 if (ch.car.state == ATTACK) {
1472 ch.car.setEnvelopeState(ATTACK);
1473 }
1474 }
1475 }
1476 break;
1477 }
1478 case 0x06: {
1479 reg[r] = data;
1480 patches[0][0].setSL((data >> 4) & 15);
1481 patches[0][0].RR = (data >> 0) & 15;
1482 for (auto i : xrange(isRhythm() ? 6 : 9)) {
1483 if ((reg[0x30 + i] & 0xF0) == 0) {
1484 Channel& ch = channels[i];
1485 ch.setPatch(0, *this); // TODO optimize
1486 ch.mod.updateEG();
1487 if (ch.mod.state == DECAY) {
1488 ch.mod.setEnvelopeState(DECAY);
1489 }
1490 }
1491 }
1492 break;
1493 }
1494 case 0x07: {
1495 reg[r] = data;
1496 patches[0][1].setSL((data >> 4) & 15);
1497 patches[0][1].RR = (data >> 0) & 15;
1498 for (auto i : xrange(isRhythm() ? 6 : 9)) {
1499 if ((reg[0x30 + i] & 0xF0) == 0) {
1500 Channel& ch = channels[i];
1501 ch.setPatch(0, *this); // TODO optimize
1502 ch.car.updateEG();
1503 if (ch.car.state == DECAY) {
1504 ch.car.setEnvelopeState(DECAY);
1505 }
1506 }
1507 }
1508 break;
1509 }
1510 case 0x0E: {
1511 uint8_t old = reg[r];
1512 reg[r] = data;
1513 setRhythmFlags(old);
1514 break;
1515 }
1516 case 0x19: case 0x1A: case 0x1B: case 0x1C:
1517 case 0x1D: case 0x1E: case 0x1F:
1518 r -= 9; // verified on real YM2413
1519 [[fallthrough]];
1520 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14:
1521 case 0x15: case 0x16: case 0x17: case 0x18: {
1522 reg[r] = data;
1523 unsigned cha = r & 0x0F; assert(cha < 9);
1524 Channel& ch = channels[cha];
1525 bool actAsCarrier = (cha >= 7) && isRhythm();
1526 unsigned freq = getFreq(cha);
1527 ch.mod.updateAll(freq, actAsCarrier);
1528 ch.car.updateAll(freq, true);
1529 break;
1530 }
1531 case 0x29: case 0x2A: case 0x2B: case 0x2C:
1532 case 0x2D: case 0x2E: case 0x2F:
1533 r -= 9; // verified on real YM2413
1534 [[fallthrough]];
1535 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24:
1536 case 0x25: case 0x26: case 0x27: case 0x28: {
1537 reg[r] = data;
1538 unsigned cha = r & 0x0F; assert(cha < 9);
1539 Channel& ch = channels[cha];
1540 bool modActAsCarrier = (cha >= 7) && isRhythm();
1541 ch.setSustain((data >> 5) & 1, modActAsCarrier);
1542 if (data & 0x10) {
1543 ch.keyOn();
1544 } else {
1545 ch.keyOff();
1546 }
1547 unsigned freq = getFreq(cha);
1548 ch.mod.updateAll(freq, modActAsCarrier);
1549 ch.car.updateAll(freq, true);
1550 break;
1551 }
1552 case 0x39: case 0x3A: case 0x3B: case 0x3C:
1553 case 0x3D: case 0x3E: case 0x3F:
1554 r -= 9; // verified on real YM2413
1555 [[fallthrough]];
1556 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
1557 case 0x35: case 0x36: case 0x37: case 0x38: {
1558 reg[r] = data;
1559 unsigned cha = r & 0x0F; assert(cha < 9);
1560 Channel& ch = channels[cha];
1561 if (isRhythm() && (cha >= 6)) {
1562 if (cha > 6) {
1563 // channel 7 or 8 in rythm mode
1564 ch.mod.setVolume(data >> 4);
1565 }
1566 } else {
1567 ch.setPatch(data >> 4, *this);
1568 }
1569 ch.car.setVolume(data & 15);
1570 bool actAsCarrier = (cha >= 7) && isRhythm();
1571 unsigned freq = getFreq(cha);
1572 ch.mod.updateAll(freq, actAsCarrier);
1573 ch.car.updateAll(freq, true);
1574 break;
1575 }
1576 default:
1577 break;
1578 }
1579}
1580
1581uint8_t YM2413::peekReg(uint8_t r) const
1582{
1583 return reg[r];
1584}
1585
1586} // namespace YM2413Okazaki
1587
1588static constexpr std::initializer_list<enum_string<YM2413Okazaki::EnvelopeState>> envelopeStateInfo = {
1589 { "ATTACK", YM2413Okazaki::ATTACK },
1590 { "DECAY", YM2413Okazaki::DECAY },
1591 { "SUSHOLD", YM2413Okazaki::SUSHOLD },
1592 { "SUSTAIN", YM2413Okazaki::SUSTAIN },
1593 { "RELEASE", YM2413Okazaki::RELEASE },
1594 { "SETTLE", YM2413Okazaki::SETTLE },
1595 { "FINISH", YM2413Okazaki::FINISH }
1596};
1598
1599namespace YM2413Okazaki {
1600
1601// version 1: initial version
1602// version 2: don't serialize "type / actAsCarrier" anymore, it's now
1603// a calculated value
1604// version 3: don't serialize slot_on_flag anymore
1605// version 4: don't serialize volume anymore
1606template<typename Archive>
1607void Slot::serialize(Archive& ar, unsigned /*version*/)
1608{
1609 ar.serialize("feedback", feedback,
1610 "output", output,
1611 "cphase", cPhase,
1612 "state", state,
1613 "eg_phase", eg_phase,
1614 "sustain", sustain);
1615
1616 // These are restored by calls to
1617 // updateAll(): eg_dPhase, dPhaseDRTableRks, tll, dPhase
1618 // setEnvelopeState(): eg_phase_max
1619 // setPatch(): patch
1620 // setVolume(): volume
1621 // update_key_status(): slot_on_flag
1622}
1623
1624// version 1: initial version
1625// version 2: removed patch_number, freq
1626template<typename Archive>
1627void Channel::serialize(Archive& ar, unsigned /*version*/)
1628{
1629 ar.serialize("mod", mod,
1630 "car", car);
1631}
1632
1633
1634// version 1: initial version
1635// version 2: 'registers' are moved here (no longer serialized in base class)
1636// version 3: no longer serialize 'user_patch_mod' and 'user_patch_car'
1637// version 4: added 'registerLatch'
1638template<typename Archive>
1639void YM2413::serialize(Archive& ar, unsigned version)
1640{
1641 if (ar.versionBelow(version, 2)) ar.beginTag("YM2413Core");
1642 ar.serialize("registers", reg);
1643 if (ar.versionBelow(version, 2)) ar.endTag("YM2413Core");
1644
1645 // no need to serialize patches[]
1646 // patches[0] is restored from registers, the others are read-only
1647 ar.serialize("channels", channels,
1648 "pm_phase", pm_phase,
1649 "am_phase", am_phase,
1650 "noise_seed", noise_seed);
1651
1652 if constexpr (Archive::IS_LOADER) {
1653 patches[0][0].initModulator(subspan<8>(reg));
1654 patches[0][1].initCarrier (subspan<8>(reg));
1655 for (auto [i, ch] : enumerate(channels)) {
1656 // restore patch
1657 unsigned p = ((i >= 6) && isRhythm())
1658 ? unsigned(16 + (i - 6))
1659 : (reg[0x30 + i] >> 4);
1660 ch.setPatch(p, *this); // before updateAll()
1661 // restore volume
1662 ch.car.setVolume(reg[0x30 + i] & 15);
1663 if (isRhythm() && (i >= 7)) { // ch 7/8 rythm
1664 ch.mod.setVolume(reg[0x30 + i] >> 4);
1665 }
1666 // sync various variables
1667 bool actAsCarrier = (i >= 7) && isRhythm();
1668 unsigned freq = getFreq(unsigned(i));
1669 ch.mod.updateAll(freq, actAsCarrier);
1670 ch.car.updateAll(freq, true);
1671 ch.mod.setEnvelopeState(ch.mod.state);
1672 ch.car.setEnvelopeState(ch.car.state);
1673 }
1674 update_key_status();
1675 }
1676 if (ar.versionAtLeast(version, 4)) {
1677 ar.serialize("registerLatch", registerLatch);
1678 } else {
1679 // could be restored from MSXMusicBase, worth the effort?
1680 }
1681}
1682
1683} // namespace YM2413Okazaki
1684
1688
1689} // namespace openmsx
TclObject t
Definition: one_of.hh:7
static constexpr FixedPoint create(int value)
Create new fixed point object from given representation.
Definition: FixedPoint.hh: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)
unsigned calc_fixed_env() const
std::span< const int, 16 > dPhaseDRTableRks
int calc_slot_hat(unsigned phase7, unsigned phase8, bool noise)
int calc_slot_cym(unsigned phase7, unsigned phase8)
int calc_slot_car(unsigned lfo_pm, int lfo_am, int fm, unsigned fixed_env)
void updateAll(unsigned freq, bool actAsCarrier)
uint8_t peekReg(uint8_t reg) const override
Read from a YM2413 register (for debug).
void serialize(Archive &ar, unsigned version)
void writePort(bool port, uint8_t value, int offset) override
Write to the YM2413 register/data port.
void generateChannels(std::span< float *, 9+5 > bufs, unsigned num) override
Generate the sound output.
void pokeReg(uint8_t reg, uint8_t data) override
Write to a YM2413 register (for debug).
float getAmplificationFactor() const override
Returns normalization factor.
void reset() override
Reset this YM2413 core.
Patch & getPatch(unsigned instrument, bool carrier)
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
Definition: enumerate.hh:28
#define ALWAYS_INLINE
Definition: inline.hh:16
constexpr double pi
Definition: Math.hh:24
constexpr double e
Definition: Math.hh:21
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:267
constexpr int EP_FP_BITS
FixedPoint< EP_FP_BITS > EnvPhaseIndex
constexpr int PG_WIDTH
This file implemented 3 utility functions:
Definition: Autofire.cc:9
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
constexpr void fill(ForwardRange &&range, const T &value)
Definition: ranges.hh:287
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1021
#define UNREACHABLE
Definition: unreachable.hh:38
constexpr auto xrange(T e)
Definition: xrange.hh:132