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