ym2612.rsannotatedym2612.rssource1052 lines · 37.2 KB · raw

YM2612 FM synthesis sound chip, also known as the OPN2

This implementation is mostly based on community research documented here: http://gendev.spritesmind.net/forum/viewtopic.php?f=24&t=386

6mod debug;
7mod envelope;
8mod lfo;
9mod phase;
10mod timer;
12use crate::ym2612::envelope::EnvelopeGenerator;
13use crate::ym2612::lfo::LowFrequencyOscillator;
14use crate::ym2612::phase::PhaseGenerator;
15use crate::ym2612::timer::{TimerA, TimerB, TimerControl, TimerTickEffect};
16use bincode::{Decode, Encode};
17use genesis_config::{GenesisEmulatorConfig, Opn2BusyBehavior};
18use jgenesis_common::num::GetBit;
19use std::sync::LazyLock;
20use std::{array, mem};
21
22pub use debug::{
23    Channel3FrequencyMode, ChannelRegisters, GlobalRegisters, LfoState, OperatorRegisters,
24    TimerState, Ym2612DebugView,
25};
26
27const FM_SAMPLE_DIVIDER: u8 = 24;

Phase is 10 bits

30const PHASE_MASK: u16 = 0x03FF;
31const HALF_PHASE_MASK: u16 = PHASE_MASK >> 1;

Operator output is signed 14-bit

34const OPERATOR_OUTPUT_MIN: i16 = -0x2000;
35const OPERATOR_OUTPUT_MAX: i16 = 0x1FFF;

Group 1 is channels 1-3 (idx 0-2), group 2 is channels 4-6 (idx 3-5)

38const GROUP_1_BASE_CHANNEL: usize = 0;
39const GROUP_2_BASE_CHANNEL: usize = 3;
41fn compute_key_code(f_number: u16, block: u8) -> u8 {
42    // Bits 4-2: Block
43    // Bit 1: F11
44    // Bit 0: (F11 & (F10 | F9 | F8)) | (!F11 & F10 & F9 & F8)
45    let f11 = f_number.bit(10);
46    let f10 = f_number.bit(9);
47    let f9 = f_number.bit(8);
48    let f8 = f_number.bit(7);
49    (block << 2)
50        | (u8::from(f11) << 1)
51        | u8::from((f11 && (f10 || f9 || f8)) || (!f11 && f10 && f9 && f8))
52}
53
54#[derive(Debug, Clone, Default, Encode, Decode)]
55struct FmOperator {
56    phase: PhaseGenerator,
57    envelope: EnvelopeGenerator,
58    am_enabled: bool,
59    current_output: i16,
60    last_output: i16,
61    // Values used in output calculation that are copied here for convenience
62    lfo_counter: u8,
63    am_sensitivity: u8,
64}
65
66impl FmOperator {
67    fn update_frequency(&mut self, f_number: u16, block: u8) {
68        self.phase.f_number = f_number;
69        self.phase.block = block;
70        self.envelope.update_key_scale_rate(f_number, block);
71    }
72
73    fn update_key_scale(&mut self, key_scale: u8) {
74        self.envelope.key_scale = key_scale;
75        self.envelope.update_key_scale_rate(self.phase.f_number, self.phase.block);
76    }
77
78    fn key_on_or_off(&mut self, value: bool) {
79        if value {
80            if !self.envelope.is_key_on() {
81                self.phase.reset();
82                self.envelope.key_on();
83            }
84        } else {
85            self.envelope.key_off();
86        }
87    }
88
89    fn sample_clock(&mut self, modulation_input: i16) -> i16 {
90        let phase = self.phase.current_phase().wrapping_add_signed(modulation_input);
91
92        // Phase is a 10-bit value that represents a number in the range 0 to 2*PI.
93        // Actual hardware splits this into a sign bit and a half-phase value from 0 to PI, computes
94        // the amplitude based on the half-phase, and then applies the sign bit at final output
95        let sign = phase.bit(9);
96        let sine_attenuation = phase_to_attenuation(phase);
97
98        let envelope_attenuation = self.envelope.current_attenuation();
99        let envelope_am_attenuation = if self.am_enabled {
100            let am_attenuation = lfo::amplitude_modulation(self.lfo_counter, self.am_sensitivity);
101            (envelope_attenuation + am_attenuation).clamp(0, envelope::MAX_ATTENUATION)
102        } else {
103            envelope_attenuation
104        };
105
106        // Add phase attenuation (4.8 fixed-point) and envelope/AM attenuation (4.6 fixed-point)
107        let total_attenuation = sine_attenuation + (envelope_am_attenuation << 2);
108
109        // Compute final output, adding the sign bit back in
110        let amplitude = attenuation_to_amplitude(total_attenuation);
111        let output = if sign { -(amplitude as i16) } else { amplitude as i16 };
112
113        self.last_output = self.current_output;
114        self.current_output = output;
115
116        output
117    }
118}

