diff --git a/docs/log.txt b/docs/log.txt index 7c8d67d..039c78e 100644 --- a/docs/log.txt +++ b/docs/log.txt @@ -267,6 +267,11 @@ Audio when it's written to the buffer (and overfills). Attempt to not write to the buffer means audio stops when the source buffer is full +2022-01-24 +- finally took another look and the glitching turned out to be an issue with the buffer size where the + check before the audio devices write only account for one channel of audio instead of two, so the + buffer was over filling. Dividing the available buffer size by 2 fixed it + diff --git a/frontends/moa-common/src/audio.rs b/frontends/moa-common/src/audio.rs index b4a1a15..3e53d11 100644 --- a/frontends/moa-common/src/audio.rs +++ b/frontends/moa-common/src/audio.rs @@ -131,20 +131,23 @@ impl AudioSource { } pub fn space_available(&self) -> usize { - self.buffer.free_space() + self.buffer.free_space() / 2 } pub fn fill_with(&mut self, buffer: &[f32]) { - for sample in buffer.iter() { - // TODO this is here to keep it quiet for testing, but should be removed later - let sample = 0.5 * *sample; - self.buffer.insert(sample); - self.buffer.insert(sample); - if self.buffer.is_full() { - break; + if self.buffer.free_space() > buffer.len() * 2 { + for sample in buffer.iter() { + // TODO this is here to keep it quiet for testing, but should be removed later + let sample = 0.5 * *sample; + self.buffer.insert(sample); + self.buffer.insert(sample); } } + self.flush(); + } + + pub fn flush(&mut self) { if self.buffer.used_space() >= self.frame_size { let mut locked_mixer = self.mixer.lock(); @@ -176,8 +179,11 @@ impl Audio for AudioSource { fn write_samples(&mut self, buffer: &[f32]) { self.fill_with(buffer); } -} + fn flush(&mut self) { + self.flush(); + } +} #[derive(Clone)] pub struct AudioMixer { diff --git a/frontends/moa-minifb/src/bin/moa-ym2612.rs b/frontends/moa-minifb/src/bin/moa-ym2612.rs index cf881d4..5fa50f2 100644 --- a/frontends/moa-minifb/src/bin/moa-ym2612.rs +++ b/frontends/moa-minifb/src/bin/moa-ym2612.rs @@ -1,48 +1,55 @@ +use std::sync::mpsc; + use moa_minifb; use moa::peripherals::ym2612::{Ym2612}; +use moa::peripherals::sn76489::{Sn76489}; use moa::error::Error; use moa::system::System; use moa::host::gfx::Frame; use moa::devices::{ClockElapsed, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable}; use moa::host::keys::{Key}; -use moa::host::traits::{Host, HostData, WindowUpdater, KeyboardUpdater}; +use moa::host::traits::{Host, HostData, KeyboardUpdater}; -pub struct SynthControlsUpdater(HostData); +pub struct SynthControlsUpdater(mpsc::Sender<(Key, bool)>); impl KeyboardUpdater for SynthControlsUpdater { fn update_keyboard(&mut self, key: Key, state: bool) { - match key { - Key::Enter => { self.0.set(state); if state { println!("start"); } }, - _ => { }, - } + self.0.send((key, state)).unwrap(); } } struct SynthControl { - button: HostData, - last: bool, + receiver: mpsc::Receiver<(Key, bool)>, } impl SynthControl { - pub fn new(button: HostData) -> Self { + pub fn new(receiver: mpsc::Receiver<(Key, bool)>) -> Self { Self { - button, - last: false, + receiver, } } } impl Steppable for SynthControl { fn step(&mut self, system: &System) -> Result { - let current = self.button.get(); + if let Ok((key, state)) = self.receiver.try_recv() { - if current != self.last { - self.last = current; - system.get_bus().write_u8(0x00, 0x28)?; - system.get_bus().write_u8(0x01, if current { 0xF0 } else { 0x00 })?; + match key { + Key::Enter => { + system.get_bus().write_u8(0x00, 0x28)?; + system.get_bus().write_u8(0x01, if state { 0xF0 } else { 0x00 })?; + }, + + Key::A => { + system.get_bus().write_u8(0x10, 0x84)?; + system.get_bus().write_u8(0x10, 0x0F)?; + system.get_bus().write_u8(0x10, if state { 0x90 } else { 0x9F })?; + }, + _ => { }, + } } Ok(1_000_000) @@ -84,17 +91,20 @@ fn main() { moa_minifb::run(matches, |host| { let mut system = System::new(); - let button = HostData::new(false); - let control = wrap_transmutable(SynthControl::new(button.clone())); + let (sender, receiver) = mpsc::channel(); + let control = wrap_transmutable(SynthControl::new(receiver)); system.add_device("control", control)?; let ym_sound = wrap_transmutable(Ym2612::create(host)?); initialize_ym(ym_sound.clone())?; system.add_addressable_device(0x00, ym_sound)?; + let sn_sound = wrap_transmutable(Sn76489::create(host)?); + system.add_addressable_device(0x10, sn_sound)?; + let frame = Frame::new_shared(384, 128); host.add_window(Frame::new_updater(frame.clone()))?; - host.register_keyboard(Box::new(SynthControlsUpdater(button)))?; + host.register_keyboard(Box::new(SynthControlsUpdater(sender)))?; Ok(system) }); diff --git a/src/host/audio.rs b/src/host/audio.rs index ecebfca..de1f5ff 100644 --- a/src/host/audio.rs +++ b/src/host/audio.rs @@ -18,6 +18,10 @@ impl SineWave { } } + pub fn set_frequency(&mut self, frequency: f32) { + self.frequency = frequency; + } + pub fn reset(&mut self) { self.position = 0; } @@ -49,6 +53,10 @@ impl SquareWave { } } + pub fn set_frequency(&mut self, frequency: f32) { + self.frequency = frequency; + } + pub fn reset(&mut self) { self.position = 0; } @@ -65,3 +73,82 @@ impl Iterator for SquareWave { } } + + +#[derive(Copy, Clone)] +pub enum SkewedSquareWaveStage { + Rising, + Positive, + Falling, + Negative, +} + +#[derive(Clone)] +pub struct SkewedSquareWave { + pub stage: SkewedSquareWaveStage, + pub frequency: f32, + pub skew: f32, + pub sample_rate: usize, + pub position: usize, + pub sample: f32, +} + +impl SkewedSquareWave { + pub fn new(frequency: f32, sample_rate: usize) -> Self { + Self { + stage: SkewedSquareWaveStage::Rising, + frequency, + skew: 0.1, + sample_rate, + position: 0, + sample: 0.0, + } + } + + pub fn set_frequency(&mut self, frequency: f32) { + self.frequency = frequency; + } + + pub fn reset(&mut self) { + self.stage = SkewedSquareWaveStage::Rising; + self.position = 0; + } +} + +impl Iterator for SkewedSquareWave { + type Item = f32; + + fn next(&mut self) -> Option { + let samples_per_hz = self.sample_rate as f32 / self.frequency; + self.position += 1; + + match self.stage { + SkewedSquareWaveStage::Rising => { + self.sample += self.skew; + if self.sample >= 1.0 { + self.sample = 1.0; + self.stage = SkewedSquareWaveStage::Positive; + } + }, + SkewedSquareWaveStage::Positive => { + if (self.position as f32 % samples_per_hz) >= (samples_per_hz / 2.0) { + self.stage = SkewedSquareWaveStage::Falling; + } + }, + SkewedSquareWaveStage::Falling => { + self.sample -= self.skew; + if self.sample <= -1.0 { + self.sample = -1.0; + self.stage = SkewedSquareWaveStage::Negative; + } + }, + SkewedSquareWaveStage::Negative => { + if (self.position as f32 % samples_per_hz) < (samples_per_hz / 2.0) { + self.stage = SkewedSquareWaveStage::Rising; + } + }, + } + Some(self.sample) + } +} + diff --git a/src/host/traits.rs b/src/host/traits.rs index afda639..f86cb01 100644 --- a/src/host/traits.rs +++ b/src/host/traits.rs @@ -51,6 +51,7 @@ pub trait Audio { fn samples_per_second(&self) -> usize; fn space_available(&self) -> usize; fn write_samples(&mut self, buffer: &[f32]); + fn flush(&mut self); } pub trait BlitableSurface { diff --git a/src/peripherals/sn76489.rs b/src/peripherals/sn76489.rs index 442333b..b5133f3 100644 --- a/src/peripherals/sn76489.rs +++ b/src/peripherals/sn76489.rs @@ -8,39 +8,94 @@ use crate::host::traits::{Host, Audio}; const DEV_NAME: &'static str = "sn76489"; +#[derive(Clone)] +pub struct Channel { + on: bool, + attenuation: f32, + wave: SquareWave, +} + +impl Channel { + pub fn new(sample_rate: usize) -> Self { + Self { + on: false, + attenuation: 0.0, + wave: SquareWave::new(600.0, sample_rate), + } + } + + pub fn set_attenuation(&mut self, attenuation: u8) { + if attenuation == 0x0F { + self.on = false; + } else { + self.on = true; + self.attenuation = (attenuation << 1) as f32; + } + println!("set attenuation to {} {}", self.attenuation, self.on); + } + + pub fn set_counter(&mut self, count: usize) { + let frequency = 3_579_545.0 / (count as f32 * 32.0); + self.wave.set_frequency(frequency); + println!("set frequency to {}", frequency); + } + + pub fn get_sample(&mut self) -> f32 { + self.wave.next().unwrap() + } +} + + pub struct Sn76489 { pub regs: [u8; 8], pub first_byte: Option, pub source: Box, - pub sine: SquareWave, + pub channels: Vec, } impl Sn76489 { pub fn create(host: &mut H) -> Result { let source = host.create_audio_source()?; - let sine = SquareWave::new(600.0, source.samples_per_second()); + let sample_rate = source.samples_per_second(); Ok(Self { regs: [0; 8], first_byte: None, source, - sine, + channels: vec![Channel::new(sample_rate); 3], }) } } impl Steppable for Sn76489 { 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 + let rate = self.source.samples_per_second(); + let available = self.source.space_available(); + let samples = if available < rate / 1000 { available } else { rate / 1000 }; - if self.sine.frequency > 200.0 { - self.sine.frequency -= 1.0; + if samples > 0 { + //if available >= rate / 1000 { + let mut buffer = vec![0.0; samples]; + for i in 0..samples { + let mut sample = 0.0; + let mut count = 0; + + for ch in 0..3 { + if self.channels[ch].on { + sample += self.channels[ch].get_sample(); + count += 1; + } + } + + if count > 0 { + buffer[i] = sample / count as f32; + } + } + self.source.write_samples(&buffer); + } else { + self.source.flush(); } - //let rate = self.source.samples_per_second(); - //self.source.write_samples(rate / 1000, &mut self.sine); - //println!("{}", self.sine.frequency); Ok(1_000_000) // Every 1ms of simulated time } } @@ -62,13 +117,25 @@ impl Addressable for Sn76489 { } if (data[0] & 0x80) == 0 { - // TODO update noise byte + let first = self.first_byte.unwrap_or(0); + let reg = (first & 0x70) >> 4; + let value = ((data[0] as usize & 0x3F) << 4) | (first as usize & 0x0F); + match reg { + 0 => self.channels[0].set_counter(value), + 2 => self.channels[1].set_counter(value), + 4 => self.channels[2].set_counter(value), + _ => { }, + } } else { let reg = (data[0] & 0x70) >> 4; - if reg == 6 { - self.first_byte = Some(data[0]); - } else { - self.regs[reg as usize] = data[0] & 0x0F; + self.first_byte = Some(data[0]); + //self.regs[reg as usize] = data[0] & 0x0F; + let attenuation = data[0] & 0x0F; + match reg { + 1 => self.channels[0].set_attenuation(attenuation), + 3 => self.channels[1].set_attenuation(attenuation), + 5 => self.channels[2].set_attenuation(attenuation), + _ => { }, } } debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]); diff --git a/src/peripherals/ym2612.rs b/src/peripherals/ym2612.rs index 6b84320..2bf35ad 100644 --- a/src/peripherals/ym2612.rs +++ b/src/peripherals/ym2612.rs @@ -27,6 +27,7 @@ pub enum OperatorAlgorithm { #[derive(Clone)] pub struct Operator { pub wave: SineWave, + pub frequency: f32, pub multiplier: f32, } @@ -34,12 +35,13 @@ impl Operator { pub fn new(sample_rate: usize) -> Self { Self { wave: SineWave::new(400.0, sample_rate), + frequency: 400.0, multiplier: 1.0, } } pub fn set_frequency(&mut self, frequency: f32) { - self.wave.frequency = frequency * self.multiplier; + self.frequency = frequency; } pub fn reset(&mut self) { @@ -48,11 +50,11 @@ impl Operator { pub fn set_multiplier(&mut self, frequency: f32, multiplier: f32) { self.multiplier = multiplier; - self.set_frequency(frequency); } - pub fn get_sample(&mut self) -> f32 { + pub fn get_sample(&mut self, modulator: f32) -> f32 { // TODO this would need to take into account the volume and envelope + self.wave.set_frequency((self.frequency * self.multiplier) + modulator); self.wave.next().unwrap() } } @@ -91,46 +93,53 @@ impl Channel { pub fn get_sample(&mut self) -> f32 { match self.algorithm { OperatorAlgorithm::A0 => { - self.operators[0].get_sample() - * self.operators[1].get_sample() - * self.operators[2].get_sample() - * self.operators[3].get_sample() + 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) }, OperatorAlgorithm::A1 => { - let sample1 = (self.operators[0].get_sample() + self.operators[1].get_sample()) / 2.0; - let sample2 = self.operators[2].get_sample(); - let sample3 = self.operators[3].get_sample(); - sample1 * sample2 * sample3 + let sample1 = (self.operators[0].get_sample(0.0) + self.operators[1].get_sample(0.0)) / 2.0; + let sample2 = self.operators[2].get_sample(sample1); + let sample3 = self.operators[3].get_sample(sample2); + sample3 }, OperatorAlgorithm::A2 => { - let mut sample = (self.operators[0].get_sample() + (self.operators[1].get_sample() * self.operators[2].get_sample())) / 2.0; - sample *= self.operators[3].get_sample(); - sample + 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) / 2.0; + let sample4 = self.operators[3].get_sample(sample3); + sample4 }, OperatorAlgorithm::A3 => { - let mut sample = ((self.operators[0].get_sample() * self.operators[1].get_sample()) + self.operators[2].get_sample()) / 2.0; - sample *= self.operators[3].get_sample(); - sample + 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((sample2 + sample3) / 2.0); + sample4 }, OperatorAlgorithm::A4 => { - let sample1 = self.operators[0].get_sample() * self.operators[1].get_sample(); - let sample2 = self.operators[2].get_sample() * self.operators[3].get_sample(); - (sample1 + sample2) / 2.0 + 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); + (sample2 + sample4) / 2.0 }, OperatorAlgorithm::A5 => { - let sample1 = self.operators[0].get_sample(); - let sample2 = (self.operators[1].get_sample() + self.operators[2].get_sample() + self.operators[3].get_sample()) / 3.0; - sample1 * sample2 + let sample1 = self.operators[0].get_sample(0.0); + let sample2 = (self.operators[1].get_sample(sample1) + self.operators[2].get_sample(sample1) + self.operators[3].get_sample(sample1)) / 3.0; + sample2 }, OperatorAlgorithm::A6 => { - let sample1 = self.operators[0].get_sample() * self.operators[1].get_sample(); - (sample1 + self.operators[2].get_sample() + self.operators[3].get_sample()) / 3.0 + 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)) / 3.0 }, OperatorAlgorithm::A7 => { - let sample = self.operators[0].get_sample() - + self.operators[1].get_sample() - + self.operators[2].get_sample() - + self.operators[3].get_sample(); + let sample = 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); sample / 4.0 }, }