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 int 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 int 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(Channel& channel, unsigned eg_cnt, bool carrier)
399{
400 switch (state) {
401 case EG_DUMP:
402 // Dump phase is performed by both operators in each channel.
403 // When CARRIER envelope gets down to zero level, phases in BOTH
404 // operators are reset (at the same time?).
405 // TODO: That sounds logical, but it does not match the implementation.
406 if (!(eg_cnt & eg_mask_dp)) {
407 egOut += eg_sel_dp[(eg_cnt >> eg_sh_dp) & 7];
408 if (egOut >= MAX_ATT_INDEX) {
409 egOut = MAX_ATT_INDEX;
410 setEnvelopeState(EG_ATTACK);
411 phase = FreqIndex(0); // restart Phase Generator
412 }
413 }
414 break;
415
416 case EG_ATTACK:
417 if (!(eg_cnt & eg_mask_ar)) {
418 egOut +=
419 (~egOut * eg_sel_ar[(eg_cnt >> eg_sh_ar) & 7]) >> 2;
420 if (egOut <= MIN_ATT_INDEX) {
421 egOut = MIN_ATT_INDEX;
422 setEnvelopeState(EG_DECAY);
423 }
424 }
425 break;
426
427 case EG_DECAY:
428 if (!(eg_cnt & eg_mask_dr)) {
429 egOut += eg_sel_dr[(eg_cnt >> eg_sh_dr) & 7];
430 if (egOut >= sl) {
431 setEnvelopeState(EG_SUSTAIN);
432 }
433 }
434 break;
435
436 case EG_SUSTAIN:
437 // this is important behaviour:
438 // one can change percussive/non-percussive modes on the fly and
439 // the chip will remain in sustain phase
440 // - verified on real YM3812
441 if (eg_sustain) {
442 // non-percussive mode (sustained tone)
443 // do nothing
444 } else {
445 // percussive mode
446 // during sustain phase chip adds Release Rate (in
447 // percussive mode)
448 if (!(eg_cnt & eg_mask_rr)) {
449 egOut += eg_sel_rr[(eg_cnt >> eg_sh_rr) & 7];
450 if (egOut >= MAX_ATT_INDEX) {
451 egOut = MAX_ATT_INDEX;
452 }
453 }
454 // else do nothing in sustain phase
455 }
456 break;
457
458 case EG_RELEASE:
459 // Exclude modulators in melody channels from performing anything in
460 // this mode.
461 if (carrier) {
462 const bool sustain = !eg_sustain || channel.isSustained();
463 const unsigned mask = sustain ? eg_mask_rs : eg_mask_rr;
464 if (!(eg_cnt & mask)) {
465 const uint8_t shift = sustain ? eg_sh_rs : eg_sh_rr;
466 std::span<const uint8_t, 8> sel = sustain ? eg_sel_rs : eg_sel_rr;
467 egOut += sel[(eg_cnt >> shift) & 7];
468 if (egOut >= MAX_ATT_INDEX) {
469 egOut = MAX_ATT_INDEX;
470 setEnvelopeState(EG_OFF);
471 }
472 }
473 }
474 break;
475
476 case EG_OFF:
477 break;
478 }
479 return egOut;
480}
481
482inline int Slot::calc_phase(Channel& channel, unsigned lfo_pm)
483{
484 if (vib) {
485 auto lfo_fn_table_index_offset = narrow<int>(lfo_pm_table
486 [(channel.getBlockFNum() & 0x01FF) >> 6][lfo_pm]);
487 phase += fnumToIncrement(
488 channel.getBlockFNum() * 2 + lfo_fn_table_index_offset
489 ) * mul;
490 } else {
491 // LFO phase modulation disabled for this operator
492 phase += freq;
493 }
494 return phase.toInt();
495}
496
497inline void Slot::updateTotalLevel(Channel& channel)
498{
499 TLL = TL + (channel.getKeyScaleLevelBase() >> ksl);
500}
501
502inline void Slot::updateAttackRate(int kcodeScaled)
503{
504 if ((ar + kcodeScaled) < (16 + 62)) {
505 eg_sh_ar = eg_rate_shift[ar + kcodeScaled];
506 eg_sel_ar = eg_inc[eg_rate_select[ar + kcodeScaled]];
507 } else {
508 eg_sh_ar = 0;
509 eg_sel_ar = eg_inc[13];
510 }
511 eg_mask_ar = (1 << eg_sh_ar) - 1;
512}
513
514inline void Slot::updateDecayRate(int kcodeScaled)
515{
516 eg_sh_dr = eg_rate_shift[dr + kcodeScaled];
517 eg_sel_dr = eg_inc[eg_rate_select[dr + kcodeScaled]];
518 eg_mask_dr = (1 << eg_sh_dr) - 1;
519}
520
521inline void Slot::updateReleaseRate(int kcodeScaled)
522{
523 eg_sh_rr = eg_rate_shift[rr + kcodeScaled];
524 eg_sel_rr = eg_inc[eg_rate_select[rr + kcodeScaled]];
525 eg_mask_rr = (1 << eg_sh_rr) - 1;
526}
527
528inline int Slot::calcOutput(Channel& channel, unsigned eg_cnt, bool carrier,
529 unsigned lfo_am, int phase2)
530{
531 int egOut2 = calc_envelope(channel, eg_cnt, carrier);
532 auto env = narrow<unsigned>((TLL + egOut2 + (lfo_am & AMmask)) << 5);
533 unsigned p = env + waveTable[phase2 & SIN_MASK];
534 return p < TL_TAB_LEN ? tlTab[p] : 0;
535}
536
537inline int Slot::calc_slot_mod(Channel& channel, unsigned eg_cnt, bool carrier,
538 unsigned lfo_pm, unsigned lfo_am)
539{
540 // Compute phase.
541 int phase2 = calc_phase(channel, lfo_pm);
542 if (fb_shift) {
543 phase2 += (op1_out[0] + op1_out[1]) >> fb_shift;
544 }
545 // Shift output in 2-place buffer.
546 op1_out[0] = op1_out[1];
547 // Calculate operator output.
548 op1_out[1] = calcOutput(channel, eg_cnt, carrier, lfo_am, phase2);
549 return op1_out[0] << 1;
550}
551
552inline int Channel::calcOutput(unsigned eg_cnt, unsigned lfo_pm, unsigned lfo_am, int fm)
553{
554 int phase = car.calc_phase(*this, lfo_pm) + fm;
555 return car.calcOutput(*this, eg_cnt, true, lfo_am, phase);
556}
557
558
559// Operators used in the rhythm sounds generation process:
560//
561// Envelope Generator:
562//
563// channel operator register number Bass High Snare Tom Top
564// / slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal
565// 6 / 0 12 50 70 90 f0 +
566// 6 / 1 15 53 73 93 f3 +
567// 7 / 0 13 51 71 91 f1 +
568// 7 / 1 16 54 74 94 f4 +
569// 8 / 0 14 52 72 92 f2 +
570// 8 / 1 17 55 75 95 f5 +
571//
572// Phase Generator:
573//
574// channel operator register number Bass High Snare Tom Top
575// / slot number MULTIPLE Drum Hat Drum Tom Cymbal
576// 6 / 0 12 30 +
577// 6 / 1 15 33 +
578// 7 / 0 13 31 + + +
579// 7 / 1 16 34 ----- n o t u s e d -----
580// 8 / 0 14 32 +
581// 8 / 1 17 35 + +
582//
583// channel operator register number Bass High Snare Tom Top
584// number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal
585// 6 12,15 B6 A6 +
586// 7 13,16 B7 A7 + + +
587// 8 14,17 B8 A8 + + +
588
589// Phase generation is based on:
590// HH (13) channel 7->slot 1 combined with channel 8->slot 2
591// (same combination as TOP CYMBAL but different output phases)
592// SD (16) channel 7->slot 1
593// TOM (14) channel 8->slot 1
594// TOP (17) channel 7->slot 1 combined with channel 8->slot 2
595// (same combination as HIGH HAT but different output phases)
596
597static constexpr int genPhaseHighHat(int phaseM7, int phaseC8, int noise_rng)
598{
599 // hi == phase >= 0x200
600 // enable gate based on frequency of operator 2 in channel 8
601 bool hi = [&] {
602 if (phaseC8 & 0x28) {
603 return true;
604 } else {
605 // base frequency derived from operator 1 in channel 7
606 // VC++ requires explicit conversion to bool. Compiler bug??
607 const bool bit7 = (phaseM7 & 0x80) != 0;
608 const bool bit3 = (phaseM7 & 0x08) != 0;
609 const bool bit2 = (phaseM7 & 0x04) != 0;
610 return bool((bit2 ^ bit7) | bit3);
611 }
612 }();
613 if (noise_rng & 1) {
614 return hi ? (0x200 | 0xD0) : (0xD0 >> 2);
615 } else {
616 return hi ? (0x200 | (0xD0 >> 2)) : 0xD0;
617 }
618}
619
620static constexpr int genPhaseSnare(int phaseM7, int noise_rng)
621{
622 // base frequency derived from operator 1 in channel 7
623 // noise bit XOR'es phase by 0x100
624 return ((phaseM7 & 0x100) + 0x100)
625 ^ ((noise_rng & 1) << 8);
626}
627
628static constexpr int genPhaseCymbal(int phaseM7, int phaseC8)
629{
630 // enable gate based on frequency of operator 2 in channel 8
631 if (phaseC8 & 0x28) {
632 return 0x300;
633 } else {
634 // base frequency derived from operator 1 in channel 7
635 // VC++ requires explicit conversion to bool. Compiler bug??
636 const bool bit7 = (phaseM7 & 0x80) != 0;
637 const bool bit3 = (phaseM7 & 0x08) != 0;
638 const bool bit2 = (phaseM7 & 0x04) != 0;
639 return ((bit2 != bit7) || bit3) ? 0x300 : 0x100;
640 }
641}
642
643
645 : waveTable(sinTab[0])
646 , eg_sel_dp(eg_inc[0]), eg_sel_ar(eg_inc[0]), eg_sel_dr(eg_inc[0])
647 , eg_sel_rr(eg_inc[0]), eg_sel_rs(eg_inc[0])
648{
649 setEnvelopeState(EG_OFF);
650}
651
653{
654 if (!key) {
655 // do NOT restart Phase Generator (verified on real YM2413)
656 setEnvelopeState(EG_DUMP);
657 }
658 key |= part;
659}
660
662{
663 if (key) {
664 key &= ~part;
665 if (!key) {
666 if (isActive()) {
667 setEnvelopeState(EG_RELEASE);
668 }
669 }
670 }
671}
672
673void Slot::setKeyOnOff(KeyPart part, bool enabled)
674{
675 if (enabled) {
676 setKeyOn(part);
677 } else {
678 setKeyOff(part);
679 }
680}
681
682bool Slot::isActive() const
683{
684 return state != EG_OFF;
685}
686
687void Slot::setEnvelopeState(EnvelopeState state_)
688{
689 state = state_;
690}
691
693{
694 mul = mul_tab[value];
695}
696
697void Slot::setKeyScaleRate(bool value)
698{
699 KSR = value ? 0 : 2;
700}
701
703{
704 eg_sustain = value;
705}
706
707void Slot::setVibrato(bool value)
708{
709 vib = value;
710}
711
713{
714 AMmask = value ? ~0 : 0;
715}
716
717void Slot::setTotalLevel(Channel& channel, uint8_t value)
718{
719 TL = value << (ENV_BITS - 2 - 7); // 7 bits TL (bit 6 = always 0)
720 updateTotalLevel(channel);
721}
722
723void Slot::setKeyScaleLevel(Channel& channel, uint8_t value)
724{
725 ksl = value ? (3 - value) : 31;
726 updateTotalLevel(channel);
727}
728
729void Slot::setWaveform(uint8_t value)
730{
731 waveTable = sinTab[value];
732}
733
734void Slot::setFeedbackShift(uint8_t value)
735{
736 fb_shift = value ? 8 - value : 0;
737}
738
739void Slot::setAttackRate(const Channel& channel, uint8_t value)
740{
741 int kcodeScaled = channel.getKeyCode() >> KSR;
742 ar = value ? 16 + (value << 2) : 0;
743 updateAttackRate(kcodeScaled);
744}
745
746void Slot::setDecayRate(const Channel& channel, uint8_t value)
747{
748 int kcodeScaled = channel.getKeyCode() >> KSR;
749 dr = value ? 16 + (value << 2) : 0;
750 updateDecayRate(kcodeScaled);
751}
752
753void Slot::setReleaseRate(const Channel& channel, uint8_t value)
754{
755 int kcodeScaled = channel.getKeyCode() >> KSR;
756 rr = value ? 16 + (value << 2) : 0;
757 updateReleaseRate(kcodeScaled);
758}
759
760void Slot::setSustainLevel(uint8_t value)
761{
762 sl = sl_tab[value];
763}
764
766{
767 updateTotalLevel(channel);
768 updateGenerators(channel);
769}
770
772{
773 waveTable = sinTab[0];
774 setEnvelopeState(EG_OFF);
775 egOut = MAX_ATT_INDEX;
776}
777
779{
780 // (frequency) phase increment counter
781 freq = channel.getFrequencyIncrement() * mul;
782
783 // calculate envelope generator rates
784 const int kcodeScaled = channel.getKeyCode() >> KSR;
785 updateAttackRate(kcodeScaled);
786 updateDecayRate(kcodeScaled);
787 updateReleaseRate(kcodeScaled);
788
789 const int rs = channel.isSustained() ? 16 + (5 << 2) : 16 + (7 << 2);
790 eg_sh_rs = eg_rate_shift[rs + kcodeScaled];
791 eg_sel_rs = eg_inc[eg_rate_select[rs + kcodeScaled]];
792
793 const int dp = 16 + (13 << 2);
794 eg_sh_dp = eg_rate_shift[dp + kcodeScaled];
795 eg_sel_dp = eg_inc[eg_rate_select[dp + kcodeScaled]];
796
797 eg_mask_rs = (1 << eg_sh_rs) - 1;
798 eg_mask_dp = (1 << eg_sh_dp) - 1;
799}
800
801void Channel::setFrequency(int block_fnum_)
802{
803 if (block_fnum == block_fnum_) return;
804 block_fnum = block_fnum_;
805
806 ksl_base = ksl_tab[block_fnum >> 5];
807 fc = fnumToIncrement(block_fnum * 2);
808
809 // Refresh Total Level and frequency counter in both SLOTs of this channel.
810 mod.updateFrequency(*this);
811 car.updateFrequency(*this);
812}
813
814void Channel::setFrequencyLow(uint8_t value)
815{
816 setFrequency((block_fnum & 0x0F00) | value);
817}
818
819void Channel::setFrequencyHigh(uint8_t value)
820{
821 setFrequency((value << 8) | (block_fnum & 0x00FF));
822}
823
825{
826 return block_fnum;
827}
828
830{
831 return fc;
832}
833
835{
836 return ksl_base;
837}
838
839uint8_t Channel::getKeyCode() const
840{
841 // BLK 2,1,0 bits -> bits 3,2,1 of kcode, FNUM MSB -> kcode LSB
842 return (block_fnum & 0x0F00) >> 8;
843}
844
846{
847 return sus;
848}
849
850void Channel::setSustain(bool sustained)
851{
852 sus = sustained;
853}
854
855void Channel::updateInstrumentPart(int part, uint8_t value)
856{
857 switch (part) {
858 case 0:
859 mod.setFrequencyMultiplier(value & 0x0F);
860 mod.setKeyScaleRate((value & 0x10) != 0);
861 mod.setEnvelopeSustained((value & 0x20) != 0);
862 mod.setVibrato((value & 0x40) != 0);
863 mod.setAmplitudeModulation((value & 0x80) != 0);
864 mod.updateGenerators(*this);
865 break;
866 case 1:
867 car.setFrequencyMultiplier(value & 0x0F);
868 car.setKeyScaleRate((value & 0x10) != 0);
869 car.setEnvelopeSustained((value & 0x20) != 0);
870 car.setVibrato((value & 0x40) != 0);
871 car.setAmplitudeModulation((value & 0x80) != 0);
872 car.updateGenerators(*this);
873 break;
874 case 2:
875 mod.setKeyScaleLevel(*this, value >> 6);
876 mod.setTotalLevel(*this, value & 0x3F);
877 break;
878 case 3:
879 mod.setWaveform((value & 0x08) >> 3);
880 mod.setFeedbackShift(value & 0x07);
881 car.setKeyScaleLevel(*this, value >> 6);
882 car.setWaveform((value & 0x10) >> 4);
883 break;
884 case 4:
885 mod.setAttackRate(*this, value >> 4);
886 mod.setDecayRate(*this, value & 0x0F);
887 break;
888 case 5:
889 car.setAttackRate(*this, value >> 4);
890 car.setDecayRate(*this, value & 0x0F);
891 break;
892 case 6:
893 mod.setSustainLevel(value >> 4);
894 mod.setReleaseRate(*this, value & 0x0F);
895 break;
896 case 7:
897 car.setSustainLevel(value >> 4);
898 car.setReleaseRate(*this, value & 0x0F);
899 break;
900 }
901}
902
903void Channel::updateInstrument(std::span<const uint8_t, 8> inst)
904{
905 for (auto part : xrange(8)) {
906 updateInstrumentPart(part, inst[part]);
907 }
908}
909
911 : lfo_am_cnt(0), lfo_pm_cnt(0)
912{
913 if (false) {
914 for (const auto& e : tlTab) std::cout << e << '\n';
915 std::cout << '\n';
916 for (const auto& s : sinTab) {
917 for (const auto& e : s) std::cout << e << '\n';
918 }
919 }
920
921 ranges::fill(reg, 0); // avoid UMR
922 eg_cnt = 0;
923 noise_rng = 0;
924
925 reset();
926}
927
928void YM2413::updateCustomInstrument(int part, uint8_t value)
929{
930 // Update instrument definition.
931 inst_tab[0][part] = value;
932
933 // Update every channel that has instrument 0 selected.
934 for (auto ch : xrange(isRhythm() ? 6 : 9)) {
935 Channel& channel = channels[ch];
936 if ((reg[0x30 + ch] & 0xF0) == 0) {
937 channel.updateInstrumentPart(part, value);
938 }
939 }
940}
941
942void YM2413::setRhythmFlags(uint8_t old)
943{
944 Channel& ch6 = channels[6];
945 Channel& ch7 = channels[7];
946 Channel& ch8 = channels[8];
947
948 // flags = X | X | mode | BD | SD | TOM | TC | HH
949 uint8_t flags = reg[0x0E];
950 if ((flags ^ old) & 0x20) {
951 if (flags & 0x20) { // OFF -> ON
952 // Bass drum.
953 ch6.updateInstrument(inst_tab[16]);
954 // High hat and snare drum.
955 ch7.updateInstrument(inst_tab[17]);
956 ch7.mod.setTotalLevel(ch7, (reg[0x37] >> 4) << 2); // High hat
957 // Tom-tom and top cymbal.
958 ch8.updateInstrument(inst_tab[18]);
959 ch8.mod.setTotalLevel(ch8, (reg[0x38] >> 4) << 2); // Tom-tom
960 } else { // ON -> OFF
961 ch6.updateInstrument(inst_tab[reg[0x36] >> 4]);
962 ch7.updateInstrument(inst_tab[reg[0x37] >> 4]);
963 ch8.updateInstrument(inst_tab[reg[0x38] >> 4]);
964 // BD key off
965 ch6.mod.setKeyOff(Slot::KEY_RHYTHM);
966 ch6.car.setKeyOff(Slot::KEY_RHYTHM);
967 // HH key off
968 ch7.mod.setKeyOff(Slot::KEY_RHYTHM);
969 // SD key off
970 ch7.car.setKeyOff(Slot::KEY_RHYTHM);
971 // TOM key off
972 ch8.mod.setKeyOff(Slot::KEY_RHYTHM);
973 // TOP-CY off
974 ch8.car.setKeyOff(Slot::KEY_RHYTHM);
975 }
976 }
977 if (flags & 0x20) {
978 // BD key on/off
979 ch6.mod.setKeyOnOff(Slot::KEY_RHYTHM, (flags & 0x10) != 0);
980 ch6.car.setKeyOnOff(Slot::KEY_RHYTHM, (flags & 0x10) != 0);
981 // HH key on/off
982 ch7.mod.setKeyOnOff(Slot::KEY_RHYTHM, (flags & 0x01) != 0);
983 // SD key on/off
984 ch7.car.setKeyOnOff(Slot::KEY_RHYTHM, (flags & 0x08) != 0);
985 // TOM key on/off
986 ch8.mod.setKeyOnOff(Slot::KEY_RHYTHM, (flags & 0x04) != 0);
987 // TOP-CY key on/off
988 ch8.car.setKeyOnOff(Slot::KEY_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 (int 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::KEY_MAIN, (v & 0x10) != 0);
1237 ch.car.setKeyOnOff(Slot::KEY_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, (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, (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 int 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:76
constexpr void addQuantum()
Increase this value with the smallest possible amount.
Definition: FixedPoint.hh:200
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].
EnvelopeState
Envelope Generator phases Note: These are ordered: phase constants are compared in the code.
void updateFrequency(Channel &channel)
Called by Channel when block_fnum changes.
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].
int calcOutput(Channel &channel, unsigned eg_cnt, bool carrier, unsigned lfo_am, int phase)
void setTotalLevel(Channel &channel, uint8_t value)
Sets the total level: [0..63].
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.
int calc_envelope(Channel &channel, unsigned eg_cnt, bool carrier)
void serialize(Archive &ar, unsigned version)
void setVibrato(bool value)
Enables (true) or disables (false) vibrato.
int calc_phase(Channel &channel, unsigned lfo_pm)
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 setKeyScaleLevel(Channel &channel, uint8_t value)
Sets the key scale level: 0->0 / 1->1.5 / 2->3.0 / 3->6.0 dB/OCT.
void setFeedbackShift(uint8_t value)
Sets the amount of feedback [0..7].
bool isActive() const
Does this slot currently produce an output signal?
int calc_slot_mod(Channel &channel, unsigned eg_cnt, bool carrier, unsigned lfo_pm, unsigned lfo_am)
void setKeyScaleRate(bool value)
Sets the key scale rate: true->0, false->2.
void updateGenerators(Channel &channel)
Update phase increment counter of operator.
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:23
constexpr double e
Definition: Math.hh:20
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: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
constexpr auto xrange(T e)
Definition: xrange.hh:133