Logic based on http://gendev.spritesmind.net/forum/viewtopic.php?p=6114#p6114

121#[inline]
122fn phase_to_attenuation(phase: u16) -> u16 {
123    // Actual hardware has a 256-entry quarter-sine table. This is emulated using a half-sine table
124    // for simplicity, but the values are calculated the same way
125    static LOG_SINE_TABLE: LazyLock<[u16; 512]> = LazyLock::new(|| {
126        array::from_fn(|mut i| {
127            use std::f64::consts::PI;
128
129            if i.bit(8) {
130                // Second quarter-phase
131                i = (!i) & 0xFF;
132            }
133
134            // The table indices represent numbers in the range 0 to PI/2, but slightly offset in order
135            // to avoid computing log2(0)
136            let n = ((i << 1) | 1) as f64;
137            let sine = (n / 512.0 * PI / 2.0).sin();
138
139            // The table stores attenuation values, but on a log2 scale instead of log10
140            let attenuation = -sine.log2();
141
142            // Table contains 12-bit values that represent 4.8 fixed-point
143            (attenuation * f64::from(1 << 8)).round() as u16
144        })
145    });
146
147    LOG_SINE_TABLE[(phase & HALF_PHASE_MASK) as usize]
148}

Logic based on http://gendev.spritesmind.net/forum/viewtopic.php?p=6114#p6114

