From 10ef61784a3ca608b88896fecb697aa6d1cdc87a Mon Sep 17 00:00:00 2001 From: transistor Date: Sun, 9 Apr 2023 13:11:45 -0700 Subject: [PATCH] Added ym2612 total level and start of envelope implementation --- emulator/core/src/host/audio.rs | 5 + emulator/core/src/interrupts.rs | 11 - emulator/core/src/system.rs | 1 - emulator/peripherals/yamaha/src/sn76489.rs | 30 +- emulator/peripherals/yamaha/src/ym2612.rs | 433 +++++++++++++++------ emulator/systems/genesis/src/system.rs | 4 +- todo.txt | 7 + 7 files changed, 350 insertions(+), 141 deletions(-) diff --git a/emulator/core/src/host/audio.rs b/emulator/core/src/host/audio.rs index 518e827..bc77fb6 100644 --- a/emulator/core/src/host/audio.rs +++ b/emulator/core/src/host/audio.rs @@ -158,3 +158,8 @@ impl Iterator for SkewedSquareWave { } } +#[inline] +pub fn db_to_gain(db: f32) -> f32 { + (10.0_f32).powf(db / 20.0) +} + diff --git a/emulator/core/src/interrupts.rs b/emulator/core/src/interrupts.rs index 1fd8b3e..69f7d80 100644 --- a/emulator/core/src/interrupts.rs +++ b/emulator/core/src/interrupts.rs @@ -4,7 +4,6 @@ use crate::devices::TransmutableBox; pub struct InterruptController { - target: Option, interrupts: Vec<(bool, u8)>, highest: u8, } @@ -12,7 +11,6 @@ pub struct InterruptController { impl Default for InterruptController { fn default() -> InterruptController { InterruptController { - target: None, interrupts: vec![(false, 0); 7], highest: 0, } @@ -20,15 +18,6 @@ impl Default for InterruptController { } impl InterruptController { - pub fn set_target(&mut self, dev: TransmutableBox) -> Result<(), Error> { - if self.target.is_some() { - return Err(Error::new("Interruptable device already set, and interrupt controller only supports one receiver")); - } - - self.target = Some(dev); - Ok(()) - } - pub fn set(&mut self, state: bool, priority: u8, number: u8) -> Result<(), Error> { self.interrupts[priority as usize].0 = state; self.interrupts[priority as usize].1 = number; diff --git a/emulator/core/src/system.rs b/emulator/core/src/system.rs index da1bc9d..6cee80b 100644 --- a/emulator/core/src/system.rs +++ b/emulator/core/src/system.rs @@ -74,7 +74,6 @@ impl System { } pub fn add_interruptable_device(&mut self, name: &str, device: TransmutableBox) -> Result<(), Error> { - self.interrupt_controller.borrow_mut().set_target(device.clone())?; self.try_queue_device(device.clone()); self.devices.insert(name.to_string(), device); Ok(()) diff --git a/emulator/peripherals/yamaha/src/sn76489.rs b/emulator/peripherals/yamaha/src/sn76489.rs index 1729248..0d1abc2 100644 --- a/emulator/peripherals/yamaha/src/sn76489.rs +++ b/emulator/peripherals/yamaha/src/sn76489.rs @@ -8,14 +8,14 @@ use moa_core::host::audio::{SquareWave}; const DEV_NAME: &str = "sn76489"; #[derive(Clone)] -pub struct ToneGenerator { +struct ToneGenerator { on: bool, attenuation: f32, wave: SquareWave, } impl ToneGenerator { - pub fn new(sample_rate: usize) -> Self { + fn new(sample_rate: usize) -> Self { Self { on: false, attenuation: 0.0, @@ -23,7 +23,7 @@ impl ToneGenerator { } } - pub fn set_attenuation(&mut self, attenuation: u8) { + fn set_attenuation(&mut self, attenuation: u8) { if attenuation == 0x0F { self.on = false; } else { @@ -33,20 +33,20 @@ impl ToneGenerator { info!("set attenuation to {} {}", self.attenuation, self.on); } - pub fn set_counter(&mut self, count: usize) { + fn set_counter(&mut self, count: usize) { let frequency = 3_579_545.0 / (count as f32 * 32.0); self.wave.set_frequency(frequency); info!("set frequency to {}", frequency); } - pub fn get_sample(&mut self) -> f32 { + fn get_sample(&mut self) -> f32 { self.wave.next().unwrap() / (self.attenuation + 1.0) } } #[derive(Clone)] -pub struct NoiseGenerator { +struct NoiseGenerator { on: bool, attenuation: f32, } @@ -61,7 +61,7 @@ impl Default for NoiseGenerator { } impl NoiseGenerator { - pub fn set_attenuation(&mut self, attenuation: u8) { + fn set_attenuation(&mut self, attenuation: u8) { if attenuation == 0x0F { self.on = false; } else { @@ -71,13 +71,13 @@ impl NoiseGenerator { info!("set attenuation to {} {}", self.attenuation, self.on); } - pub fn set_control(&mut self, _bits: u8) { + fn set_control(&mut self, _bits: u8) { //let frequency = 3_579_545.0 / (count as f32 * 32.0); //self.wave.set_frequency(frequency); //debug!("set frequency to {}", frequency); } - pub fn get_sample(&mut self) -> f32 { + fn get_sample(&mut self) -> f32 { // TODO this isn't implemented yet 0.0 } @@ -86,18 +86,20 @@ impl NoiseGenerator { pub struct Sn76489 { - pub first_byte: Option, - pub source: Box, - pub tones: Vec, - pub noise: NoiseGenerator, + clock_frequency: u32, + first_byte: Option, + source: Box, + tones: Vec, + noise: NoiseGenerator, } impl Sn76489 { - pub fn create(host: &mut H) -> Result { + pub fn create(host: &mut H, clock_frequency: u32) -> Result { let source = host.create_audio_source()?; let sample_rate = source.samples_per_second(); Ok(Self { + clock_frequency, first_byte: None, source, tones: vec![ToneGenerator::new(sample_rate); 3], diff --git a/emulator/peripherals/yamaha/src/ym2612.rs b/emulator/peripherals/yamaha/src/ym2612.rs index 41539ae..be8383c 100644 --- a/emulator/peripherals/yamaha/src/ym2612.rs +++ b/emulator/peripherals/yamaha/src/ym2612.rs @@ -3,16 +3,24 @@ use std::num::NonZeroU8; use std::collections::VecDeque; use moa_core::{debug, warn}; -use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable}; +use moa_core::{System, Error, Clock, ClockElapsed, Address, Addressable, Steppable, Transmutable}; use moa_core::host::{Host, Audio}; -use moa_core::host::audio::{SineWave}; +use moa_core::host::audio::{SineWave, db_to_gain}; const DEV_NAME: &str = "ym2612"; const CHANNELS: usize = 8; #[derive(Copy, Clone, Debug)] -pub enum OperatorAlgorithm { +enum EnvelopeState { + Attack, + Decay1, + Decay2, + Release, +} + +#[derive(Copy, Clone, Debug)] +enum OperatorAlgorithm { A0, A1, A2, @@ -25,148 +33,283 @@ pub enum OperatorAlgorithm { #[derive(Clone)] -pub struct Operator { - pub wave: SineWave, - pub frequency: f32, - pub multiplier: f32, +struct Operator { + wave: SineWave, + frequency: f32, + multiplier: f32, + total_level: f32, + + attack_rate: usize, + first_decay_rate: usize, + first_decay_level: usize, + second_decay_rate: usize, + release_rate: usize, + + envelope_state: EnvelopeState, + last_event: Clock, + envelope_gain: f32, } impl Operator { - pub fn new(sample_rate: usize) -> Self { + fn new(sample_rate: usize) -> Self { Self { wave: SineWave::new(400.0, sample_rate), frequency: 400.0, multiplier: 1.0, + total_level: 0.0, + + attack_rate: 0, + first_decay_rate: 0, + first_decay_level: 0, + second_decay_rate: 0, + release_rate: 0, + + envelope_state: EnvelopeState::Attack, + last_event: 0, + envelope_gain: 0.0, } } - pub fn set_frequency(&mut self, frequency: f32) { + fn set_frequency(&mut self, frequency: f32) { self.frequency = frequency; } - pub fn reset(&mut self) { + fn set_total_level(&mut self, db: f32) { + self.total_level = db_to_gain(db); + } + + fn set_attack_rate(&mut self, rate: usize) { + self.attack_rate = rate; + } + + fn set_first_decay_rate(&mut self, rate: usize) { + self.first_decay_rate = rate; + } + + fn set_first_decay_level(&mut self, rate: usize) { + self.first_decay_level = rate; + } + + fn set_second_decay_rate(&mut self, rate: usize) { + self.second_decay_rate = rate; + } + + fn set_release_rate(&mut self, rate: usize) { + self.release_rate = rate; + } + + fn notify_state_change(&mut self, state: bool, event_clock: Clock) { + self.last_event = event_clock; + if state { + self.envelope_state = EnvelopeState::Attack; + self.envelope_gain = 0.0; + } else { + self.envelope_state = EnvelopeState::Release; + } + } + + fn reset(&mut self) { self.wave.reset(); } - pub fn set_multiplier(&mut self, _frequency: f32, multiplier: f32) { + fn set_multiplier(&mut self, _frequency: f32, multiplier: f32) { self.multiplier = multiplier; } - pub fn get_sample(&mut self, modulator: f32) -> f32 { - // TODO this would need to take into account the volume and envelope + fn get_sample(&mut self, modulator: f32, event_clock: Clock) -> f32 { self.wave.set_frequency((self.frequency * self.multiplier) + modulator); - self.wave.next().unwrap() + let sample = self.wave.next().unwrap(); + + /* + let time_since_last = event_clock - self.last_event; + match self.envelope_state { + EnvelopeState::Attack => { + let gain = rate_to_gain(self.attack_rate, time_since_last).min(self.total_level); + if gain == self.total_level { + self.envelope_state = EnvelopeState::Decay1; + } + sample / gain + }, + EnvelopeState::Decay1 => { + let gain = (self.total_level - rate_to_gain(self.first_decay_rate, time_since_last)).max(self.total_level / 2.0); + if gain == self.total_level / 2.0 { + self.envelope_state = EnvelopeState::Decay2; + } + sample / gain + }, + EnvelopeState::Decay2 => { + let gain = (self.total_level / 2.0 - rate_to_gain(self.second_decay_rate, time_since_last)).max(0.0); + sample / gain + }, + EnvelopeState::Release => { + let gain = (self.total_level / 2.0 - rate_to_gain(self.release_rate, time_since_last)).max(0.0); + sample / gain + }, + } + */ + sample } } +fn rate_to_gain(rate: usize, event_clock: Clock) -> f32 { + event_clock as f32 * rate as f32 +} + #[derive(Clone)] -pub struct Channel { - pub operators: Vec, - pub on: u8, - pub base_frequency: f32, - pub algorithm: OperatorAlgorithm, +struct Channel { + operators: Vec, + on_state: u8, + next_on_state: u8, + base_frequency: f32, + algorithm: OperatorAlgorithm, } impl Channel { - pub fn new(sample_rate: usize) -> Self { + fn new(sample_rate: usize) -> Self { Self { operators: vec![Operator::new(sample_rate); 4], - on: 0, + on_state: 0, + next_on_state: 0, base_frequency: 0.0, algorithm: OperatorAlgorithm::A0, } } - pub fn set_frequency(&mut self, frequency: f32) { + fn set_frequency(&mut self, frequency: f32) { self.base_frequency = frequency; for operator in self.operators.iter_mut() { operator.set_frequency(frequency); } } - pub fn reset(&mut self) { + fn reset(&mut self) { for operator in self.operators.iter_mut() { operator.reset(); } } - pub fn get_sample(&mut self) -> f32 { + fn get_sample(&mut self, event_clock: Clock) -> f32 { + if self.on_state != self.next_on_state { + self.on_state = self.next_on_state; + for (i, operator) in self.operators.iter_mut().enumerate() { + operator.notify_state_change(((self.on_state >> i) & 0x01) != 0, event_clock); + } + } + + if self.on_state != 0 { + self.get_algorithm_sample(event_clock) + } else { + 0.0 + } + } + + fn get_algorithm_sample(&mut self, event_clock: Clock) -> f32 { match self.algorithm { OperatorAlgorithm::A0 => { - let modulator0 = self.operators[0].get_sample(0.0); - let modulator1 = self.operators[1].get_sample(modulator0); - let modulator2 = self.operators[2].get_sample(modulator1); - self.operators[3].get_sample(modulator2) + let modulator0 = self.operators[0].get_sample(0.0, event_clock); + let modulator1 = self.operators[1].get_sample(modulator0, event_clock); + let modulator2 = self.operators[2].get_sample(modulator1, event_clock); + self.operators[3].get_sample(modulator2, event_clock) }, OperatorAlgorithm::A1 => { - let sample1 = self.operators[0].get_sample(0.0) + self.operators[1].get_sample(0.0); - let sample2 = self.operators[2].get_sample(sample1); - self.operators[3].get_sample(sample2) + let sample1 = self.operators[0].get_sample(0.0, event_clock) + self.operators[1].get_sample(0.0, event_clock); + let sample2 = self.operators[2].get_sample(sample1, event_clock); + self.operators[3].get_sample(sample2, event_clock) }, OperatorAlgorithm::A2 => { - let sample1 = self.operators[1].get_sample(0.0); - let sample2 = self.operators[2].get_sample(sample1); - let sample3 = self.operators[0].get_sample(0.0) + sample2; - self.operators[3].get_sample(sample3) + let sample1 = self.operators[1].get_sample(0.0, event_clock); + let sample2 = self.operators[2].get_sample(sample1, event_clock); + let sample3 = self.operators[0].get_sample(0.0, event_clock) + sample2; + self.operators[3].get_sample(sample3, event_clock) }, OperatorAlgorithm::A3 => { - let sample1 = self.operators[0].get_sample(0.0); - let sample2 = self.operators[1].get_sample(sample1); - let sample3 = self.operators[2].get_sample(0.0); - self.operators[3].get_sample(sample2 + sample3) + let sample1 = self.operators[0].get_sample(0.0, event_clock); + let sample2 = self.operators[1].get_sample(sample1, event_clock); + let sample3 = self.operators[2].get_sample(0.0, event_clock); + self.operators[3].get_sample(sample2 + sample3, event_clock) }, OperatorAlgorithm::A4 => { - let sample1 = self.operators[0].get_sample(0.0); - let sample2 = self.operators[1].get_sample(sample1); - let sample3 = self.operators[2].get_sample(0.0); - let sample4 = self.operators[3].get_sample(sample3); + let sample1 = self.operators[0].get_sample(0.0, event_clock); + let sample2 = self.operators[1].get_sample(sample1, event_clock); + let sample3 = self.operators[2].get_sample(0.0, event_clock); + let sample4 = self.operators[3].get_sample(sample3, event_clock); sample2 + sample4 }, OperatorAlgorithm::A5 => { - let sample1 = self.operators[0].get_sample(0.0); - self.operators[1].get_sample(sample1) + self.operators[2].get_sample(sample1) + self.operators[3].get_sample(sample1) + let sample1 = self.operators[0].get_sample(0.0, event_clock); + self.operators[1].get_sample(sample1, event_clock) + self.operators[2].get_sample(sample1, event_clock) + self.operators[3].get_sample(sample1, event_clock) }, OperatorAlgorithm::A6 => { - let sample1 = self.operators[0].get_sample(0.0); - let sample2 = self.operators[1].get_sample(sample1); - sample2 + self.operators[2].get_sample(0.0) + self.operators[3].get_sample(0.0) + let sample1 = self.operators[0].get_sample(0.0, event_clock); + let sample2 = self.operators[1].get_sample(sample1, event_clock); + sample2 + self.operators[2].get_sample(0.0, event_clock) + self.operators[3].get_sample(0.0, event_clock) }, OperatorAlgorithm::A7 => { - self.operators[0].get_sample(0.0) - + self.operators[1].get_sample(0.0) - + self.operators[2].get_sample(0.0) - + self.operators[3].get_sample(0.0) + self.operators[0].get_sample(0.0, event_clock) + + self.operators[1].get_sample(0.0, event_clock) + + self.operators[2].get_sample(0.0, event_clock) + + self.operators[3].get_sample(0.0, event_clock) }, } } } +struct Dac { + enabled: bool, + samples: VecDeque, +} + +impl Default for Dac { + fn default() -> Self { + Self { + enabled: false, + samples: VecDeque::with_capacity(100), + } + } +} + +impl Dac { + fn add_sample(&mut self, sample: f32) { + self.samples.push_back(sample); + } + + fn get_sample(&mut self) -> f32 { + if let Some(data) = self.samples.pop_front() { + data + } else { + 0.0 + } + } +} + pub struct Ym2612 { - pub source: Box, - pub selected_reg_0: Option, - pub selected_reg_1: Option, + source: Box, + selected_reg_0: Option, + selected_reg_1: Option, - pub channels: Vec, - pub channel_frequencies: [(u8, u16); CHANNELS], + clock_frequency: u32, + event_clock_period: ClockElapsed, + channels: Vec, + channel_frequencies: [(u8, u16); CHANNELS], + dac: Dac, - pub dac_enabled: bool, - pub dac: VecDeque, + timer_a_enable: bool, + timer_a: u16, + timer_a_current: u16, + timer_a_overflow: bool, - pub timer_a_enable: bool, - pub timer_a: u16, - pub timer_a_current: u16, - pub timer_a_overflow: bool, + timer_b_enable: bool, + timer_b: u8, + timer_b_current: u8, + timer_b_overflow: bool, - pub timer_b_enable: bool, - pub timer_b: u8, - pub timer_b_current: u8, - pub timer_b_overflow: bool, + registers: Vec, } impl Ym2612 { - pub fn create(host: &mut H) -> Result { + pub fn create(host: &mut H, clock_frequency: u32) -> Result { let source = host.create_audio_source()?; let sample_rate = source.samples_per_second(); Ok(Self { @@ -174,11 +317,12 @@ impl Ym2612 { selected_reg_0: None, selected_reg_1: None, + clock_frequency, + event_clock_period: 3 * 144 * 1_000_000_000 / clock_frequency as ClockElapsed, channels: vec![Channel::new(sample_rate); 8], channel_frequencies: [(0, 0); CHANNELS], - dac_enabled: false, - dac: VecDeque::with_capacity(100), + dac: Dac::default(), timer_a_enable: false, timer_a: 0, @@ -189,10 +333,15 @@ impl Ym2612 { timer_b: 0, timer_b_current: 0, timer_b_overflow: false, + + registers: vec![0; 512], }) } - pub fn set_register(&mut self, bank: usize, reg: usize, data: u8) { + pub fn set_register(&mut self, bank: u8, reg: u8, data: u8) { + // Keep a copy for debugging purposes, and if the original values are needed + self.registers[bank as usize * 256 + reg as usize] = data; + //warn!("{}: set reg {}{:x} to {:x}", DEV_NAME, bank, reg, data); match reg { 0x24 => { @@ -211,23 +360,23 @@ impl Ym2612 { 0x28 => { let ch = (data as usize) & 0x07; - self.channels[ch].on = data >> 4; + self.channels[ch].next_on_state = data >> 4; self.channels[ch].reset(); }, 0x2a => { - if self.dac_enabled { + if self.dac.enabled { for _ in 0..3 { - self.dac.push_back(data); + self.dac.add_sample(((data as f32 - 128.0) / 255.0) * 2.0); } } }, 0x2b => { - self.dac_enabled = data & 0x80 != 0; + self.dac.enabled = data & 0x80 != 0; }, - reg if (reg & 0xF0) == 0x30 => { + reg if is_reg_range(reg, 0x30) => { let (ch, op) = get_ch_op(bank, reg); let multiplier = if data == 0 { 0.5 } else { (data & 0x0F) as f32 }; let frequency = self.channels[ch].base_frequency; @@ -235,8 +384,24 @@ impl Ym2612 { self.channels[ch].operators[op].set_multiplier(frequency, multiplier) }, + reg if is_reg_range(reg, 0x40) => { + let (ch, op) = get_ch_op(bank, reg); + // 0-127 is the attenuation, where 0 is the highest volume and 127 is the lowest, in 0.75 dB intervals + self.channels[ch].operators[op].set_total_level((data & 0x7F) as f32 * 0.75); + }, + + reg if is_reg_range(reg, 0x50) + || is_reg_range(reg, 0x60) + || is_reg_range(reg, 0x70) + || is_reg_range(reg, 0x80) + || is_reg_range(reg, 0x90) + => { + let (ch, op) = get_ch_op(bank, reg); + self.update_rates(ch, op); + }, + reg if (0xA0..=0xA2).contains(®) => { - let ch = (reg & 0x07) + (bank * 3); + let ch = get_ch(bank, reg); self.channel_frequencies[ch].1 = (self.channel_frequencies[ch].1 & 0xFF00) | data as u16; let frequency = fnumber_to_frequency(self.channel_frequencies[ch]); @@ -245,13 +410,13 @@ impl Ym2612 { }, reg if (0xA4..=0xA6).contains(®) => { - let ch = (reg & 0x07) - 4 + (bank * 3); + let ch = ((reg as usize) & 0x07) - 4 + ((bank as usize) * 3); self.channel_frequencies[ch].1 = (self.channel_frequencies[ch].1 & 0xFF) | ((data as u16) & 0x07) << 8; self.channel_frequencies[ch].0 = (data & 0x38) >> 3; }, reg if (0xB0..=0xB2).contains(®) => { - let ch = (reg & 0x07) + (bank * 3); + let ch = get_ch(bank, reg); self.channels[ch].algorithm = match data & 0x07 { 0 => OperatorAlgorithm::A0, 1 => OperatorAlgorithm::A1, @@ -270,59 +435,101 @@ impl Ym2612 { }, } } + + fn update_rates(&mut self, ch: usize, op: usize) { + let index = get_index(ch, op); + let keycode = self.registers[0xA0 + get_ch_index(ch)] >> 1; + let rate_scaling = self.registers[0x50 + index] & 0xC0 >> 6; + let attack_rate = self.registers[0x50 + index] & 0x1F; + let first_decay_rate = self.registers[0x60 + index] & 0x1F; + let first_decay_level = (self.registers[0x80 + index] & 0x0F) >> 4; + let second_decay_rate = self.registers[0x70 + index] & 0x1F; + let release_rate = self.registers[0x80 + index] & 0x0F; + + self.channels[ch].operators[op].set_attack_rate(calculate_rate(attack_rate, rate_scaling, keycode)); + self.channels[ch].operators[op].set_first_decay_rate(calculate_rate(first_decay_rate, rate_scaling, keycode)); + self.channels[ch].operators[op].set_first_decay_level(calculate_rate(first_decay_level, rate_scaling, keycode)); + self.channels[ch].operators[op].set_second_decay_rate(calculate_rate(second_decay_rate, rate_scaling, keycode)); + self.channels[ch].operators[op].set_release_rate(calculate_rate(release_rate, rate_scaling, keycode)); + } } -#[inline(always)] -pub fn fnumber_to_frequency(fnumber: (u8, u16)) -> f32 { +#[inline] +fn fnumber_to_frequency(fnumber: (u8, u16)) -> f32 { (fnumber.1 as f32 * 0.0264) * 2_u32.pow(fnumber.0 as u32) as f32 } -#[inline(always)] -pub fn get_ch_op(bank: usize, reg: usize) -> (usize, usize) { - let ch = (reg & 0x03) + (bank * 3); - let op = (reg & 0xC0) >> 2; +#[inline] +fn calculate_rate(rate: u8, rate_scaling: u8, keycode: u8) -> usize { + let scale = match rate_scaling { + 0 => 8, + 1 => 4, + 2 => 2, + 3 => 1, + _ => 8, // this shouldn't be possible + }; + + (2 * rate as usize + (keycode as usize / scale)).min(64) +} + +#[inline] +fn is_reg_range(reg: u8, base: u8) -> bool { + // There is no 4th channel in each of the groupings + reg >= base && reg <= base + 0x0F && (reg & 0x03) != 0x03 +} + +/// Get the channel and operator to target with a given register number +/// and bank number. Bank 0 refers to operators for channels 1-3, and +/// bank 1 refers to operators for channels 4-6. +#[inline] +fn get_ch_op(bank: u8, reg: u8) -> (usize, usize) { + let ch = ((reg as usize) & 0x03) + ((bank as usize) * 3); + let op = ((reg as usize) & 0x0C) >> 2; (ch, op) } +#[inline] +fn get_index(ch: usize, op: usize) -> usize { + let (bank, ch_l) = if ch < 3 { (0, ch) } else { (1, ch - 3) }; + (bank << 8) | op << 2 | ch +} + +#[inline] +fn get_ch(bank: u8, reg: u8) -> usize { + ((reg as usize) & 0x07) + ((bank as usize) * 3) +} + +#[inline] +fn get_ch_index(ch: usize) -> usize { + if ch < 3 { + ch + } else { + 0x100 + ch - 3 + } +} + impl Steppable for Ym2612 { fn step(&mut self, system: &System) -> Result { - // TODO since you expect this step function to be called every 1ms of simulated time - // you could assume that you should produce (sample_rate / 1000) samples - - //if self.sine.frequency < 2000.0 { - // self.sine.frequency += 1.0; - //} - - //let rate = self.source.samples_per_second(); - //self.source.write_samples(rate / 1000, &mut self.sine); - //println!("{}", self.sine.frequency); - - //if self.on { - // let rate = self.source.samples_per_second(); - // self.source.write_samples(rate / 1000, &mut self.sine); - //} - let rate = self.source.samples_per_second(); let available = self.source.space_available(); let samples = if available < rate / 1000 { available } else { rate / 1000 }; + let nanos_per_sample = 1_000_000_000 / rate; + //if self.source.space_available() >= samples { let mut buffer = vec![0.0; samples]; - for buffered_sample in buffer.iter_mut().take(samples) { + for (i, buffered_sample) in buffer.iter_mut().enumerate().take(samples) { + let event_clock = (system.clock + (i * nanos_per_sample) as Clock) / self.event_clock_period; let mut sample = 0.0; for ch in 0..6 { - if self.channels[ch].on != 0 { - sample += self.channels[ch].get_sample(); - } + sample += self.channels[ch].get_sample(event_clock); } - if self.dac_enabled { - if let Some(data) = self.dac.pop_front() { - sample += ((data as f32 - 128.0) / 255.0) * 2.0; - } - } else if self.channels[6].on != 0 { - sample += self.channels[6].get_sample(); + if self.dac.enabled { + sample += self.dac.get_sample(); + } else { + sample += self.channels[6].get_sample(event_clock); } *buffered_sample = sample.clamp(-1.0, 1.0); @@ -361,7 +568,7 @@ impl Addressable for Ym2612 { }, 1 => { if let Some(reg) = self.selected_reg_0 { - self.set_register(0, reg.get() as usize, data[0]); + self.set_register(0, reg.get(), data[0]); } }, 2 => { @@ -369,7 +576,7 @@ impl Addressable for Ym2612 { }, 3 => { if let Some(reg) = self.selected_reg_1 { - self.set_register(1, reg.get() as usize, data[0]); + self.set_register(1, reg.get(), data[0]); } }, _ => { diff --git a/emulator/systems/genesis/src/system.rs b/emulator/systems/genesis/src/system.rs index 13fe0cb..d96e630 100644 --- a/emulator/systems/genesis/src/system.rs +++ b/emulator/systems/genesis/src/system.rs @@ -70,8 +70,8 @@ pub fn build_genesis(host: &mut H, mut options: SegaGenesisOptions) -> // Build the Coprocessor's Bus let bank_register = Signal::new(0); let coproc_ram = wrap_transmutable(MemoryBlock::new(vec![0; 0x00002000])); - let coproc_ym_sound = wrap_transmutable(Ym2612::create(host)?); - let coproc_sn_sound = wrap_transmutable(Sn76489::create(host)?); + let coproc_ym_sound = wrap_transmutable(Ym2612::create(host, 7_670_454)?); + let coproc_sn_sound = wrap_transmutable(Sn76489::create(host, 3_579_545)?); let coproc_register = wrap_transmutable(CoprocessorBankRegister::new(bank_register.clone())); let coproc_area = wrap_transmutable(CoprocessorBankArea::new(bank_register, system.bus.clone())); diff --git a/todo.txt b/todo.txt index 6f2e2c0..b43e1c2 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,11 @@ +* the interrupt controller stuff is really not good. It should be more like busport, and connected to a device at startup (eg. create + interrupt controller, then create objects that use that controller and pass in values, maybe an option so that the controller doesn't + have to be hooked up, meaning hardware interrupts would not be used. + +* along with the interrupt stuff, I'm kind of thinking of packaging things a bit differently, like using a tuple struct for the rc refcell + transmutable abstraction, so that you can avoid the need for explicit borrows + * improve performance * should it be possible to reschedule multiple events at different intervals to reduce the times a given step function is called? Some have multiple clocks, or multiple things at different clocks, and making them each an event would mean they could be smaller and faster, but at