openMSX
YM2413Burczynski.cc
Go to the documentation of this file.
1/*
2 *
3 * File: ym2413.c - software implementation of YM2413
4 * FM sound generator type OPLL
5 *
6 * Copyright (C) 2002 Jarek Burczynski
7 *
8 * Version 1.0
9 *
10 *
11 * TODO:
12 * - make sure of the sinus amplitude bits
13 * - make sure of the EG resolution bits (looks like the biggest
14 * modulation index generated by the modulator is 123, 124 = no modulation)
15 * - find proper algorithm for attack phase of EG
16 * - tune up instruments ROM
17 * - support sample replay in test mode (it is NOT as simple as setting bit 0
18 * in register 0x0f and using register 0x10 for sample data).
19 * Which games use this feature ?
20 */
21
22#include "YM2413Burczynski.hh"
23
24#include "Math.hh"
25#include "cstd.hh"
26#include "narrow.hh"
27#include "ranges.hh"
28#include "serialize.hh"
29#include "xrange.hh"
30
31#include <array>
32#include <cstdint>
33#include <iostream>
34#include <utility>
35
36namespace openmsx {
37namespace YM2413Burczynski {
38
39// envelope output entries
40static constexpr int ENV_BITS = 10;
41static constexpr double ENV_STEP = 128.0 / (1 << ENV_BITS);
42
43static constexpr int MAX_ATT_INDEX = (1 << (ENV_BITS - 2)) - 1; // 255
44static constexpr int MIN_ATT_INDEX = 0;
45
46static constexpr int TL_RES_LEN = 256; // 8 bits addressing (real chip)
47
48// key scale level
49// table is 3dB/octave, DV converts this into 6dB/octave
50// 0.1875 is bit 0 weight of the envelope counter (volume) expressed
51// in the 'decibel' scale
52static constexpr int DV(double x) { return narrow_cast<int>(x / 0.1875); }
53static constexpr std::array<int, 8 * 16> ksl_tab =
54{
55 // OCT 0
56 DV( 0.000),DV( 0.000),DV( 0.000),DV( 0.000),
57 DV( 0.000),DV( 0.000),DV( 0.000),DV( 0.000),
58 DV( 0.000),DV( 0.000),DV( 0.000),DV( 0.000),
59 DV( 0.000),DV( 0.000),DV( 0.000),DV( 0.000),
60 // OCT 1
61 DV( 0.000),DV( 0.000),DV( 0.000),DV( 0.000),
62 DV( 0.000),DV( 0.000),DV( 0.000),DV( 0.000),
63 DV( 0.000),DV( 0.750),DV( 1.125),DV( 1.500),
64 DV( 1.875),DV( 2.250),DV( 2.625),DV( 3.000),
65 // OCT 2
66 DV( 0.000),DV( 0.000),DV( 0.000),DV( 0.000),
67 DV( 0.000),DV( 1.125),DV( 1.875),DV( 2.625),
68 DV( 3.000),DV( 3.750),DV( 4.125),DV( 4.500),
69 DV( 4.875),DV( 5.250),DV( 5.625),DV( 6.000),
70 // OCT 3
71 DV( 0.000),DV( 0.000),DV( 0.000),DV( 1.875),
72 DV( 3.000),DV( 4.125),DV( 4.875),DV( 5.625),
73 DV( 6.000),DV( 6.750),DV( 7.125),DV( 7.500),
74 DV( 7.875),DV( 8.250),DV( 8.625),DV( 9.000),
75 // OCT 4
76 DV( 0.000),DV( 0.000),DV( 3.000),DV( 4.875),
77 DV( 6.000),DV( 7.125),DV( 7.875),DV( 8.625),
78 DV( 9.000),DV( 9.750),DV(10.125),DV(10.500),
79 DV(10.875),DV(11.250),DV(11.625),DV(12.000),
80 // OCT 5
81 DV( 0.000),DV( 3.000),DV( 6.000),DV( 7.875),
82 DV( 9.000),DV(10.125),DV(10.875),DV(11.625),
83 DV(12.000),DV(12.750),DV(13.125),DV(13.500),
84 DV(13.875),DV(14.250),DV(14.625),DV(15.000),
85 // OCT 6
86 DV( 0.000),DV( 6.000),DV( 9.000),DV(10.875),
87 DV(12.000),DV(13.125),DV(13.875),DV(14.625),
88 DV(15.000),DV(15.750),DV(16.125),DV(16.500),
89 DV(16.875),DV(17.250),DV(17.625),DV(18.000),
90 // OCT 7
91 DV( 0.000),DV( 9.000),DV(12.000),DV(13.875),
92 DV(15.000),DV(16.125),DV(16.875),DV(17.625),
93 DV(18.000),DV(18.750),DV(19.125),DV(19.500),
94 DV(19.875),DV(20.250),DV(20.625),DV(21.000)
95};
96
97// sustain level table (3dB per step)
98// 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,45 (dB)
99static constexpr int SC(int db) { return int(double(db) / ENV_STEP); }
100static constexpr std::array<int, 16> sl_tab = {
101 SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
102 SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(15)
103};
104
105static constexpr std::array eg_inc =
106{
107 // cycle: 0 1 2 3 4 5 6 7
108 /* 0 */ std::array<uint8_t, 8>{ 0,1, 0,1, 0,1, 0,1, }, // rates 00..12 0 (increment by 0 or 1)
109 /* 1 */ std::array<uint8_t, 8>{ 0,1, 0,1, 1,1, 0,1, }, // rates 00..12 1
110 /* 2 */ std::array<uint8_t, 8>{ 0,1, 1,1, 0,1, 1,1, }, // rates 00..12 2
111 /* 3 */ std::array<uint8_t, 8>{ 0,1, 1,1, 1,1, 1,1, }, // rates 00..12 3
112
113 /* 4 */ std::array<uint8_t, 8>{ 1,1, 1,1, 1,1, 1,1, }, // rate 13 0 (increment by 1)
114 /* 5 */ std::array<uint8_t, 8>{ 1,1, 1,2, 1,1, 1,2, }, // rate 13 1
115 /* 6 */ std::array<uint8_t, 8>{ 1,2, 1,2, 1,2, 1,2, }, // rate 13 2
116 /* 7 */ std::array<uint8_t, 8>{ 1,2, 2,2, 1,2, 2,2, }, // rate 13 3
117
118 /* 8 */ std::array<uint8_t, 8>{ 2,2, 2,2, 2,2, 2,2, }, // rate 14 0 (increment by 2)
119 /* 9 */ std::array<uint8_t, 8>{ 2,2, 2,4, 2,2, 2,4, }, // rate 14 1
120 /*10 */ std::array<uint8_t, 8>{ 2,4, 2,4, 2,4, 2,4, }, // rate 14 2
121 /*11 */ std::array<uint8_t, 8>{ 2,4, 4,4, 2,4, 4,4, }, // rate 14 3
122
123 /*12 */ std::array<uint8_t, 8>{ 4,4, 4,4, 4,4, 4,4, }, // rates 15 0, 15 1, 15 2, 15 3 (incr by 4)
124 /*13 */ std::array<uint8_t, 8>{ 8,8, 8,8, 8,8, 8,8, }, // rates 15 2, 15 3 for attack
125 /*14 */ std::array<uint8_t, 8>{ 0,0, 0,0, 0,0, 0,0, }, // infinity rates for attack and decay(s)
126};
127
128// note that there is no value 13 in this table - it's directly in the code
129static constexpr std::array<uint8_t, 16 + 64 + 16> eg_rate_select =
130{
131 // Envelope Generator rates (16 + 64 rates + 16 RKS)
132 // 16 infinite time rates
133 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
134
135 // rates 00-12
136 0, 1, 2, 3,
137 0, 1, 2, 3,
138 0, 1, 2, 3,
139 0, 1, 2, 3,
140 0, 1, 2, 3,
141 0, 1, 2, 3,
142 0, 1, 2, 3,
143 0, 1, 2, 3,
144 0, 1, 2, 3,
145 0, 1, 2, 3,
146 0, 1, 2, 3,
147 0, 1, 2, 3,
148 0, 1, 2, 3,
149
150 // rate 13
151 4, 5, 6, 7,
152
153 // rate 14
154 8, 9,10,11,
155
156 // rate 15
157 12,12,12,12,
158
159 // 16 dummy rates (same as 15 3)
160 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
161};
162
163// rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
164// shift 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0
165// mask 8191, 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0
166
167static constexpr std::array<uint8_t, 16 + 64 + 16> eg_rate_shift =
168{
169 // Envelope Generator counter shifts (16 + 64 rates + 16 RKS)
170 // 16 infinite time rates
171 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
172
173 // rates 00-12
174 13,13,13,13,
175 12,12,12,12,
176 11,11,11,11,
177 10,10,10,10,
178 9, 9, 9, 9,
179 8, 8, 8, 8,
180 7, 7, 7, 7,
181 6, 6, 6, 6,
182 5, 5, 5, 5,
183 4, 4, 4, 4,
184 3, 3, 3, 3,
185 2, 2, 2, 2,
186 1, 1, 1, 1,
187
188 // rate 13
189 0, 0, 0, 0,
190
191 // rate 14
192 0, 0, 0, 0,
193
194 // rate 15
195 0, 0, 0, 0,
196
197 // 16 dummy rates (same as 15 3)
198 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
199};
200
201// multiple table
202static constexpr uint8_t ML(double x) { return uint8_t(2 * x); }
203static constexpr std::array<uint8_t, 16> mul_tab =
204{
205 ML( 0.50), ML( 1.00), ML( 2.00), ML( 3.00),
206 ML( 4.00), ML( 5.00), ML( 6.00), ML( 7.00),
207 ML( 8.00), ML( 9.00), ML(10.00), ML(10.00),
208 ML(12.00), ML(12.00), ML(15.00), ML(15.00),
209};
210
211// TL_TAB_LEN is calculated as:
212// 11 - sinus amplitude bits (Y axis)
213// 2 - sinus sign bit (Y axis)
214// TL_RES_LEN - sinus resolution (X axis)
215static constexpr int TL_TAB_LEN = 11 * 2 * TL_RES_LEN;
216static constexpr auto tlTab = [] {
217 std::array<int, TL_TAB_LEN> result = {};
218 for (auto x : xrange(TL_RES_LEN)) {
219 double m = (1 << 16) / cstd::exp2<6>((x + 1) * (ENV_STEP / 4.0) / 8.0);
220
221 // we never reach (1 << 16) here due to the (x + 1)
222 // result fits within 16 bits at maximum
223 auto n = int(m); // 16 bits here
224 n >>= 4; // 12 bits here
225 n = (n >> 1) + (n & 1); // round to nearest
226 // 11 bits here (rounded)
227 for (auto i : xrange(11)) {
228 result[x * 2 + 0 + i * 2 * TL_RES_LEN] = n >> i;
229 result[x * 2 + 1 + i * 2 * TL_RES_LEN] = -(n >> i);
230 }
231 }
232 return result;
233}();
234
235// sin waveform table in 'decibel' scale
236// two waveforms on OPLL type chips
237static constexpr auto sinTab = [] {
238 std::array<std::array<unsigned, SIN_LEN>, 2> result = {};
239 for (auto i : xrange(SIN_LEN / 4)) {
240 // checked on real hardware, see also
241 // http://docs.google.com/Doc?id=dd8kqn9f_13cqjkf4gp
242 double m = cstd::sin<2>(narrow_cast<double>((i * 2) + 1) * Math::pi / SIN_LEN);
243 auto n = int(cstd::round(cstd::log2<8, 3>(m) * -256.0));
244 result[0][i] = 2 * n;
245 }
246 for (auto i : xrange(SIN_LEN / 4)) {
247 result[0][SIN_LEN / 4 + i] = result[0][SIN_LEN / 4 - 1 - i];
248 }
249 for (auto i : xrange(SIN_LEN / 2)) {
250 result[0][SIN_LEN / 2 + i] = result[0][i] | 1;
251 }
252 for (auto i : xrange(SIN_LEN / 2)) {
253 result[1][i] = result[0][i];
254 }
255 for (auto i : xrange(SIN_LEN / 2)) {
256 result[1][i + SIN_LEN / 2] = TL_TAB_LEN;
257 }
258 return result;
259}();
260
261// LFO Amplitude Modulation table (verified on real YM3812)
262// 27 output levels (triangle waveform);
263// 1 level takes one of: 192, 256 or 448 samples
264//
265// Length: 210 elements.
266//
267// Each of the elements has to be repeated
268// exactly 64 times (on 64 consecutive samples).
269// The whole table takes: 64 * 210 = 13440 samples.
270//
271// We use data>>1, until we find what it really is on real chip...
272
273static constexpr int LFO_AM_TAB_ELEMENTS = 210;
274static constexpr std::array<uint8_t, LFO_AM_TAB_ELEMENTS> lfo_am_table =
275{
276 0,0,0,0,0,0,0,
277 1,1,1,1,
278 2,2,2,2,
279 3,3,3,3,
280 4,4,4,4,
281 5,5,5,5,
282 6,6,6,6,
283 7,7,7,7,
284 8,8,8,8,
285 9,9,9,9,
286 10,10,10,10,
287 11,11,11,11,
288 12,12,12,12,
289 13,13,13,13,
290 14,14,14,14,
291 15,15,15,15,
292 16,16,16,16,
293 17,17,17,17,
294 18,18,18,18,
295 19,19,19,19,
296 20,20,20,20,
297 21,21,21,21,
298 22,22,22,22,
299 23,23,23,23,
300 24,24,24,24,
301 25,25,25,25,
302 26,26,26,
303 25,25,25,25,
304 24,24,24,24,
305 23,23,23,23,
306 22,22,22,22,
307 21,21,21,21,
308 20,20,20,20,
309 19,19,19,19,
310 18,18,18,18,
311 17,17,17,17,
312 16,16,16,16,
313 15,15,15,15,
314 14,14,14,14,
315 13,13,13,13,
316 12,12,12,12,
317 11,11,11,11,
318 10,10,10,10,
319 9,9,9,9,
320 8,8,8,8,
321 7,7,7,7,
322 6,6,6,6,
323 5,5,5,5,
324 4,4,4,4,
325 3,3,3,3,
326 2,2,2,2,
327 1,1,1,1
328};
329
330// LFO Phase Modulation table (verified on real YM2413)
331static constexpr std::array lfo_pm_table =
332{
333 // FNUM2/FNUM = 0 00xxxxxx (0x0000)
334 std::array<int8_t, 8>{ 0, 0, 0, 0, 0, 0, 0, 0, },
335
336 // FNUM2/FNUM = 0 01xxxxxx (0x0040)
337 std::array<int8_t, 8>{ 1, 0, 0, 0,-1, 0, 0, 0, },
338
339 // FNUM2/FNUM = 0 10xxxxxx (0x0080)
340 std::array<int8_t, 8>{ 2, 1, 0,-1,-2,-1, 0, 1, },
341
342 // FNUM2/FNUM = 0 11xxxxxx (0x00C0)
343 std::array<int8_t, 8>{ 3, 1, 0,-1,-3,-1, 0, 1, },
344
345 // FNUM2/FNUM = 1 00xxxxxx (0x0100)
346 std::array<int8_t, 8>{ 4, 2, 0,-2,-4,-2, 0, 2, },
347
348 // FNUM2/FNUM = 1 01xxxxxx (0x0140)
349 std::array<int8_t, 8>{ 5, 2, 0,-2,-5,-2, 0, 2, },
350
351 // FNUM2/FNUM = 1 10xxxxxx (0x0180)
352 std::array<int8_t, 8>{ 6, 3, 0,-3,-6,-3, 0, 3, },
353
354 // FNUM2/FNUM = 1 11xxxxxx (0x01C0)
355 std::array<int8_t, 8>{ 7, 3, 0,-3,-7,-3, 0, 3, },
356};
357
358// This is not 100% perfect yet but very close
359//
360// - multi parameters are 100% correct (instruments and drums)
361// - LFO PM and AM enable are 100% correct
362// - waveform DC and DM select are 100% correct
363static constexpr std::array table = {
364 // MULT MULT modTL DcDmFb AR/DR AR/DR SL/RR SL/RR
365 // 0 1 2 3 4 5 6 7
366 std::array<uint8_t, 8>{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user instrument
367 std::array<uint8_t, 8>{ 0x61, 0x61, 0x1e, 0x17, 0xf0, 0x7f, 0x00, 0x17 }, // violin
368 std::array<uint8_t, 8>{ 0x13, 0x41, 0x16, 0x0e, 0xfd, 0xf4, 0x23, 0x23 }, // guitar
369 std::array<uint8_t, 8>{ 0x03, 0x01, 0x9a, 0x04, 0xf3, 0xf3, 0x13, 0xf3 }, // piano
370 std::array<uint8_t, 8>{ 0x11, 0x61, 0x0e, 0x07, 0xfa, 0x64, 0x70, 0x17 }, // flute
371 std::array<uint8_t, 8>{ 0x22, 0x21, 0x1e, 0x06, 0xf0, 0x76, 0x00, 0x28 }, // clarinet
372 std::array<uint8_t, 8>{ 0x21, 0x22, 0x16, 0x05, 0xf0, 0x71, 0x00, 0x18 }, // oboe
373 std::array<uint8_t, 8>{ 0x21, 0x61, 0x1d, 0x07, 0x82, 0x80, 0x17, 0x17 }, // trumpet
374 std::array<uint8_t, 8>{ 0x23, 0x21, 0x2d, 0x16, 0x90, 0x90, 0x00, 0x07 }, // organ
375 std::array<uint8_t, 8>{ 0x21, 0x21, 0x1b, 0x06, 0x64, 0x65, 0x10, 0x17 }, // horn
376 std::array<uint8_t, 8>{ 0x21, 0x21, 0x0b, 0x1a, 0x85, 0xa0, 0x70, 0x07 }, // synthesizer
377 std::array<uint8_t, 8>{ 0x23, 0x01, 0x83, 0x10, 0xff, 0xb4, 0x10, 0xf4 }, // harpsichord
378 std::array<uint8_t, 8>{ 0x97, 0xc1, 0x20, 0x07, 0xff, 0xf4, 0x22, 0x22 }, // vibraphone
379 std::array<uint8_t, 8>{ 0x61, 0x00, 0x0c, 0x05, 0xc2, 0xf6, 0x40, 0x44 }, // synthesizer bass
380 std::array<uint8_t, 8>{ 0x01, 0x01, 0x56, 0x03, 0x94, 0xc2, 0x03, 0x12 }, // acoustic bass
381 std::array<uint8_t, 8>{ 0x21, 0x01, 0x89, 0x03, 0xf1, 0xe4, 0xf0, 0x23 }, // electric guitar
382 // drum instruments definitions
383 // MULTI MULTI modTL xxx AR/DR AR/DR SL/RR SL/RR
384 // 0 1 2 3 4 5 6 7
385 // { 0x07, 0x21, 0x14, 0x00, 0xee, 0xf8, 0xff, 0xf8 },
386 // { 0x01, 0x31, 0x00, 0x00, 0xf8, 0xf7, 0xf8, 0xf7 },
387 // { 0x25, 0x11, 0x00, 0x00, 0xf8, 0xfa, 0xf8, 0x55 }
388 std::array<uint8_t, 8>{ 0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d },// BD(multi verified, modTL verified, mod env - verified(close), carr. env verified)
389 std::array<uint8_t, 8>{ 0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8 },// HH(multi verified), SD(multi not used)
390 std::array<uint8_t, 8>{ 0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55 },// TOM(multi,env verified), TOP CYM(multi verified, env verified)
391};
392
393static constexpr FreqIndex fnumToIncrement(int block_fnum)
394{
395 // OPLL (YM2413) phase increment counter = 18bit
396 // Chip works with 10.10 fixed point, while we use 16.16.
397 const int block = (block_fnum & 0x1C00) >> 10;
398 return FreqIndex(block_fnum & 0x03FF) >> (11 - block);
399}
400
401inline int Slot::calc_envelope(const Channel& channel, unsigned eg_cnt, bool carrier)
402{
403 switch (state) {
404 using enum EnvelopeState;
405 case DUMP:
406 // Dump phase is performed by both operators in each channel.
407 // When CARRIER envelope gets down to zero level, phases in BOTH
408 // operators are reset (at the same time?).
409 // TODO: That sounds logical, but it does not match the implementation.
410 if (!(eg_cnt & eg_mask_dp)) {
411 egOut += eg_sel_dp[(eg_cnt >> eg_sh_dp) & 7];
412 if (egOut >= MAX_ATT_INDEX) {
413 egOut = MAX_ATT_INDEX;
414 setEnvelopeState(ATTACK);
415 phase = FreqIndex(0); // restart Phase Generator
416 }
417 }
418 break;
419
420 case ATTACK:
421 if (!(eg_cnt & eg_mask_ar)) {
422 egOut +=
423 (~egOut * eg_sel_ar[(eg_cnt >> eg_sh_ar) & 7]) >> 2;
424 if (egOut <= MIN_ATT_INDEX) {
425 egOut = MIN_ATT_INDEX;
426 setEnvelopeState(DECAY);
427 }
428 }
429 break;
430
431 case DECAY:
432 if (!(eg_cnt & eg_mask_dr)) {
433 egOut += eg_sel_dr[(eg_cnt >> eg_sh_dr) & 7];
434 if (egOut >= sl) {
435 setEnvelopeState(SUSTAIN);
436 }
437 }
438 break;
439
440 case SUSTAIN:
441 // this is important behaviour:
442 // one can change percussive/non-percussive modes on the fly and
443 // the chip will remain in sustain phase
444 // - verified on real YM3812
445 if (eg_sustain) {
446 // non-percussive mode (sustained tone)
447 // do nothing
448 } else {
449 // percussive mode
450 // during sustain phase chip adds Release Rate (in
451 // percussive mode)
452 if (!(eg_cnt & eg_mask_rr)) {
453 egOut += eg_sel_rr[(eg_cnt >> eg_sh_rr) & 7];
454 if (egOut >= MAX_ATT_INDEX) {
455 egOut = MAX_ATT_INDEX;
456 }
457 }
458 // else do nothing in sustain phase
459 }
460 break;
461
462 case RELEASE:
463 // Exclude modulators in melody channels from performing anything in
464 // this mode.
465 if (carrier) {
466 const bool sustain = !eg_sustain || channel.isSustained();
467 const unsigned mask = sustain ? eg_mask_rs : eg_mask_rr;
468 if (!(eg_cnt & mask)) {
469 const uint8_t shift = sustain ? eg_sh_rs : eg_sh_rr;
470 std::span<const uint8_t, 8> sel = sustain ? eg_sel_rs : eg_sel_rr;
471 egOut += sel[(eg_cnt >> shift) & 7];
472 if (egOut >= MAX_ATT_INDEX) {
473 egOut = MAX_ATT_INDEX;
474 setEnvelopeState(OFF);
475 }
476 }
477 }
478 break;
479
480 case OFF:
481 break;
482 }
483 return egOut;
484}
485
486inline int Slot::calc_phase(const Channel& channel, unsigned lfo_pm)
487{
488 if (vib) {
489 auto lfo_fn_table_index_offset = narrow<int>(lfo_pm_table
490 [(channel.getBlockFNum() & 0x01FF) >> 6][lfo_pm]);
491 phase += fnumToIncrement(
492 channel.getBlockFNum() * 2 + lfo_fn_table_index_offset
493 ) * mul;
494 } else {
495 // LFO phase modulation disabled for this operator
496 phase += freq;
497 }
498 return phase.toInt();
499}
500
501inline void Slot::updateTotalLevel(const Channel& channel)
502{
503 TLL = TL + (channel.getKeyScaleLevelBase() >> ksl);
504}
505
506inline void Slot::updateAttackRate(int kcodeScaled)
507{
508 if ((ar + kcodeScaled) < (16 + 62)) {
509 eg_sh_ar = eg_rate_shift[ar + kcodeScaled];
510 eg_sel_ar = eg_inc[eg_rate_select[ar + kcodeScaled]];
511 } else {
512 eg_sh_ar = 0;
513 eg_sel_ar = eg_inc[13];
514 }
515 eg_mask_ar = (1 << eg_sh_ar) - 1;
516}
517
518inline void Slot::updateDecayRate(int kcodeScaled)
519{
520 eg_sh_dr = eg_rate_shift[dr + kcodeScaled];
521 eg_sel_dr = eg_inc[eg_rate_select[dr + kcodeScaled]];
522 eg_mask_dr = (1 << eg_sh_dr) - 1;
523}
524
525inline void Slot::updateReleaseRate(int kcodeScaled)
526{
527 eg_sh_rr = eg_rate_shift[rr + kcodeScaled];
528 eg_sel_rr = eg_inc[eg_rate_select[rr + kcodeScaled]];
529 eg_mask_rr = (1 << eg_sh_rr) - 1;
530}
531
532inline int Slot::calcOutput(const Channel& channel, unsigned eg_cnt, bool carrier,
533 unsigned lfo_am, int phase2)
534{
535 int egOut2 = calc_envelope(channel, eg_cnt, carrier);
536 auto env = narrow<unsigned>((TLL + egOut2 + (lfo_am & AMmask)) << 5);
537 unsigned p = env + waveTable[phase2 & SIN_MASK];
538 return p < TL_TAB_LEN ? tlTab[p] : 0;
539}
540
541inline int Slot::calc_slot_mod(const Channel& channel, unsigned eg_cnt, bool carrier,
542 unsigned lfo_pm, unsigned lfo_am)
543{
544 // Compute phase.
545 int phase2 = calc_phase(channel, lfo_pm);
546 if (fb_shift) {
547 phase2 += (op1_out[0] + op1_out[1]) >> fb_shift;
548 }
549 // Shift output in 2-place buffer.
550 op1_out[0] = op1_out[1];
551 // Calculate operator output.
552 op1_out[1] = calcOutput(channel, eg_cnt, carrier, lfo_am, phase2);
553 return op1_out[0] << 1;
554}
555
556inline int Channel::calcOutput(unsigned eg_cnt, unsigned lfo_pm, unsigned lfo_am, int fm)
557{
558 int phase = car.calc_phase(*this, lfo_pm) + fm;
559 return car.calcOutput(*this, eg_cnt, true, lfo_am, phase);
560}
561
562
563// Operators used in the rhythm sounds generation process:
564//
565// Envelope Generator:
566//
567// channel operator register number Bass High Snare Tom Top
568// / slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal
569// 6 / 0 12 50 70 90 f0 +
570// 6 / 1 15 53 73 93 f3 +
571// 7 / 0 13 51 71 91 f1 +
572// 7 / 1 16 54 74 94 f4 +
573// 8 / 0 14 52 72 92 f2 +
574// 8 / 1 17 55 75 95 f5 +
575//
576// Phase Generator:
577//
578// channel operator register number Bass High Snare Tom Top
579// / slot number MULTIPLE Drum Hat Drum Tom Cymbal
580// 6 / 0 12 30 +
581// 6 / 1 15 33 +
582// 7 / 0 13 31 + + +
583// 7 / 1 16 34 ----- n o t u s e d -----
584// 8 / 0 14 32 +
585// 8 / 1 17 35 + +
586//
587// channel operator register number Bass High Snare Tom Top
588// number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal
589// 6 12,15 B6 A6 +
590// 7 13,16 B7 A7 + + +
591// 8 14,17 B8 A8 + + +
592
593// Phase generation is based on:
594// HH (13) channel 7->slot 1 combined with channel 8->slot 2
595// (same combination as TOP CYMBAL but different output phases)
596// SD (16) channel 7->slot 1
597// TOM (14) channel 8->slot 1
598// TOP (17) channel 7->slot 1 combined with channel 8->slot 2
599// (same combination as HIGH HAT but different output phases)
600
601static constexpr int genPhaseHighHat(int phaseM7, int phaseC8, int noise_rng)
602{
603 // hi == phase >= 0x200
604 // enable gate based on frequency of operator 2 in channel 8
605 bool hi = [&] {
606 if (phaseC8 & 0x28) {
607 return true;
608 } else {
609 // base frequency derived from operator 1 in channel 7
610 // VC++ requires explicit conversion to bool. Compiler bug??
611 const bool bit7 = (phaseM7 & 0x80) != 0;
612 const bool bit3 = (phaseM7 & 0x08) != 0;
613 const bool bit2 = (phaseM7 & 0x04) != 0;
614 return bool((bit2 ^ bit7) | bit3);
615 }
616 }();
617 if (noise_rng & 1) {
618 return hi ? (0x200 | 0xD0) : (0xD0 >> 2);
619 } else {
620 return hi ? (0x200 | (0xD0 >> 2)) : 0xD0;
621 }
622}
623
624static constexpr int genPhaseSnare(int phaseM7, int noise_rng)
625{
626 // base frequency derived from operator 1 in channel 7
627 // noise bit XOR'es phase by 0x100
628 return ((phaseM7 & 0x100) + 0x100)
629 ^ ((noise_rng & 1) << 8);
630}
631
632static constexpr int genPhaseCymbal(int phaseM7, int phaseC8)
633{
634 // enable gate based on frequency of operator 2 in channel 8
635 if (phaseC8 & 0x28) {
636 return 0x300;
637 } else {
638 // base frequency derived from operator 1 in channel 7
639 // VC++ requires explicit conversion to bool. Compiler bug??
640 const bool bit7 = (phaseM7 & 0x80) != 0;
641 const bool bit3 = (phaseM7 & 0x08) != 0;
642 const bool bit2 = (phaseM7 & 0x04) != 0;
643 return ((bit2 != bit7) || bit3) ? 0x300 : 0x100;
644 }
645}
646
647
649 : waveTable(sinTab[0])
650 , eg_sel_dp(eg_inc[0]), eg_sel_ar(eg_inc[0]), eg_sel_dr(eg_inc[0])
651 , eg_sel_rr(eg_inc[0]), eg_sel_rs(eg_inc[0])
652{
653 setEnvelopeState(EnvelopeState::OFF);
654}
655
657{
658 if (!key) {
659 // do NOT restart Phase Generator (verified on real YM2413)
660 setEnvelopeState(EnvelopeState::DUMP);
661 }
662 key |= std::to_underlying(part);
663}
664
666{
667 if (key) {
668 key &= ~std::to_underlying(part);
669 if (!key && isActive()) {
670 setEnvelopeState(EnvelopeState::RELEASE);
671 }
672 }
673}
674
675void Slot::setKeyOnOff(KeyPart part, bool enabled)
676{
677 if (enabled) {
678 setKeyOn(part);
679 } else {
680 setKeyOff(part);
681 }
682}
683
684bool Slot::isActive() const
685{
686 return state != EnvelopeState::OFF;
687}
688
689void Slot::setEnvelopeState(EnvelopeState state_)
690{
691 state = state_;
692}
693
695{
696 mul = mul_tab[value];
697}
698
699void Slot::setKeyScaleRate(bool value)
700{
701 KSR = value ? 0 : 2;
702}
703
705{
706 eg_sustain = value;
707}
708
709void Slot::setVibrato(bool value)
710{
711 vib = value;
712}
713
715{
716 AMmask = value ? ~0 : 0;
717}
718
719void Slot::setTotalLevel(const Channel& channel, uint8_t value)
720{
721 TL = value << (ENV_BITS - 2 - 7); // 7 bits TL (bit 6 = always 0)
722 updateTotalLevel(channel);
723}
724
725void Slot::setKeyScaleLevel(const Channel& channel, uint8_t value)
726{
727 ksl = value ? (3 - value) : 31;
728 updateTotalLevel(channel);
729}
730
731void Slot::setWaveform(uint8_t value)
732{
733 waveTable = sinTab[value];
734}
735
736void Slot::setFeedbackShift(uint8_t value)
737{
738 fb_shift = value ? 8 - value : 0;
739}
740
741void Slot::setAttackRate(const Channel& channel, uint8_t value)
742{
743 int kcodeScaled = channel.getKeyCode() >> KSR;
744 ar = value ? narrow<uint8_t>(16 + (value << 2)) : 0;
745 updateAttackRate(kcodeScaled);
746}
747
748void Slot::setDecayRate(const Channel& channel, uint8_t value)
749{
750 int kcodeScaled = channel.getKeyCode() >> KSR;
751 dr = value ? narrow<uint8_t>(16 + (value << 2)) : 0;
752 updateDecayRate(kcodeScaled);
753}
754
755void Slot::setReleaseRate(const Channel& channel, uint8_t value)
756{
757 int kcodeScaled = channel.getKeyCode() >> KSR;
758 rr = value ? narrow<uint8_t>(16 + (value << 2)) : 0;
759 updateReleaseRate(kcodeScaled);
760}
761
762void Slot::setSustainLevel(uint8_t value)
763{
764 sl = sl_tab[value];
765}
766
767void Slot::updateFrequency(const Channel& channel)
768{
769 updateTotalLevel(channel);
770 updateGenerators(channel);
771}
772
774{
775 waveTable = sinTab[0];
776 setEnvelopeState(EnvelopeState::OFF);
777 egOut = MAX_ATT_INDEX;
778}
779
780void Slot::updateGenerators(const Channel& channel)
781{
782 // (frequency) phase increment counter
783 freq = channel.getFrequencyIncrement() * mul;
784
785 // calculate envelope generator rates
786 const int kcodeScaled = channel.getKeyCode() >> KSR;
787 updateAttackRate(kcodeScaled);
788 updateDecayRate(kcodeScaled);
789 updateReleaseRate(kcodeScaled);
790
791 const int rs = channel.isSustained() ? 16 + (5 << 2) : 16 + (7 << 2);
792 eg_sh_rs = eg_rate_shift[rs + kcodeScaled];
793 eg_sel_rs = eg_inc[eg_rate_select[rs + kcodeScaled]];
794
795 const int dp = 16 + (13 << 2);
796 eg_sh_dp = eg_rate_shift[dp + kcodeScaled];
797 eg_sel_dp = eg_inc[eg_rate_select[dp + kcodeScaled]];
798
799 eg_mask_rs = (1 << eg_sh_rs) - 1;
800 eg_mask_dp = (1 << eg_sh_dp) - 1;
801}
802
803void Channel::setFrequency(int block_fnum_)
804{
805 if (block_fnum == block_fnum_) return;
806 block_fnum = block_fnum_;
807
808 ksl_base = ksl_tab[block_fnum >> 5];
809 fc = fnumToIncrement(block_fnum * 2);
810
811 // Refresh Total Level and frequency counter in both SLOTs of this channel.
812 mod.updateFrequency(*this);
813 car.updateFrequency(*this);
814}
815
816void Channel::setFrequencyLow(uint8_t value)
817{
818 setFrequency((block_fnum & 0x0F00) | value);
819}
820
821void Channel::setFrequencyHigh(uint8_t value)
822{
823 setFrequency((value << 8) | (block_fnum & 0x00FF));
824}
825
827{
828 return block_fnum;
829}
830
832{
833 return fc;
834}
835
837{
838 return ksl_base;
839}
840
841uint8_t Channel::getKeyCode() const
842{
843 // BLK 2,1,0 bits -> bits 3,2,1 of kcode, FNUM MSB -> kcode LSB
844 return (block_fnum & 0x0F00) >> 8;
845}
846
848{
849 return sus;
850}
851
852void Channel::setSustain(bool sustained)
853{
854 sus = sustained;
855}
856
857void Channel::updateInstrumentPart(int part, uint8_t value)
858{
859 switch (part) {
860 case 0:
861 mod.setFrequencyMultiplier(value & 0x0F);
862 mod.setKeyScaleRate((value & 0x10) != 0);
863 mod.setEnvelopeSustained((value & 0x20) != 0);
864 mod.setVibrato((value & 0x40) != 0);
865 mod.setAmplitudeModulation((value & 0x80) != 0);
866 mod.updateGenerators(*this);
867 break;
868 case 1:
869 car.setFrequencyMultiplier(value & 0x0F);
870 car.setKeyScaleRate((value & 0x10) != 0);
871 car.setEnvelopeSustained((value & 0x20) != 0);
872 car.setVibrato((value & 0x40) != 0);
873 car.setAmplitudeModulation((value & 0x80) != 0);
874 car.updateGenerators(*this);
875 break;
876 case 2:
877 mod.setKeyScaleLevel(*this, value >> 6);
878 mod.setTotalLevel(*this, value & 0x3F);
879 break;
880 case 3:
881 mod.setWaveform((value & 0x08) >> 3);
882 mod.setFeedbackShift(value & 0x07);
883 car.setKeyScaleLevel(*this, value >> 6);
884 car.setWaveform((value & 0x10) >> 4);
885 break;
886 case 4:
887 mod.setAttackRate(*this, value >> 4);
888 mod.setDecayRate(*this, value & 0x0F);
889 break;
890 case 5:
891 car.setAttackRate(*this, value >> 4);
892 car.setDecayRate(*this, value & 0x0F);
893 break;
894 case 6:
895 mod.setSustainLevel(value >> 4);
896 mod.setReleaseRate(*this, value & 0x0F);
897 break;
898 case 7:
899 car.setSustainLevel(value >> 4);
900 car.setReleaseRate(*this, value & 0x0F);
901 break;
902 }
903}
904
905void Channel::updateInstrument(std::span<const uint8_t, 8> inst)
906{
907 for (auto part : xrange(8)) {
908 updateInstrumentPart(part, inst[part]);
909 }
910}
911
913{
914 if (false) {
915 for (const auto& e : tlTab) std::cout << e << '\n';
916 std::cout << '\n';
917 for (const auto& s : sinTab) {
918 for (const auto& e : s) std::cout << e << '\n';
919 }
920 }
921
922 ranges::fill(reg, 0); // avoid UMR
923 eg_cnt = 0;
924 noise_rng = 0;
925
926 reset();
927}
928
929void YM2413::updateCustomInstrument(int part, uint8_t value)
930{
931 // Update instrument definition.
932 inst_tab[0][part] = value;
933
934 // Update every channel that has instrument 0 selected.
935 for (auto ch : xrange(isRhythm() ? 6 : 9)) {
936 Channel& channel = channels[ch];
937 if ((reg[0x30 + ch] & 0xF0) == 0) {
938 channel.updateInstrumentPart(part, value);
939 }
940 }
941}
942
943void YM2413::setRhythmFlags(uint8_t old)
944{
945 Channel& ch6 = channels[6];
946 Channel& ch7 = channels[7];
947 Channel& ch8 = channels[8];
948
949 // flags = X | X | mode | BD | SD | TOM | TC | HH
950 using enum Slot::KeyPart;
951 uint8_t flags = reg[0x0E];
952 if ((flags ^ old) & 0x20) {
953 if (flags & 0x20) { // OFF -> ON
954 // Bass drum.
955 ch6.updateInstrument(inst_tab[16]);
956 // High hat and snare drum.
957 ch7.updateInstrument(inst_tab[17]);
958 ch7.mod.setTotalLevel(ch7, uint8_t((reg[0x37] >> 4) << 2)); // High hat
959 // Tom-tom and top cymbal.
960 ch8.updateInstrument(inst_tab[18]);
961 ch8.mod.setTotalLevel(ch8, uint8_t((reg[0x38] >> 4) << 2)); // Tom-tom
962 } else { // ON -> OFF
963 ch6.updateInstrument(inst_tab[reg[0x36] >> 4]);
964 ch7.updateInstrument(inst_tab[reg[0x37] >> 4]);
965 ch8.updateInstrument(inst_tab[reg[0x38] >> 4]);
966
967 // BD key off
968 ch6.mod.setKeyOff(RHYTHM);
969 ch6.car.setKeyOff(RHYTHM);
970 // HH key off
971 ch7.mod.setKeyOff(RHYTHM);
972 // SD key off
973 ch7.car.setKeyOff(RHYTHM);
974 // TOM key off
975 ch8.mod.setKeyOff(RHYTHM);
976 // TOP-CY off
977 ch8.car.setKeyOff(RHYTHM);
978 }
979 }
980 if (flags & 0x20) {
981 // BD key on/off
982 ch6.mod.setKeyOnOff(RHYTHM, (flags & 0x10) != 0);
983 ch6.car.setKeyOnOff(RHYTHM, (flags & 0x10) != 0);
984 // HH key on/off
985 ch7.mod.setKeyOnOff(RHYTHM, (flags & 0x01) != 0);
986 // SD key on/off
987 ch7.car.setKeyOnOff(RHYTHM, (flags & 0x08) != 0);
988 // TOM key on/off
989 ch8.mod.setKeyOnOff(RHYTHM, (flags & 0x04) != 0);
990 // TOP-CY key on/off
991 ch8.car.setKeyOnOff(RHYTHM, (flags & 0x02) != 0);
992 }
993}
994
996{
997 eg_cnt = 0;
998 noise_rng = 1; // noise shift register
999 idleSamples = 0;
1000
1001 // setup instruments table
1002 inst_tab = table;
1003
1004 // reset with register write
1005 writeReg(0x0F, 0); // test reg
1006 for (uint8_t i = 0x3F; i >= 0x10; --i) {
1007 writeReg(i, 0);
1008 }
1009 registerLatch = 0;
1010
1011 resetOperators();
1012}
1013
1014void YM2413::resetOperators()
1015{
1016 for (auto& ch : channels) {
1017 ch.mod.resetOperators();
1018 ch.car.resetOperators();
1019 }
1020}
1021
1022bool YM2413::isRhythm() const
1023{
1024 return (reg[0x0E] & 0x20) != 0;
1025}
1026
1027Channel& YM2413::getChannelForReg(uint8_t r)
1028{
1029 uint8_t chan = (r & 0x0F) % 9; // verified on real YM2413
1030 return channels[chan];
1031}
1032
1034{
1035 return 1.0f / 2048.0f;
1036}
1037
1038void YM2413::generateChannels(std::span<float*, 9 + 5> bufs, unsigned num)
1039{
1040 // TODO make channelActiveBits a member and
1041 // keep it up-to-date all the time
1042
1043 // bits 0-8 -> ch[0-8].car
1044 // bits 9-17 -> ch[0-8].mod (only ch7 and ch8 used)
1045 unsigned channelActiveBits = 0;
1046
1047 for (auto ch : xrange(isRhythm() ? 6 : 9)) {
1048 if (channels[ch].car.isActive()) {
1049 channelActiveBits |= 1 << ch;
1050 } else {
1051 bufs[ch] = nullptr;
1052 }
1053 }
1054 if (isRhythm()) {
1055 ranges::fill(subspan<3>(bufs, 6), nullptr);
1056 for (auto ch : xrange(6, 9)) {
1057 if (channels[ch].car.isActive()) {
1058 channelActiveBits |= 1 << ch;
1059 } else {
1060 bufs[ch + 3] = nullptr;
1061 }
1062 }
1063 if (channels[7].mod.isActive()) {
1064 channelActiveBits |= 1 << (7 + 9);
1065 } else {
1066 bufs[12] = nullptr;
1067 }
1068 if (channels[8].mod.isActive()) {
1069 channelActiveBits |= 1 << (8 + 9);
1070 } else {
1071 bufs[13] = nullptr;
1072 }
1073 } else {
1074 ranges::fill(subspan<5>(bufs, 9), nullptr);
1075 }
1076
1077 if (channelActiveBits) {
1078 idleSamples = 0;
1079 } else {
1080 if (idleSamples > (CLOCK_FREQ / (72 * 5))) {
1081 // Optimization:
1082 // idle for over 1/5s = 200ms
1083 // we don't care that noise / AM / PM isn't exactly
1084 // in sync with the real HW when music resumes
1085 // Alternative:
1086 // implement an efficient advance(n) method
1087 return;
1088 }
1089 idleSamples += num;
1090 }
1091
1092 for (auto i : xrange(num)) {
1093 // Amplitude modulation: 27 output levels (triangle waveform)
1094 // 1 level takes one of: 192, 256 or 448 samples
1095 // One entry from LFO_AM_TABLE lasts for 64 samples
1096 lfo_am_cnt.addQuantum();
1097 if (lfo_am_cnt == LFOAMIndex(LFO_AM_TAB_ELEMENTS)) {
1098 // lfo_am_table is 210 elements long
1099 lfo_am_cnt = LFOAMIndex(0);
1100 }
1101 unsigned lfo_am = lfo_am_table[lfo_am_cnt.toInt()] >> 1;
1102 unsigned lfo_pm = lfo_pm_cnt.toInt() & 7;
1103
1104 for (auto ch : xrange(isRhythm() ? 6 : 9)) {
1105 Channel& channel = channels[ch];
1106 int fm = channel.mod.calc_slot_mod(channel, eg_cnt, false, lfo_pm, lfo_am);
1107 if ((channelActiveBits >> ch) & 1) {
1108 bufs[ch][i] += narrow_cast<float>(channel.calcOutput(eg_cnt, lfo_pm, lfo_am, fm));
1109 }
1110 }
1111 if (isRhythm()) {
1112 // Bass Drum (verified on real YM3812):
1113 // - depends on the channel 6 'connect' register:
1114 // when connect = 0 it works the same as in normal (non-rhythm) mode
1115 // (op1->op2->out)
1116 // when connect = 1 _only_ operator 2 is present on output (op2->out),
1117 // operator 1 is ignored
1118 // - output sample always is multiplied by 2
1119 Channel& channel6 = channels[6];
1120 int fm = channel6.mod.calc_slot_mod(channels[6], eg_cnt, true, lfo_pm, lfo_am);
1121 if (channelActiveBits & (1 << 6)) {
1122 bufs[ 9][i] += narrow_cast<float>(2 * channel6.calcOutput(eg_cnt, lfo_pm, lfo_am, fm));
1123 }
1124
1125 // TODO: Skip phase generation if output will 0 anyway.
1126 // Possible by passing phase generator as a template parameter to
1127 // calcOutput.
1128
1129 /*C7*/ (void)channels[7].car.calc_phase(channels[7], lfo_pm);
1130 int phaseM7 = channels[7].mod.calc_phase(channels[7], lfo_pm);
1131 int phaseC8 = channels[8].car.calc_phase(channels[8], lfo_pm);
1132 int phaseM8 = channels[8].mod.calc_phase(channels[8], lfo_pm);
1133
1134 // Snare Drum (verified on real YM3812)
1135 if (channelActiveBits & (1 << 7)) {
1136 Slot& SLOT7_2 = channels[7].car;
1137 bufs[10][i] += narrow_cast<float>(2 * SLOT7_2.calcOutput(channels[7], eg_cnt, true, lfo_am, genPhaseSnare(phaseM7, noise_rng)));
1138 }
1139
1140 // Top Cymbal (verified on real YM2413)
1141 if (channelActiveBits & (1 << 8)) {
1142 Slot& SLOT8_2 = channels[8].car;
1143 bufs[11][i] += narrow_cast<float>(2 * SLOT8_2.calcOutput(channels[8], eg_cnt, true, lfo_am, genPhaseCymbal(phaseM7, phaseC8)));
1144 }
1145
1146 // High Hat (verified on real YM3812)
1147 if (channelActiveBits & (1 << (7 + 9))) {
1148 Slot& SLOT7_1 = channels[7].mod;
1149 bufs[12][i] += narrow_cast<float>(2 * SLOT7_1.calcOutput(channels[7], eg_cnt, true, lfo_am, genPhaseHighHat(phaseM7, phaseC8, noise_rng)));
1150 }
1151
1152 // Tom Tom (verified on real YM3812)
1153 if (channelActiveBits & (1 << (8 + 9))) {
1154 Slot& SLOT8_1 = channels[8].mod;
1155 bufs[13][i] += narrow_cast<float>(2 * SLOT8_1.calcOutput(channels[8], eg_cnt, true, lfo_am, phaseM8));
1156 }
1157 }
1158
1159 // Vibrato: 8 output levels (triangle waveform)
1160 // 1 level takes 1024 samples
1161 lfo_pm_cnt.addQuantum();
1162
1163 ++eg_cnt;
1164
1165 // The Noise Generator of the YM3812 is 23-bit shift register.
1166 // Period is equal to 2^23-2 samples.
1167 // Register works at sampling frequency of the chip, so output
1168 // can change on every sample.
1169 //
1170 // Output of the register and input to the bit 22 is:
1171 // bit0 XOR bit14 XOR bit15 XOR bit22
1172 //
1173 // Simply use bit 22 as the noise output.
1174
1175 // int j = ((noise_rng >> 0) ^ (noise_rng >> 14) ^
1176 // (noise_rng >> 15) ^ (noise_rng >> 22)) & 1;
1177 // noise_rng = (j << 22) | (noise_rng >> 1);
1178 //
1179 // Instead of doing all the logic operations above, we
1180 // use a trick here (and use bit 0 as the noise output).
1181 // The difference is only that the noise bit changes one
1182 // step ahead. This doesn't matter since we don't know
1183 // what is real state of the noise_rng after the reset.
1184 if (noise_rng & 1) {
1185 noise_rng ^= 0x800302;
1186 }
1187 noise_rng >>= 1;
1188 }
1189}
1190
1191void YM2413::writePort(bool port, uint8_t value, int /*offset*/)
1192{
1193 if (port == 0) {
1194 registerLatch = value;
1195 } else {
1196 writeReg(registerLatch & 0x3f, value);
1197 }
1198}
1199
1200void YM2413::pokeReg(uint8_t r, uint8_t v)
1201{
1202 writeReg(r, v);
1203}
1204
1205void YM2413::writeReg(uint8_t r, uint8_t v)
1206{
1207 uint8_t old = reg[r];
1208 reg[r] = v;
1209
1210 switch (r & 0xF0) {
1211 case 0x00: { // 00-0F: control
1212 switch (r & 0x0F) {
1213 case 0x00: // AM/VIB/EGTYP/KSR/MULTI (modulator)
1214 case 0x01: // AM/VIB/EGTYP/KSR/MULTI (carrier)
1215 case 0x02: // Key Scale Level, Total Level (modulator)
1216 case 0x03: // Key Scale Level, carrier waveform, modulator waveform,
1217 // Feedback
1218 case 0x04: // Attack, Decay (modulator)
1219 case 0x05: // Attack, Decay (carrier)
1220 case 0x06: // Sustain, Release (modulator)
1221 case 0x07: // Sustain, Release (carrier)
1222 updateCustomInstrument(r, v);
1223 break;
1224 case 0x0E:
1225 setRhythmFlags(old);
1226 break;
1227 }
1228 break;
1229 }
1230 case 0x10: {
1231 // 10-18: FNUM 0-7
1232 Channel& ch = getChannelForReg(r);
1233 ch.setFrequencyLow(v);
1234 break;
1235 }
1236 case 0x20: {
1237 // 20-28: susOn, keyOn, block, FNUM 8
1238 Channel& ch = getChannelForReg(r);
1239 ch.mod.setKeyOnOff(Slot::KeyPart::MAIN, (v & 0x10) != 0);
1240 ch.car.setKeyOnOff(Slot::KeyPart::MAIN, (v & 0x10) != 0);
1241 ch.setSustain((v & 0x20) != 0);
1242 // Note: When changing the frequency, a new value for RS is
1243 // computed using the sustain value, so make sure the new
1244 // sustain value is committed first.
1245 ch.setFrequencyHigh(v & 0x0F);
1246 break;
1247 }
1248 case 0x30: { // inst 4 MSBs, VOL 4 LSBs
1249 Channel& ch = getChannelForReg(r);
1250 ch.car.setTotalLevel(ch, uint8_t((v & 0x0F) << 2));
1251
1252 // Check wether we are in rhythm mode and handle instrument/volume
1253 // register accordingly.
1254
1255 uint8_t chan = (r & 0x0F) % 9; // verified on real YM2413
1256 if (isRhythm() && (chan >= 6)) {
1257 if (chan > 6) {
1258 // channel 7 or 8 in rythm mode
1259 // modulator envelope is HH(chan=7) or TOM(chan=8).
1260 ch.mod.setTotalLevel(ch, uint8_t((v >> 4) << 2));
1261 }
1262 } else {
1263 if ((old & 0xF0) != (v & 0xF0)) {
1264 ch.updateInstrument(inst_tab[v >> 4]);
1265 }
1266 }
1267 break;
1268 }
1269 default:
1270 break;
1271 }
1272}
1273
1274uint8_t YM2413::peekReg(uint8_t r) const
1275{
1276 return reg[r];
1277}
1278
1279} // namespace YM2413Burczynski
1280
1281static constexpr std::initializer_list<enum_string<YM2413Burczynski::Slot::EnvelopeState>> envelopeStateInfo = {
1288};
1290
1291namespace YM2413Burczynski {
1292
1293// version 1: initial version
1294// version 2: - removed kcodeScaled
1295// - calculated more members from other state
1296// (TLL, freq, eg_sel_*, eg_sh_*)
1297template<typename Archive>
1298void Slot::serialize(Archive& a, unsigned /*version*/)
1299{
1300 // TODO some of the serialized members here could be calculated from
1301 // other members
1302 uint8_t waveform = (waveTable.data() == sinTab[0].data()) ? 0 : 1;
1303 a.serialize("waveform", waveform);
1304 if constexpr (Archive::IS_LOADER) {
1305 setWaveform(waveform);
1306 }
1307
1308 a.serialize("phase", phase,
1309 "TL", TL,
1310 "volume", egOut,
1311 "sl", sl,
1312 "state", state,
1313 "op1_out", op1_out,
1314 "eg_sustain", eg_sustain,
1315 "fb_shift", fb_shift,
1316 "key", key,
1317 "ar", ar,
1318 "dr", dr,
1319 "rr", rr,
1320 "KSR", KSR,
1321 "ksl", ksl,
1322 "mul", mul,
1323 "AMmask", AMmask,
1324 "vib", vib);
1325
1326 // These are calculated by updateTotalLevel()
1327 // TLL
1328 // These are calculated by updateGenerators()
1329 // freq, eg_sh_ar, eg_sel_ar, eg_sh_dr, eg_sel_dr, eg_sh_rr, eg_sel_rr
1330 // eg_sh_rs, eg_sel_rs, eg_sh_dp, eg_sel_dp
1331}
1332
1333// version 1: original version
1334// version 2: removed kcode
1335// version 3: removed instvol_r
1336template<typename Archive>
1337void Channel::serialize(Archive& a, unsigned /*version*/)
1338{
1339 // mod/car were originally an array, keep serializing as such for bwc
1340 std::array<Slot, 2> slots = {mod, car};
1341 a.serialize("slots", slots);
1342 if constexpr (Archive::IS_LOADER) {
1343 mod = slots[0];
1344 car = slots[1];
1345 }
1346
1347 a.serialize("block_fnum", block_fnum,
1348 "fc", fc,
1349 "ksl_base", ksl_base,
1350 "sus", sus);
1351
1352 if constexpr (Archive::IS_LOADER) {
1353 mod.updateFrequency(*this);
1354 car.updateFrequency(*this);
1355 }
1356}
1357
1358// version 1: initial version
1359// version 2: 'registers' are moved here (no longer serialized in base class)
1360// version 3: removed 'rhythm' variable
1361// version 4: added 'registerLatch'
1362template<typename Archive>
1363void YM2413::serialize(Archive& a, unsigned version)
1364{
1365 if (a.versionBelow(version, 2)) a.beginTag("YM2413Core");
1366 a.serialize("registers", reg);
1367 if (a.versionBelow(version, 2)) a.endTag("YM2413Core");
1368
1369 // only serialize user instrument
1370 a.serialize_blob("user_instrument", inst_tab[0]);
1371 a.serialize("channels", channels,
1372 "eg_cnt", eg_cnt,
1373 "noise_rng", noise_rng,
1374 "lfo_am_cnt", lfo_am_cnt,
1375 "lfo_pm_cnt", lfo_pm_cnt);
1376 if (a.versionAtLeast(version, 4)) {
1377 a.serialize("registerLatch", registerLatch);
1378 } else {
1379 // could be restored from MSXMusicBase, worth the effort?
1380 }
1381 // don't serialize idleSamples, it's only an optimization
1382}
1383
1384} // namespace YM2413Burczynski
1385
1389
1390} // namespace openmsx
constexpr int toInt() const
Returns the integer part (rounded down) of this fixed point number.
Definition FixedPoint.hh:77
constexpr void addQuantum()
Increase this value with the smallest possible amount.
void updateInstrument(std::span< const uint8_t, 8 > inst)
Sets all synthesis parameters as specified by the instrument.
void updateInstrumentPart(int part, uint8_t value)
Sets some synthesis parameters as specified by the instrument.
void setFrequencyLow(uint8_t value)
Changes the lower 8 bits of the frequency for this channel.
void serialize(Archive &ar, unsigned version)
void setFrequency(int block_fnum)
Sets the frequency for this channel.
void setFrequencyHigh(uint8_t value)
Changes the higher 4 bits of the frequency for this channel.
int calcOutput(unsigned eg_cnt, unsigned lfo_pm, unsigned lfo_am, int fm)
Calculate the value of the current sample produced by this channel.
void setSustainLevel(uint8_t value)
Sets the sustain level [0..15].
int calc_phase(const Channel &channel, unsigned lfo_pm)
int calc_slot_mod(const Channel &channel, unsigned eg_cnt, bool carrier, unsigned lfo_pm, unsigned lfo_am)
int calc_envelope(const Channel &channel, unsigned eg_cnt, bool carrier)
void setEnvelopeSustained(bool value)
Sets the envelope type of the current instrument.
void setKeyOnOff(KeyPart part, bool enabled)
void setAttackRate(const Channel &channel, uint8_t value)
Sets the attack rate [0..15].
void setFrequencyMultiplier(uint8_t value)
Sets the frequency multiplier [0..15].
void setReleaseRate(const Channel &channel, uint8_t value)
Sets the release rate [0..15].
void setWaveform(uint8_t value)
Sets the waveform: 0 = sinus, 1 = half sinus, half silence.
void updateFrequency(const Channel &channel)
Called by Channel when block_fnum changes.
int calcOutput(const Channel &channel, unsigned eg_cnt, bool carrier, unsigned lfo_am, int phase)
void serialize(Archive &ar, unsigned version)
void setVibrato(bool value)
Enables (true) or disables (false) vibrato.
void setAmplitudeModulation(bool value)
Enables (true) or disables (false) amplitude modulation.
void setDecayRate(const Channel &channel, uint8_t value)
Sets the decay rate [0..15].
void setFeedbackShift(uint8_t value)
Sets the amount of feedback [0..7].
void setKeyScaleLevel(const Channel &channel, uint8_t value)
Sets the key scale level: 0->0 / 1->1.5 / 2->3.0 / 3->6.0 dB/OCT.
void updateGenerators(const Channel &channel)
Update phase increment counter of operator.
void setTotalLevel(const Channel &channel, uint8_t value)
Sets the total level: [0..63].
bool isActive() const
Does this slot currently produce an output signal?
void setKeyScaleRate(bool value)
Sets the key scale rate: true->0, false->2.
void generateChannels(std::span< float *, 9+5 > bufs, unsigned num) override
Generate the sound output.
void writePort(bool port, uint8_t value, int offset) override
Write to the YM2413 register/data port.
void serialize(Archive &ar, unsigned version)
void reset() override
Reset this YM2413 core.
void pokeReg(uint8_t reg, uint8_t value) override
Write to a YM2413 register (for debug).
float getAmplificationFactor() const override
Returns normalization factor.
uint8_t peekReg(uint8_t reg) const override
Read from a YM2413 register (for debug).
Abstract interface for the YM2413 core.
Definition YM2413Core.hh:28
static constexpr int CLOCK_FREQ
Input clock frequency.
Definition YM2413Core.hh:41
constexpr double pi
Definition Math.hh:24
constexpr double round(double x)
Definition cstd.hh:247
FixedPoint< 16 > FreqIndex
16.16 fixed point type for frequency calculations.
This file implemented 3 utility functions:
Definition Autofire.cc:11
constexpr void fill(ForwardRange &&range, const T &value)
Definition ranges.hh:315
STL namespace.
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
#define SERIALIZE_ENUM(TYPE, INFO)
#define REGISTER_POLYMORPHIC_INITIALIZER(BASE, CLASS, NAME)
constexpr auto xrange(T e)
Definition xrange.hh:132