151#[inline]
152fn attenuation_to_amplitude(attenuation: u16) -> u16 {
153    static POW2_TABLE: LazyLock<[u16; 256]> = LazyLock::new(|| {
154        array::from_fn(|i| {
155            // This is a lookup table for 2^(-n), where n is a value between 0 and 1
156            // Index i represents the number (i + 1)/256
157            let n = ((i + 1) as f64) / 256.0;
158            let inverse_pow2 = 2.0_f64.powf(-n);
159
160            // Table contains 11-bit values that represent 0.11 fixed-point
161            (inverse_pow2 * f64::from(1 << 11)).round() as u16
162        })
163    });
164
165    // Attenuation is interpreted as a 5.8 fixed-point number on a log2 scale
166    let int_part = (attenuation >> 8) & 0x1F;
167    if int_part >= 13 {
168        // Final result is guaranteed to shift down to 0
169        // Int part is applied as a right shift to 13-bit values
170        return 0;
171    }
172
173    let fract_part = attenuation & 0xFF;
174    let fract_pow2 = POW2_TABLE[fract_part as usize];
175    (fract_pow2 << 2) >> int_part
176}
178#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)]
179enum FrequencyMode {
180    #[default]
181    Single,
182    Multiple,
183}
184
185#[derive(Debug, Clone, Encode, Decode)]
186struct FmChannel {
187    operators: [FmOperator; 4],
188    mode: FrequencyMode,
189    pending_ch_f_number_high: u8,
190    channel_f_number: u16,
191    pending_ch_block: u8,
192    channel_block: u8,
193    pending_op_f_numbers_high: [u8; 3],
194    operator_f_numbers: [u16; 3],
195    pending_op_blocks: [u8; 3],
196    operator_blocks: [u8; 3],
197    algorithm: u8,
198    feedback_level: u8,
199    am_sensitivity: u8,
200    fm_sensitivity: u8,
201    l_output: bool,
202    r_output: bool,
203    current_output: i16,
204}
205
206impl FmChannel {
207    fn new() -> Self {
208        Self {
209            operators: array::from_fn(|_| FmOperator::default()),
210            mode: FrequencyMode::Single,
211            pending_ch_f_number_high: 0,
212            channel_f_number: 0,
213            pending_ch_block: 0,
214            channel_block: 0,
215            pending_op_f_numbers_high: [0; 3],
216            operator_f_numbers: [0; 3],
217            pending_op_blocks: [0; 3],
218            operator_blocks: [0; 3],
219            algorithm: 0,
220            feedback_level: 0,
221            am_sensitivity: 0,
222            fm_sensitivity: 0,
223            l_output: true,
224            r_output: true,
225            current_output: 0,
226        }
227    }
228
229    #[inline]
230    fn clock(&mut self, lfo_counter: u8, quantization_mask: i16) {
231        for operator in &mut self.operators {
232            operator.phase.clock(lfo_counter, self.fm_sensitivity);
233            operator.envelope.clock(&mut operator.phase);
234
235            operator.lfo_counter = lfo_counter;
236            operator.am_sensitivity = self.am_sensitivity;
237        }
238
239        self.generate_sample(quantization_mask);
240    }
241
242    fn generate_sample(&mut self, out_mask: i16) {
243        macro_rules! carrier_sum {
244            ($($carrier:expr),*) => {
245                {
246                    let mut sum = 0;
247                    $(sum += $carrier & out_mask;)*
248                    sum.clamp(OPERATOR_OUTPUT_MIN & out_mask, OPERATOR_OUTPUT_MAX & out_mask)
249                }
250            }
251        }
252
253        let op1_feedback = match self.feedback_level {
254            0 => 0,
255            f => (self.operators[0].current_output + self.operators[0].last_output) >> (10 - f),
256        };
257
258        // Operator order is 1 -> 3 -> 2 -> 4, per http://gendev.spritesmind.net/forum/viewtopic.php?p=30063#p30063
259        // Additionally, when two operators execute consecutively, if the first one modulates the
260        // second one, it will use the operator output from the previous cycle instead of the current
261        // cycle. This is due to how the chip pipelines operator evaluation internally.
262        let sample = match self.algorithm {
263            0 => {
264                // O1 -> O2 -> O3 -> O4 -> Output
265                let m1 = self.operators[0].sample_clock(op1_feedback);
266
267                let m2_old = self.operators[1].current_output;
268                self.operators[1].sample_clock(m1 >> 1);
269
270                let m3 = self.operators[2].sample_clock(m2_old >> 1);
271                let c4 = self.operators[3].sample_clock(m3 >> 1);
272
273                c4 & out_mask
274            }
275            1 => {
276                // O1 --|
277                //      --> O3 -> O4 -> Output
278                // O2 --|
279                let m1_old = self.operators[0].current_output;
280                self.operators[0].sample_clock(op1_feedback);
281
282                let m2_old = self.operators[1].current_output;
283                self.operators[1].sample_clock(0);
284
285                let m3 = self.operators[2].sample_clock((m1_old + m2_old) >> 1);
286                let c4 = self.operators[3].sample_clock(m3 >> 1);
287
288                c4 & out_mask
289            }
290            2 => {
291                //       O1 --|
292                //            --> O4 -> Output
293                // O2 -> O3 --|
294                let m1 = self.operators[0].sample_clock(op1_feedback);
295
296                let m2_old = self.operators[1].current_output;
297                self.operators[1].sample_clock(0);
298
299                let m3 = self.operators[2].sample_clock(m2_old >> 1);
300                let c4 = self.operators[3].sample_clock((m1 + m3) >> 1);
301
302                c4 & out_mask
303            }
304            3 => {
305                // O1 -> O2 --|
306                //            --> O4 -> Output
307                //       O3 --|
308                let m1 = self.operators[0].sample_clock(op1_feedback);
309
310                let m2_old = self.operators[1].current_output;
311                self.operators[1].sample_clock(m1 >> 1);
312
313                let m3 = self.operators[2].sample_clock(0);
314                let c4 = self.operators[3].sample_clock((m2_old + m3) >> 1);
315
316                c4 & out_mask
317            }
318            4 => {
319                // O1 -> O2 --|
320                //            --> Output
321                // O3 -> O4 --|
322                let m1 = self.operators[0].sample_clock(op1_feedback);
323                let c2 = self.operators[1].sample_clock(m1 >> 1);
324                let m3 = self.operators[2].sample_clock(0);
325                let c4 = self.operators[3].sample_clock(m3 >> 1);
326
327                carrier_sum!(c2, c4)
328            }
329            5 => {
330                //      --> O2 --|
331                //      |        |
332                // O1 --|-> O3 ----> Output
333                //      |        |
334                //      --> O4 --|
335                let m1_old = self.operators[0].current_output;
336                let m1 = self.operators[0].sample_clock(op1_feedback);
337                let c2 = self.operators[1].sample_clock(m1 >> 1);
338                let c3 = self.operators[2].sample_clock(m1_old >> 1);
339                let c4 = self.operators[3].sample_clock(m1 >> 1);
340
341                carrier_sum!(c2, c3, c4)
342            }
343            6 => {
344                // O1 --> O2 --|
345                //             |
346                //        O3 ----> Output
347                //             |
348                //        O4 --|
349                let m1 = self.operators[0].sample_clock(op1_feedback);
350                let c2 = self.operators[1].sample_clock(m1 >> 1);
351                let c3 = self.operators[2].sample_clock(0);
352                let c4 = self.operators[3].sample_clock(0);
353
354                carrier_sum!(c2, c3, c4)
355            }
356            7 => {
357                // O1 --|
358                //      |
359                // O2 --|
360                //      --> Output
361                // O3 --|
362                //      |
363                // O4 --|
364                let c1 = self.operators[0].sample_clock(op1_feedback);
365                let c2 = self.operators[1].sample_clock(0);
366                let c3 = self.operators[2].sample_clock(0);
367                let c4 = self.operators[3].sample_clock(0);
368
369                carrier_sum!(c1, c2, c3, c4)
370            }
371            _ => panic!("invalid algorithm: {}", self.algorithm),
372        };
373
374        self.current_output = sample;
375    }
376
377    // Update phase generator F-numbers & blocks after channel-level F-number, block, or frequency mode is updated
378    fn update_phase_generators(&mut self) {
379        match self.mode {
380            FrequencyMode::Single => {
381                let f_number = self.channel_f_number;
382                let block = self.channel_block;
383                for operator in &mut self.operators {
384                    operator.update_frequency(f_number, block);
385                }
386            }
387            FrequencyMode::Multiple => {
388                for i in 0..3 {
389                    let f_number = self.operator_f_numbers[i];
390                    let block = self.operator_blocks[i];
391
392                    self.operators[i].update_frequency(f_number, block);
393                }
394
395                let last_f_number = self.channel_f_number;
396                let last_block = self.channel_block;
397
398                self.operators[3].update_frequency(last_f_number, last_block);
399            }
400        }
401    }
402}
403
404impl Default for FmChannel {
405    fn default() -> Self {
406        Self::new()
407    }
408}

