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