1use crate::{AyMode, AymBackend, SoundChip, StereoSample, AY_REGISTER_COUNT};
2
3const TONE_CHANNELS: usize = 3;
4const DECIMATE_FACTOR: usize = 8;
5const FIR_SIZE: usize = 192;
6const DC_FILTER_SIZE: usize = 1024;
7
8#[derive(Default)]
9struct ToneChannel {
10 tone_period: u16,
11 tone_counter: u16,
12 tone: usize,
13 tone_off_bit: usize,
14 noise_off_bit: usize,
15 envelope_enabled: bool,
16 volume: usize,
17 pan_left: f64,
18 pan_right: f64,
19}
20
21#[derive(Default)]
22struct Interpolator {
23 c: [f64; 4],
24 y: [f64; 4],
25}
26
27struct DcFilter {
28 sum: f64,
29 delay: [f64; DC_FILTER_SIZE],
30}
31
32impl Default for DcFilter {
33 fn default() -> Self {
34 Self {
35 sum: 0.0,
36 delay: [0.0; DC_FILTER_SIZE],
37 }
38 }
39}
40
41pub struct AymPrecise {
48 channels: [ToneChannel; TONE_CHANNELS],
49
50 noise_period: u16,
51 noise_counter: u16,
52 noise: usize,
53
54 envelope_counter: u16,
55 envelope_period: u16,
56 envelope_shape: usize,
57 envelope_segment: usize,
58 envelope: usize,
59
60 dac_table: &'static [f64; 32],
61 step: f64,
62 x: f64,
63 interpolator_left: Interpolator,
64 interpolator_right: Interpolator,
65
66 fir_left: [f64; FIR_SIZE * 2],
67 fir_right: [f64; FIR_SIZE * 2],
68 fir_index: usize,
69
70 dc_left: DcFilter,
71 dc_right: DcFilter,
72 dc_index: usize,
73
74 left: f64,
75 right: f64,
76
77 registers: [u8; AY_REGISTER_COUNT],
78 dc_filter: bool,
79}
80
81#[rustfmt::skip]
82const AY_DAC_TABLE: [f64; 32] = [
83 0.0, 0.0,
84 0.00999465934234, 0.00999465934234,
85 0.0144502937362, 0.0144502937362,
86 0.0210574502174, 0.0210574502174,
87 0.0307011520562, 0.0307011520562,
88 0.0455481803616, 0.0455481803616,
89 0.0644998855573, 0.0644998855573,
90 0.107362478065, 0.107362478065,
91 0.126588845655, 0.126588845655,
92 0.20498970016, 0.20498970016,
93 0.292210269322, 0.292210269322,
94 0.372838941024, 0.372838941024,
95 0.492530708782, 0.492530708782,
96 0.635324635691, 0.635324635691,
97 0.805584802014, 0.805584802014,
98 1.0, 1.0
99];
100
101#[rustfmt::skip]
102const YM_DAC_TABLE: [f64; 32] = [
103 0.0, 0.0,
104 0.00465400167849, 0.00772106507973,
105 0.0109559777218, 0.0139620050355,
106 0.0169985503929, 0.0200198367285,
107 0.024368657969, 0.029694056611,
108 0.0350652323186, 0.0403906309606,
109 0.0485389486534, 0.0583352407111,
110 0.0680552376593, 0.0777752346075,
111 0.0925154497597, 0.111085679408,
112 0.129747463188, 0.148485542077,
113 0.17666895552, 0.211551079576,
114 0.246387426566, 0.281101701381,
115 0.333730067903, 0.400427252613,
116 0.467383840696, 0.53443198291,
117 0.635172045472, 0.75800717174,
118 0.879926756695, 1.0
119];
120
121static ENVELOPES: [[fn(&mut AymPrecise); 2]; 16] = [
122 [AymPrecise::slide_down, AymPrecise::hold_bottom],
123 [AymPrecise::slide_down, AymPrecise::hold_bottom],
124 [AymPrecise::slide_down, AymPrecise::hold_bottom],
125 [AymPrecise::slide_down, AymPrecise::hold_bottom],
126 [AymPrecise::slide_up, AymPrecise::hold_bottom],
127 [AymPrecise::slide_up, AymPrecise::hold_bottom],
128 [AymPrecise::slide_up, AymPrecise::hold_bottom],
129 [AymPrecise::slide_up, AymPrecise::hold_bottom],
130 [AymPrecise::slide_down, AymPrecise::slide_down],
131 [AymPrecise::slide_down, AymPrecise::hold_bottom],
132 [AymPrecise::slide_down, AymPrecise::slide_up],
133 [AymPrecise::slide_down, AymPrecise::hold_top],
134 [AymPrecise::slide_up, AymPrecise::slide_up],
135 [AymPrecise::slide_up, AymPrecise::hold_top],
136 [AymPrecise::slide_up, AymPrecise::slide_down],
137 [AymPrecise::slide_up, AymPrecise::hold_bottom],
138];
139
140static ENVELOPE_RESET_TO_MAX: [[bool; 2]; 16] = [
141 [true, false],
142 [true, false],
143 [true, false],
144 [true, false],
145 [false, false],
146 [false, false],
147 [false, false],
148 [false, false],
149 [true, true],
150 [true, false],
151 [true, false],
152 [true, true],
153 [false, false],
154 [false, true],
155 [false, true],
156 [false, false],
157];
158
159impl AymPrecise {
160 fn new(is_ym: bool, clock_rate: f64, sample_rate: usize) -> Self {
161 let mut this = Self {
162 channels: Default::default(),
163 noise_period: 0,
164 noise_counter: 0,
165 noise: 0,
166 envelope_counter: 0,
167 envelope_period: 0,
168 envelope_shape: 0,
169 envelope_segment: 0,
170 envelope: 0,
171 dac_table: &AY_DAC_TABLE,
172 step: 0.0,
173 x: 0.0,
174 interpolator_left: Default::default(),
175 interpolator_right: Default::default(),
176 fir_left: [0.0; FIR_SIZE * 2],
177 fir_right: [0.0; FIR_SIZE * 2],
178 fir_index: 0,
179 dc_left: Default::default(),
180 dc_right: Default::default(),
181 dc_index: 0,
182 left: 0.0,
183 right: 0.0,
184 registers: [0; AY_REGISTER_COUNT],
185 dc_filter: false,
186 };
187
188 this.step = clock_rate / (sample_rate as f64 * 8f64 * DECIMATE_FACTOR as f64);
189 if is_ym {
190 this.dac_table = &YM_DAC_TABLE;
191 }
192 this.noise = 1;
193 this.set_envelope(1);
194 for i in 0..TONE_CHANNELS {
195 this.set_tone(i, 1);
196 }
197 this
198 }
199
200 fn set_pan(&mut self, index: usize, pan: f64, is_eqp: bool) {
201 if is_eqp {
202 self.channels[index].pan_left = libm::sqrt(1f64 - pan);
203 self.channels[index].pan_right = libm::sqrt(pan);
204 } else {
205 self.channels[index].pan_left = 1f64 - pan;
206 self.channels[index].pan_right = pan;
207 }
208 }
209
210 fn set_tone(&mut self, index: usize, period: u16) {
211 let period = period & 0xFFF;
212 self.channels[index].tone_period = (period == 0) as u16 | period;
213 }
214
215 fn set_noise(&mut self, period: u16) {
216 let period = period & 0x1F;
217 self.noise_period = (period == 0) as u16 | period;
218 }
219
220 fn set_mixer(
221 &mut self,
222 index: usize,
223 tone_enable: bool,
224 noise_enable: bool,
225 envelope_enabled: bool,
226 ) {
227 self.channels[index].tone_off_bit = (!tone_enable) as usize;
228 self.channels[index].noise_off_bit = (!noise_enable) as usize;
229 self.channels[index].envelope_enabled = envelope_enabled;
230 }
231
232 fn set_volume(&mut self, index: usize, volume: usize) {
233 self.channels[index].volume = volume & 0x0F;
234 }
235
236 fn set_envelope(&mut self, period: u16) {
237 self.envelope_period = (period == 0) as u16 | period;
238 }
239
240 fn set_envelope_shape(&mut self, shape: usize) {
241 self.envelope_shape = shape & 0x0F;
242 self.envelope_counter = 0;
243 self.envelope_segment = 0;
244 self.reset_segment();
245 }
246
247 fn process(&mut self) {
248 self.fir_index = (self.fir_index + 1) % (FIR_SIZE / DECIMATE_FACTOR - 1);
249 for i in (0..DECIMATE_FACTOR).rev() {
250 self.x += self.step;
251 if self.x >= 1.0 {
252 self.x -= 1.0;
253 self.interpolator_left.y[0] = self.interpolator_left.y[1];
254 self.interpolator_left.y[1] = self.interpolator_left.y[2];
255 self.interpolator_left.y[2] = self.interpolator_left.y[3];
256 self.interpolator_right.y[0] = self.interpolator_right.y[1];
257 self.interpolator_right.y[1] = self.interpolator_right.y[2];
258 self.interpolator_right.y[2] = self.interpolator_right.y[3];
259 self.update_mixer();
260 self.interpolator_left.y[3] = self.left;
261 self.interpolator_right.y[3] = self.right;
262 let y1 = self.interpolator_left.y[2] - self.interpolator_left.y[0];
263 self.interpolator_left.c[0] = 0.5 * self.interpolator_left.y[1]
264 + 0.25 * (self.interpolator_left.y[0] + self.interpolator_left.y[2]);
265 self.interpolator_left.c[1] = 0.5 * y1;
266 self.interpolator_left.c[2] =
267 0.25 * (self.interpolator_left.y[3] - self.interpolator_left.y[1] - y1);
268 let y1 = self.interpolator_right.y[2] - self.interpolator_right.y[0];
269 self.interpolator_right.c[0] = 0.5 * self.interpolator_right.y[1]
270 + 0.25 * (self.interpolator_right.y[0] + self.interpolator_right.y[2]);
271 self.interpolator_right.c[1] = 0.5 * y1;
272 self.interpolator_right.c[2] =
273 0.25 * (self.interpolator_right.y[3] - self.interpolator_right.y[1] - y1);
274 }
275 self.fir_left[FIR_SIZE - self.fir_index * DECIMATE_FACTOR..][i] =
276 (self.interpolator_left.c[2] * self.x + self.interpolator_left.c[1]) * self.x
277 + self.interpolator_left.c[0];
278 self.fir_right[FIR_SIZE - self.fir_index * DECIMATE_FACTOR..][i] =
279 (self.interpolator_right.c[2] * self.x + self.interpolator_right.c[1]) * self.x
280 + self.interpolator_right.c[0];
281 }
282 self.left = decimate(&mut self.fir_left[FIR_SIZE - self.fir_index * DECIMATE_FACTOR..]);
283 self.right = decimate(&mut self.fir_right[FIR_SIZE - self.fir_index * DECIMATE_FACTOR..]);
284 }
285
286 fn apply_dc_filter(&mut self) {
287 self.left = apply_dc_filter_for_sample(&mut self.dc_left, self.dc_index, self.left);
288 self.right = apply_dc_filter_for_sample(&mut self.dc_right, self.dc_index, self.right);
289 self.dc_index = (self.dc_index + 1) & (DC_FILTER_SIZE - 1);
290 }
291
292 fn slide_up(&mut self) {
293 if self.envelope == 31 {
294 self.envelope_segment ^= 1;
295 self.reset_segment();
296 } else {
297 self.envelope += 1;
298 }
299 }
300
301 fn slide_down(&mut self) {
302 if self.envelope == 0 {
303 self.envelope_segment ^= 1;
304 self.reset_segment();
305 } else {
306 self.envelope -= 1;
307 }
308 }
309
310 fn hold_top(&mut self) {}
311
312 fn hold_bottom(&mut self) {}
313
314 fn reset_segment(&mut self) {
315 if ENVELOPE_RESET_TO_MAX[self.envelope_shape][self.envelope_segment] {
316 self.envelope = 31;
317 return;
318 }
319 self.envelope = 0;
320 }
321
322 fn update_tone(&mut self, index: usize) -> usize {
323 let ch = &mut self.channels.as_mut()[index];
324 ch.tone_counter += 1;
325 if ch.tone_counter >= ch.tone_period {
326 ch.tone_counter = 0;
327 ch.tone ^= 1;
328 }
329
330 ch.tone
331 }
332
333 fn update_noise(&mut self) -> usize {
334 self.noise_counter += 1;
335 if self.noise_counter >= self.noise_period << 1 {
336 self.noise_counter = 0;
337 let bit0x3 = (self.noise ^ (self.noise >> 3)) & 1;
338 self.noise = (self.noise >> 1) | (bit0x3 << 16);
339 }
340
341 self.noise & 1
342 }
343
344 fn update_envelope(&mut self) -> usize {
345 self.envelope_counter += 1;
346 if self.envelope_counter >= self.envelope_period {
347 self.envelope_counter = 0;
348 ENVELOPES[self.envelope_shape][self.envelope_segment](self);
349 }
350 self.envelope
351 }
352
353 fn update_mixer(&mut self) {
354 let noise = self.update_noise();
355 let envelope = self.update_envelope();
356 self.left = 0.0;
357 self.right = 0.0;
358 for i in 0..TONE_CHANNELS {
359 let mut out = (self.update_tone(i) | self.channels[i].tone_off_bit)
360 & (noise | self.channels[i].noise_off_bit);
361 out *= if self.channels[i].envelope_enabled {
362 envelope
363 } else {
364 self.channels[i].volume * 2 + 1
365 };
366 assert!(out < 32);
367 self.left += self.dac_table[out] * self.channels[i].pan_left;
368 self.right += self.dac_table[out] * self.channels[i].pan_right;
369 }
370 }
371}
372
373#[allow(clippy::excessive_precision)]
374fn decimate(x: &mut [f64]) -> f64 {
375 assert!(x.len() >= FIR_SIZE);
376
377 let y = -0.0000046183113992051936 * (x[1] + x[191])
378 + -0.00001117761640887225 * (x[2] + x[190])
379 + -0.000018610264502005432 * (x[3] + x[189])
380 + -0.000025134586135631012 * (x[4] + x[188])
381 + -0.000028494281690666197 * (x[5] + x[187])
382 + -0.000026396828793275159 * (x[6] + x[186])
383 + -0.000017094212558802156 * (x[7] + x[185])
384 + 0.000023798193576966866 * (x[9] + x[183])
385 + 0.000051281160242202183 * (x[10] + x[182])
386 + 0.00007762197826243427 * (x[11] + x[181])
387 + 0.000096759426664120416 * (x[12] + x[180])
388 + 0.00010240229300393402 * (x[13] + x[179])
389 + 0.000089344614218077106 * (x[14] + x[178])
390 + 0.000054875700118949183 * (x[15] + x[177])
391 + -0.000069839082210680165 * (x[17] + x[175])
392 + -0.0001447966132360757 * (x[18] + x[174])
393 + -0.00021158452917708308 * (x[19] + x[173])
394 + -0.00025535069106550544 * (x[20] + x[172])
395 + -0.00026228714374322104 * (x[21] + x[171])
396 + -0.00022258805927027799 * (x[22] + x[170])
397 + -0.00013323230495695704 * (x[23] + x[169])
398 + 0.00016182578767055206 * (x[25] + x[167])
399 + 0.00032846175385096581 * (x[26] + x[166])
400 + 0.00047045611576184863 * (x[27] + x[165])
401 + 0.00055713851457530944 * (x[28] + x[164])
402 + 0.00056212565121518726 * (x[29] + x[163])
403 + 0.00046901918553962478 * (x[30] + x[162])
404 + 0.00027624866838952986 * (x[31] + x[161])
405 + -0.00032564179486838622 * (x[33] + x[159])
406 + -0.00065182310286710388 * (x[34] + x[158])
407 + -0.00092127787309319298 * (x[35] + x[157])
408 + -0.0010772534348943575 * (x[36] + x[156])
409 + -0.0010737727700273478 * (x[37] + x[155])
410 + -0.00088556645390392634 * (x[38] + x[154])
411 + -0.00051581896090765534 * (x[39] + x[153])
412 + 0.00059548767193795277 * (x[41] + x[151])
413 + 0.0011803558710661009 * (x[42] + x[150])
414 + 0.0016527320270369871 * (x[43] + x[149])
415 + 0.0019152679330965555 * (x[44] + x[148])
416 + 0.0018927324805381538 * (x[45] + x[147])
417 + 0.0015481870327877937 * (x[46] + x[146])
418 + 0.00089470695834941306 * (x[47] + x[145])
419 + -0.0010178225878206125 * (x[49] + x[143])
420 + -0.0020037400552054292 * (x[50] + x[142])
421 + -0.0027874356824117317 * (x[51] + x[141])
422 + -0.003210329988021943 * (x[52] + x[140])
423 + -0.0031540624117984395 * (x[53] + x[139])
424 + -0.0025657163651900345 * (x[54] + x[138])
425 + -0.0014750752642111449 * (x[55] + x[137])
426 + 0.0016624165446378462 * (x[57] + x[135])
427 + 0.0032591192839069179 * (x[58] + x[134])
428 + 0.0045165685815867747 * (x[59] + x[133])
429 + 0.0051838984346123896 * (x[60] + x[132])
430 + 0.0050774264697459933 * (x[61] + x[131])
431 + 0.0041192521414141585 * (x[62] + x[130])
432 + 0.0023628575417966491 * (x[63] + x[129])
433 + -0.0026543507866759182 * (x[65] + x[127])
434 + -0.0051990251084333425 * (x[66] + x[126])
435 + -0.0072020238234656924 * (x[67] + x[125])
436 + -0.0082672928192007358 * (x[68] + x[124])
437 + -0.0081033739572956287 * (x[69] + x[123])
438 + -0.006583111539570221 * (x[70] + x[122])
439 + -0.0037839040415292386 * (x[71] + x[121])
440 + 0.0042781252851152507 * (x[73] + x[119])
441 + 0.0084176358598320178 * (x[74] + x[118])
442 + 0.01172566057463055 * (x[75] + x[117])
443 + 0.013550476647788672 * (x[76] + x[116])
444 + 0.013388189369997496 * (x[77] + x[115])
445 + 0.010979501242341259 * (x[78] + x[114])
446 + 0.006381274941685413 * (x[79] + x[113])
447 + -0.007421229604153888 * (x[81] + x[111])
448 + -0.01486456304340213 * (x[82] + x[110])
449 + -0.021143584622178104 * (x[83] + x[109])
450 + -0.02504275058758609 * (x[84] + x[108])
451 + -0.025473530942547201 * (x[85] + x[107])
452 + -0.021627310017882196 * (x[86] + x[106])
453 + -0.013104323383225543 * (x[87] + x[105])
454 + 0.017065133989980476 * (x[89] + x[103])
455 + 0.036978919264451952 * (x[90] + x[102])
456 + 0.05823318062093958 * (x[91] + x[101])
457 + 0.079072012081405949 * (x[92] + x[100])
458 + 0.097675998716952317 * (x[93] + x[99])
459 + 0.11236045936950932 * (x[94] + x[98])
460 + 0.12176343577287731 * (x[95] + x[97])
461 + 0.125 * x[96];
462
463 let (src, dest) = x.split_at_mut(FIR_SIZE - DECIMATE_FACTOR);
464 dest[0..DECIMATE_FACTOR].copy_from_slice(&src[0..DECIMATE_FACTOR]);
465
466 y
467}
468
469fn apply_dc_filter_for_sample(dc: &mut DcFilter, index: usize, x: f64) -> f64 {
470 dc.sum += -dc.delay[index] + x;
471 dc.delay[index] = x;
472 x - dc.sum / DC_FILTER_SIZE as f64
473}
474
475impl AymPrecise {
476 pub fn enable_dc_filter(&mut self) {
478 self.dc_filter = true;
479 }
480}
481
482impl AymBackend for AymPrecise {
483 type SoundSample = f64;
484
485 fn new(chip: SoundChip, mode: AyMode, frequency: usize, sample_rate: usize) -> Self {
486 let mut ay = AymPrecise::new(matches!(chip, SoundChip::YM), frequency as f64, sample_rate);
487
488 let (pan_a, pan_b, pan_c) = match mode {
489 AyMode::Mono => (0.5, 0.5, 0.5),
490 AyMode::ABC => (0.0, 0.5, 1.0),
491 AyMode::ACB => (0.0, 1.0, 0.5),
492 AyMode::BAC => (0.5, 0.0, 1.0),
493 AyMode::BCA => (1.0, 0.0, 0.5),
494 AyMode::CAB => (0.5, 1.0, 0.0),
495 AyMode::CBA => (1.0, 0.5, 0.0),
496 };
497 ay.set_pan(0, pan_a, true);
498 ay.set_pan(1, pan_b, true);
499 ay.set_pan(2, pan_c, true);
500 ay
501 }
502
503 fn write_register(&mut self, address: u8, value: u8) {
504 if address as usize >= AY_REGISTER_COUNT {
505 return;
506 }
507
508 self.registers[address as usize] = value;
509
510 let r = self.registers;
511
512 match address {
513 0 | 1 => self.set_tone(0, u16::from_le_bytes([r[0], r[1] & 0x0f])),
514 2 | 3 => self.set_tone(1, u16::from_le_bytes([r[2], r[3] & 0x0f])),
515 4 | 5 => self.set_tone(2, u16::from_le_bytes([r[4], r[5] & 0x0f])),
516 6 => self.set_noise((r[6] & 0x1f) as u16),
517 7 => {
518 self.set_mixer(
519 0,
520 (r[7] & 0x01) == 0,
521 (r[7] & 0x08) == 0,
522 (r[8] & 0x10) != 0,
523 );
524 self.set_mixer(
525 1,
526 (r[7] & 0x02) == 0,
527 (r[7] & 0x10) == 0,
528 (r[9] & 0x10) != 0,
529 );
530 self.set_mixer(
531 2,
532 (r[7] & 0x04) == 0,
533 (r[7] & 0x20) == 0,
534 (r[10] & 0x10) != 0,
535 );
536 }
537 8 => {
538 self.set_mixer(
539 0,
540 (r[7] & 0x01) == 0,
541 (r[7] & 0x08) == 0,
542 (r[8] & 0x10) != 0,
543 );
544 self.set_volume(0, (r[8] & 0x0F) as usize);
545 }
546 9 => {
547 self.set_mixer(
548 1,
549 (r[7] & 0x02) == 0,
550 (r[7] & 0x10) == 0,
551 (r[9] & 0x10) != 0,
552 );
553 self.set_volume(1, (r[9] & 0x0F) as usize);
554 }
555 10 => {
556 self.set_mixer(
557 2,
558 (r[7] & 0x04) == 0,
559 (r[7] & 0x20) == 0,
560 (r[10] & 0x10) != 0,
561 );
562 self.set_volume(2, (r[10] & 0x0F) as usize);
563 }
564 11 | 12 => self.set_envelope(u16::from_le_bytes([r[11], r[12]])),
565 13 => self.set_envelope_shape((r[13] & 0x0F) as usize),
566 _ => unreachable!(),
567 }
568 }
569
570 fn next_sample(&mut self) -> StereoSample<Self::SoundSample> {
571 self.process();
572
573 if self.dc_filter {
574 self.apply_dc_filter();
575 }
576
577 StereoSample {
578 left: self.left,
579 right: self.right,
580 }
581 }
582}