The YM2612 always raises the BUSY line for exactly 32 internal cycles after a register write

411const WRITE_BUSY_CYCLES: u8 = 32;
413#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)]
414pub enum RegisterGroup {
415    // Channel 1-3 and global registers
416    #[default]
417    One,
418    // Channel 4-6 registers
419    Two,
420}
421
422trait GenesisConfigExt {
423    fn channels_muted(&self) -> [bool; 6];
424}
425
426impl GenesisConfigExt for GenesisEmulatorConfig {
427    fn channels_muted(&self) -> [bool; 6] {
428        self.ym2612_channels_enabled.map(|enabled| !enabled)
429    }
430}
431
432#[derive(Debug, Clone, Encode, Decode)]
433pub struct Ym2612 {
434    channels: [FmChannel; 6],
435    channels_muted: [bool; 6],
436    dac_channel_enabled: bool,
437    dac_channel_sample: u8,
438    lfo: LowFrequencyOscillator,
439    selected_register: u8,
440    selected_register_group: RegisterGroup,
441    sample_divider: u8,
442    busy_cycles_remaining: u8,
443    timer_a: TimerA,
444    timer_b: TimerB,
445    csm_enabled: bool,
446    quantize_output: bool,
447    emulate_ladder_effect: bool,
448    busy_behavior: Opn2BusyBehavior,
449    last_status_read: u8,
450    status_decay_samples_remaining: u32,
451    output_samples: Vec<(f64, f64)>,
452}
453
454impl Ym2612 {
455    #[must_use]
456    pub fn new(config: &GenesisEmulatorConfig) -> Self {
457        Self::new_internal(
458            config.channels_muted(),
459            config.quantize_ym2612_output,
460            config.emulate_ym2612_ladder_effect,
461            config.opn2_busy_behavior,
462            FM_SAMPLE_DIVIDER,
463            Vec::with_capacity(500),
464        )
465    }
466
467    fn new_internal(
468        channels_muted: [bool; 6],
469        quantize_output: bool,
470        emulate_ladder_effect: bool,
471        busy_behavior: Opn2BusyBehavior,
472        sample_divider: u8,
473        output_samples: Vec<(f64, f64)>,
474    ) -> Self {
475        Self {
476            channels: array::from_fn(|_| FmChannel::default()),
477            channels_muted,
478            dac_channel_enabled: false,
479            dac_channel_sample: 128,
480            lfo: LowFrequencyOscillator::new(),
481            selected_register: 0,
482            selected_register_group: RegisterGroup::default(),
483            sample_divider,
484            busy_cycles_remaining: 0,
485            timer_a: TimerA::new(),
486            timer_b: TimerB::new(),
487            csm_enabled: false,
488            quantize_output,
489            emulate_ladder_effect,
490            busy_behavior,
491            last_status_read: 0,
492            status_decay_samples_remaining: 0,
493            output_samples,
494        }
495    }
496
497    pub fn reset(&mut self) {
498        *self = Self::new_internal(
499            self.channels_muted,
500            self.quantize_output,
501            self.emulate_ladder_effect,
502            self.busy_behavior,
503            self.sample_divider,
504            mem::take(&mut self.output_samples),
505        );
506    }
507
508    // Set the address register and set group to 1 (system registers + channels 1-3)
509    pub fn write_address_1(&mut self, value: u8) {
510        self.selected_register = value;
511        self.selected_register_group = RegisterGroup::One;
512    }
513
514    // Set the address register and set group to 2 (channels 4-6)
515    pub fn write_address_2(&mut self, value: u8) {
516        self.selected_register = value;
517        self.selected_register_group = RegisterGroup::Two;
518    }
519
520    // Write to the data port
521    // Whether this is a group 1 or 2 write depends solely on which address register was last written
522    pub fn write_data(&mut self, value: u8) {
523        match self.selected_register_group {
524            RegisterGroup::One => self.write_group_1_register(value),
525            RegisterGroup::Two => self.write_group_2_register(value),
526        }
527    }
528
529    // Write to the data port for group 1 (system registers + channels 1-3)
530    fn write_group_1_register(&mut self, value: u8) {
531        if self.selected_register != 0x2A {
532            log::trace!("G1: Wrote {value:02X} to {:02X}", self.selected_register);
533        }
534
535        self.busy_cycles_remaining = WRITE_BUSY_CYCLES;
536
537        let register = self.selected_register;
538        match register {
539            0x22 => {
540                // LFO configuration register
541                let lfo_enabled = value.bit(3);
542                self.lfo.set_enabled(lfo_enabled);
543
544                let lfo_frequency = value & 0x07;
545                self.lfo.set_frequency(lfo_frequency);
546
547                log::trace!("LFO enabled: {lfo_enabled}");
548                log::trace!("LFO frequency: {lfo_frequency}");
549            }
550            0x24 => {
551                // Timer A interval bits 9-2
552                self.timer_a.write_interval_high(value);
553
554                log::trace!("Timer A interval: {}", self.timer_a.interval());
555            }
556            0x25 => {
557                // Timer A interval bits 1-0
558                self.timer_a.write_interval_low(value);
559
560                log::trace!("Timer A interval: {}", self.timer_a.interval());
561            }
562            0x26 => {
563                // Timer B interval
564                self.timer_b.interval = value;
565
566                log::trace!("Timer B interval: {}", self.timer_b.interval);
567            }
568            0x27 => {
569                // Channel 3 mode + timer control
570                let mode =
571                    if value & 0xC0 != 0 { FrequencyMode::Multiple } else { FrequencyMode::Single };
572                self.csm_enabled = value & 0xC0 == 0x80;
573
574                // Mode applies only to channel 3
575                let channel = &mut self.channels[2];
576                channel.mode = mode;
577                channel.update_phase_generators();
578
579                self.timer_a.write_control(TimerControl {
580                    enabled: value.bit(0),
581                    overflow_flag_enabled: value.bit(2),
582                    clear_overflow_flag: value.bit(4),
583                });
584
585                self.timer_b.write_control(TimerControl {
586                    enabled: value.bit(1),
587                    overflow_flag_enabled: value.bit(3),
588                    clear_overflow_flag: value.bit(5),
589                });
590
591                log::trace!("Channel 3 frequency mode: {mode:?}");
592                log::trace!("CSM enabled: {}", self.csm_enabled);
593                log::trace!("Timer A state: {:?}", self.timer_a);
594                log::trace!("Timer B state: {:?}", self.timer_b);
595            }
596            0x28 => {
597                let base_channel =
598                    if value.bit(2) { GROUP_2_BASE_CHANNEL } else { GROUP_1_BASE_CHANNEL };
599                let offset = value & 0x03;
600                if offset < 3 {
601                    let channel_idx = base_channel + (value & 0x03) as usize;
602                    let channel = &mut self.channels[channel_idx];
603                    channel.operators[0].key_on_or_off(value.bit(4));
604                    channel.operators[1].key_on_or_off(value.bit(5));
605                    channel.operators[2].key_on_or_off(value.bit(6));
606                    channel.operators[3].key_on_or_off(value.bit(7));
607
608                    log::trace!("Key on/off for channel {}: {:02X}", channel_idx + 1, value >> 4);
609                }
610            }
611            0x2A => {
612                self.dac_channel_sample = value;
613            }
614            0x2B => {
615                self.dac_channel_enabled = value.bit(7);
616                log::trace!("PCM enabled: {}", self.dac_channel_enabled);
617            }
618            0x30..=0x9F => {
619                self.write_operator_level_register(register, value, GROUP_1_BASE_CHANNEL);
620            }
621            0xA0..=0xBF => {
622                self.write_channel_level_register(register, value, GROUP_1_BASE_CHANNEL);
623            }
624            _ => {}
625        }
626    }
627
628    // Write to the data port for group 2 (channels 4-6)
629    fn write_group_2_register(&mut self, value: u8) {
630        log::trace!("G2: Wrote {value:02X} to {:02X}", self.selected_register);
631
632        self.busy_cycles_remaining = WRITE_BUSY_CYCLES;
633
634        let register = self.selected_register;
635        match register {
636            0x30..=0x9F => {
637                self.write_operator_level_register(register, value, GROUP_2_BASE_CHANNEL);
638            }
639            0xA0..=0xBF => {
640                self.write_channel_level_register(register, value, GROUP_2_BASE_CHANNEL);
641            }
642            _ => {}
643        }
644    }
645
646    #[allow(clippy::unused_self)]
647    #[must_use]
648    pub fn read_register(&mut self, address: u16) -> u8 {
649        if self.busy_behavior == Opn2BusyBehavior::Ym2612 && address & 3 != 0 {
650            // On YM2612, reads from $4001-$4003 return the last value read from $4000
651            // Status value decays to 0 after a certain amount of time has passed
652            return if self.status_decay_samples_remaining != 0 {
653                self.last_status_read
654            } else {
655                0
656            };
657        }
658
659        let busy_flag = match self.busy_behavior {
660            Opn2BusyBehavior::AlwaysZero => false,
661            Opn2BusyBehavior::Ym2612 | Opn2BusyBehavior::Ym3438 => self.busy_cycles_remaining != 0,
662        };
663
664        let status = (u8::from(busy_flag) << 7)
665            | (u8::from(self.timer_b.overflow_flag()) << 1)
666            | u8::from(self.timer_a.overflow_flag());
667
668        // 12000 sample decay period produces a result similar to actual YM2612 hardware, though from
669        // limited testing the decay period can vary even on a single console
670        self.status_decay_samples_remaining = 12000;
671        self.last_status_read = status;
672
673        status
674    }
675
676    #[inline]
677    pub fn tick(&mut self, ticks: u32) {
678        for _ in 0..ticks {
679            self.busy_cycles_remaining = self.busy_cycles_remaining.saturating_sub(1);
680
681            self.sample_divider -= 1;
682            if self.sample_divider == 0 {
683                self.sample_divider = FM_SAMPLE_DIVIDER;
684
685                self.status_decay_samples_remaining =
686                    self.status_decay_samples_remaining.saturating_sub(1);
687
688                self.lfo.tick();
689
690                self.timer_b.tick();
691                let timer_a_effect = self.timer_a.tick();
692
693                if self.csm_enabled && timer_a_effect == TimerTickEffect::Overflowed {
694                    // CSM: Whenever Timer A overflows, instantaneously key on & off all operators in
695                    // channel 3 that are not already keyed on
696                    for operator in &mut self.channels[2].operators {
697                        if !operator.envelope.is_key_on() {
698                            operator.key_on_or_off(true);
699                            operator.key_on_or_off(false);
700                        }
701                    }
702                }
703
704                self.clock();
705                self.output_samples.push(self.sample());
706            }
707        }
708    }
709
710    #[must_use]
711    pub fn sample(&self) -> (f64, f64) {
712        let mut sum_l = 0;
713        let mut sum_r = 0;
714        for (i, channel) in self.channels.iter().enumerate() {
715            if self.channels_muted[i] {
716                continue;
717            }
718
719            let sample = if i == 5 && self.dac_channel_enabled {
720                // Channel 6 is in DAC mode; play PCM sample instead of FM output
721                // Convert unsigned 8-bit sample to a signed 14-bit sample
722                (i16::from(self.dac_channel_sample) - 128) << 6
723            } else {
724                channel.current_output
725            };
726
727            let sample_l = self.apply_panning(sample, channel.l_output);
728            let sample_r = self.apply_panning(sample, channel.r_output);
729
730            sum_l += i32::from(sample_l);
731            sum_r += i32::from(sample_r);
732        }
733
734        // Each channel has a range of [-8192, 8191], so divide the sums by 6*8192 to convert to [-1.0, 1.0]
735        (f64::from(sum_l) / 49152.0, f64::from(sum_r) / 49152.0)
736    }
737
738    pub fn drain_output_samples(&mut self) -> impl Iterator<Item = (f64, f64)> {
739        self.output_samples.drain(..)
740    }
741
742    fn apply_panning(&self, sample: i16, pan_enabled: bool) -> i16 {
743        let pan_enabled: i16 = pan_enabled.into();
744
745        if !self.emulate_ladder_effect {
746            return sample * pan_enabled;
747        }
748
749        // Ladder effect emulation
750        // If channel is not muted through panning, add +4 to non-negative samples and -3 to negative
751        // If muted, output a constant +4 for non-negative samples and -4 for negative
752        // See https://gendev.spritesmind.net/forum/viewtopic.php?p=32605#p32605
753        let adjustment = if sample >= 0 { 4 } else { -(4 - pan_enabled) };
754
755        sample * pan_enabled + (adjustment << 5)
756    }
757
758    fn write_operator_level_register(&mut self, register: u8, value: u8, base_channel_idx: usize) {
759        assert!((0x30..=0x9F).contains(&register));
760
761        let channel_offset = register & 0x03;
762        if channel_offset == 3 {
763            // Invalid; only 3 channels per group
764            return;
765        }
766
767        let channel_idx = base_channel_idx + channel_offset as usize;
768        // Operator comes from bits 2 and 3 of register, except swapped (01=Operator 3, 10=Operator 2)
769        let operator_idx = (((register & 0x08) >> 3) | ((register & 0x04) >> 1)) as usize;
770
771        log::trace!(
772            "Writing to operator-level register for channel {} / operator {}",
773            channel_idx + 1,
774            operator_idx + 1
775        );
776
777        let operator = &mut self.channels[channel_idx].operators[operator_idx];
778        match register >> 4 {
779            0x03 => {
780                operator.phase.multiple = value & 0x0F;
781                operator.phase.detune = (value >> 4) & 0x07;
782
783                log::trace!(
784                    "Multiple={}, detune={}",
785                    operator.phase.multiple,
786                    operator.phase.detune
787                );
788            }
789            0x04 => {
790                operator.envelope.total_level = value & 0x7F;
791
792                log::trace!("Total level={:02X}", operator.envelope.total_level);
793            }
794            0x05 => {
795                operator.envelope.attack_rate = value & 0x1F;
796                operator.update_key_scale(value >> 6);
797
798                log::trace!(
799                    "Attack rate={}, key scale={}, Rks={}",
800                    operator.envelope.attack_rate,
801                    operator.envelope.key_scale,
802                    operator.envelope.key_scale_rate
803                );
804            }
805            0x06 => {
806                operator.envelope.decay_rate = value & 0x1F;
807                operator.am_enabled = value.bit(7);
808
809                log::trace!(
810                    "Decay rate={}, AM enabled={}",
811                    operator.envelope.decay_rate,
812                    operator.am_enabled
813                );
814            }
815            0x07 => {
816                operator.envelope.sustain_rate = value & 0x1F;
817
818                log::trace!("Sustain rate={}", operator.envelope.sustain_rate);
819            }
820            0x08 => {
821                operator.envelope.release_rate = value & 0x0F;
822                operator.envelope.sustain_level = value >> 4;
823
824                log::trace!(
825                    "Release rate={}, sustain level={}",
826                    operator.envelope.release_rate,
827                    operator.envelope.sustain_level
828                );
829            }
830            0x09 => {
831                operator.envelope.write_ssg_register(value);
832            }
833            _ => unreachable!("register is in 0x30..=0x9F"),
834        }
835    }
836
837    fn write_channel_level_register(&mut self, register: u8, value: u8, base_channel_idx: usize) {
838        assert!((0xA0..=0xBF).contains(&register));
839
840        match register {
841            0xA0..=0xA2 => {
842                // F-number low bits
843                let channel_idx = base_channel_idx + (register & 0x03) as usize;
844                let channel = &mut self.channels[channel_idx];
845
846                channel.channel_f_number =
847                    u16::from_le_bytes([value, channel.pending_ch_f_number_high]);
848                channel.channel_block = channel.pending_ch_block;
849
850                channel.update_phase_generators();
851
852                log::trace!("Channel {}: F-num={:04X}", channel_idx + 1, channel.channel_f_number);
853            }
854            0xA4..=0xA6 => {
855                // F-number high bits and block
856                // Writes to this register do not take effect until low bits are written
857                let channel_idx = base_channel_idx + (register & 0x03) as usize;
858                let channel = &mut self.channels[channel_idx];
859                channel.pending_ch_f_number_high = value & 7;
860                channel.pending_ch_block = (value >> 3) & 7;
861
862                log::trace!(
863                    "Channel {}: F-num high bits {}, block {}",
864                    channel_idx + 1,
865                    channel.pending_ch_f_number_high,
866                    channel.pending_ch_block,
867                );
868            }
869            0xA8..=0xAA => {
870                // Operator-level F-number low bits for channel 3
871                let channel_idx = base_channel_idx + 2;
872                let operator_idx = match register {
873                    0xA8 => 2,
874                    0xA9 => 0,
875                    0xAA => 1,
876                    _ => unreachable!("nested match expressions"),
877                };
878                let channel = &mut self.channels[channel_idx];
879
880                let f_num_high = channel.pending_op_f_numbers_high[operator_idx];
881                channel.operator_f_numbers[operator_idx] = u16::from_le_bytes([value, f_num_high]);
882                channel.operator_blocks[operator_idx] = channel.pending_op_blocks[operator_idx];
883                if channel.mode == FrequencyMode::Multiple {
884                    channel.update_phase_generators();
885                }
886
887                log::trace!(
888                    "Set operator-level frequency for channel {} / operator {}: F-num={:04X}",
889                    channel_idx + 1,
890                    operator_idx + 1,
891                    channel.operator_f_numbers[operator_idx]
892                );
893            }
894            0xAC..=0xAE => {
895                // Operator-level F-number high bits and block for channel 3
896                // Writes to this register do not take effect until low bits are written
897                let channel_idx = base_channel_idx + 2;
898                let operator_idx = match register {
899                    0xAC => 2,
900                    0xAD => 0,
901                    0xAE => 1,
902                    _ => unreachable!("nested match expressions"),
903                };
904                let channel = &mut self.channels[channel_idx];
905                channel.pending_op_f_numbers_high[operator_idx] = value & 7;
906                channel.pending_op_blocks[operator_idx] = (value >> 3) & 7;
907
908                log::trace!(
909                    "Set operator-level frequency / block for channel {} / operator {}: F-num high bits {}, block {}",
910                    channel_idx + 1,
911                    operator_idx + 1,
912                    channel.pending_op_f_numbers_high[operator_idx],
913                    channel.pending_op_blocks[operator_idx],
914                );
915            }
916            0xB0..=0xB2 => {
917                // Algorithm and operator 1 feedback level
918                let channel_idx = base_channel_idx + (register & 0x03) as usize;
919                let channel = &mut self.channels[channel_idx];
920                channel.algorithm = value & 0x07;
921                channel.feedback_level = (value >> 3) & 0x07;
922
923                log::trace!(
924                    "Channel {}: Algorithm={}, feedback level={}",
925                    channel_idx + 1,
926                    channel.algorithm,
927                    channel.feedback_level
928                );
929            }
930            0xB4..=0xB6 => {
931                // Stereo control and LFO sensitivity
932                let channel_idx = base_channel_idx + (register & 0x03) as usize;
933                let channel = &mut self.channels[channel_idx];
934                channel.l_output = value.bit(7);
935                channel.r_output = value.bit(6);
936                channel.am_sensitivity = (value >> 4) & 0x03;
937                channel.fm_sensitivity = value & 0x07;
938
939                log::trace!(
940                    "Channel {}: L={}, R={}, AM sensitivity={}, FM sensitivity={}",
941                    channel_idx + 1,
942                    channel.l_output,
943                    channel.r_output,
944                    channel.am_sensitivity,
945                    channel.fm_sensitivity
946                );
947            }
948            _ => {}
949        }
950    }
951
952    #[inline]
953    fn clock(&mut self) {
954        let lfo_counter = self.lfo.counter();
955        let quantization_mask = if self.quantize_output {
956            // Simulate a 9-bit DAC by masking out the lowest 5 bits of the 14-bit channel outputs
957            !((1 << 5) - 1)
958        } else {
959            !0
960        };
961
962        for channel in &mut self.channels {
963            channel.clock(lfo_counter, quantization_mask);
964        }
965    }
966
967    pub fn reload_config(&mut self, config: &GenesisEmulatorConfig) {
968        self.channels_muted = config.channels_muted();
969        self.quantize_output = config.quantize_ym2612_output;
970        self.emulate_ladder_effect = config.emulate_ym2612_ladder_effect;
971        self.busy_behavior = config.opn2_busy_behavior;
972    }
973}
974
975#[cfg(test)]
976mod tests {
977    use super::*;
978
979    #[test]
980    fn ladder_effect() {
981        let ym2612 = Ym2612::new(&GenesisEmulatorConfig {
982            emulate_ym2612_ladder_effect: true,
983            ..GenesisEmulatorConfig::default()
984        });
985
986        // Zero; output +4
987        assert_eq!(4 << 5, ym2612.apply_panning(0, false));
988        assert_eq!(4 << 5, ym2612.apply_panning(0, true));
989
990        // Positive; output +4 when muted, add +4 when enabled
991        assert_eq!(4 << 5, ym2612.apply_panning(6 << 5, false));
992        assert_eq!(10 << 5, ym2612.apply_panning(6 << 5, true));
993
994        // Negative; output -4 when muted, add -3 when enabled
995        assert_eq!(-(4 << 5), ym2612.apply_panning(-(6 << 5), false));
996        assert_eq!(-(9 << 5), ym2612.apply_panning(-(6 << 5), true));
997    }
998
999    #[test]
1000    fn busy_flag_ym2612() {
1001        let mut ym2612 = Ym2612::new(&GenesisEmulatorConfig {
1002            opn2_busy_behavior: Opn2BusyBehavior::Ym2612,
1003            ..GenesisEmulatorConfig::default()
1004        });
1005
1006        let check_4001_4003 = |ym2612: &mut Ym2612, value: u8| {
1007            for address in 0x4001..=0x4003 {
1008                assert_eq!(ym2612.read_register(address) & 0x80, value);
1009            }
1010        };
1011
1012        // Write to a register
1013        ym2612.write_address_1(0x30);
1014        ym2612.write_data(0xFF);
1015
1016        // $4001-$4003 should read 0
1017        check_4001_4003(&mut ym2612, 0);
1018
1019        // Read from $4000 should have busy flag set
1020        assert_eq!(ym2612.read_register(0x4000) & 0x80, 0x80);
1021
1022        // $4001-$4003 should now read with the busy flag set
1023        check_4001_4003(&mut ym2612, 0x80);
1024
1025        // Tick for 40 internal cycles
1026        ym2612.tick(40);
1027
1028        // Busy flag should be clear by now, but $4001-$4003 should still read the old value
1029        check_4001_4003(&mut ym2612, 0x80);
1030
1031        // Read from $4000 should have busy flag clear
1032        assert_eq!(ym2612.read_register(0x4000) & 0x80, 0);
1033
1034        // $4001-$4003 should now have busy flag clear
1035        check_4001_4003(&mut ym2612, 0);
1036
1037        // Write to a register again
1038        ym2612.write_address_1(0x30);
1039        ym2612.write_data(0xFF);
1040
1041        // $4000 should now have busy flag set again
1042        assert_eq!(ym2612.read_register(0x4000) & 0x80, 0x80);
1043        check_4001_4003(&mut ym2612, 0x80);
1044
1045        // Tick for almost half a second's worth of cycles
1046        ym2612.tick(500000);
1047
1048        // Status value should have decayed to 0 by now
1049        check_4001_4003(&mut ym2612, 0);
1050        assert_eq!(ym2612.read_register(0x4000) & 0x80, 0);
1051    }
1052}