Fixed audio glitch (but haven't cleaned up code)

This commit is contained in:
transistor 2022-01-26 11:12:09 -08:00
parent 749a9d2250
commit f464bfa1e0
7 changed files with 257 additions and 72 deletions

View File

@ -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 it's written to the buffer (and overfills). Attempt to not write to the buffer means audio stops
when the source buffer is full 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

View File

@ -131,20 +131,23 @@ impl AudioSource {
} }
pub fn space_available(&self) -> usize { pub fn space_available(&self) -> usize {
self.buffer.free_space() self.buffer.free_space() / 2
} }
pub fn fill_with(&mut self, buffer: &[f32]) { pub fn fill_with(&mut self, buffer: &[f32]) {
for sample in buffer.iter() { if self.buffer.free_space() > buffer.len() * 2 {
// TODO this is here to keep it quiet for testing, but should be removed later for sample in buffer.iter() {
let sample = 0.5 * *sample; // TODO this is here to keep it quiet for testing, but should be removed later
self.buffer.insert(sample); let sample = 0.5 * *sample;
self.buffer.insert(sample); self.buffer.insert(sample);
if self.buffer.is_full() { self.buffer.insert(sample);
break;
} }
} }
self.flush();
}
pub fn flush(&mut self) {
if self.buffer.used_space() >= self.frame_size { if self.buffer.used_space() >= self.frame_size {
let mut locked_mixer = self.mixer.lock(); let mut locked_mixer = self.mixer.lock();
@ -176,8 +179,11 @@ impl Audio for AudioSource {
fn write_samples(&mut self, buffer: &[f32]) { fn write_samples(&mut self, buffer: &[f32]) {
self.fill_with(buffer); self.fill_with(buffer);
} }
}
fn flush(&mut self) {
self.flush();
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct AudioMixer { pub struct AudioMixer {

View File

@ -1,48 +1,55 @@
use std::sync::mpsc;
use moa_minifb; use moa_minifb;
use moa::peripherals::ym2612::{Ym2612}; use moa::peripherals::ym2612::{Ym2612};
use moa::peripherals::sn76489::{Sn76489};
use moa::error::Error; use moa::error::Error;
use moa::system::System; use moa::system::System;
use moa::host::gfx::Frame; use moa::host::gfx::Frame;
use moa::devices::{ClockElapsed, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable}; use moa::devices::{ClockElapsed, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable};
use moa::host::keys::{Key}; use moa::host::keys::{Key};
use moa::host::traits::{Host, HostData, WindowUpdater, KeyboardUpdater}; use moa::host::traits::{Host, HostData, KeyboardUpdater};
pub struct SynthControlsUpdater(HostData<bool>); pub struct SynthControlsUpdater(mpsc::Sender<(Key, bool)>);
impl KeyboardUpdater for SynthControlsUpdater { impl KeyboardUpdater for SynthControlsUpdater {
fn update_keyboard(&mut self, key: Key, state: bool) { fn update_keyboard(&mut self, key: Key, state: bool) {
match key { self.0.send((key, state)).unwrap();
Key::Enter => { self.0.set(state); if state { println!("start"); } },
_ => { },
}
} }
} }
struct SynthControl { struct SynthControl {
button: HostData<bool>, receiver: mpsc::Receiver<(Key, bool)>,
last: bool,
} }
impl SynthControl { impl SynthControl {
pub fn new(button: HostData<bool>) -> Self { pub fn new(receiver: mpsc::Receiver<(Key, bool)>) -> Self {
Self { Self {
button, receiver,
last: false,
} }
} }
} }
impl Steppable for SynthControl { impl Steppable for SynthControl {
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> { fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
let current = self.button.get(); if let Ok((key, state)) = self.receiver.try_recv() {
if current != self.last { match key {
self.last = current; Key::Enter => {
system.get_bus().write_u8(0x00, 0x28)?; system.get_bus().write_u8(0x00, 0x28)?;
system.get_bus().write_u8(0x01, if current { 0xF0 } else { 0x00 })?; 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) Ok(1_000_000)
@ -84,17 +91,20 @@ fn main() {
moa_minifb::run(matches, |host| { moa_minifb::run(matches, |host| {
let mut system = System::new(); let mut system = System::new();
let button = HostData::new(false); let (sender, receiver) = mpsc::channel();
let control = wrap_transmutable(SynthControl::new(button.clone())); let control = wrap_transmutable(SynthControl::new(receiver));
system.add_device("control", control)?; system.add_device("control", control)?;
let ym_sound = wrap_transmutable(Ym2612::create(host)?); let ym_sound = wrap_transmutable(Ym2612::create(host)?);
initialize_ym(ym_sound.clone())?; initialize_ym(ym_sound.clone())?;
system.add_addressable_device(0x00, ym_sound)?; 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); let frame = Frame::new_shared(384, 128);
host.add_window(Frame::new_updater(frame.clone()))?; host.add_window(Frame::new_updater(frame.clone()))?;
host.register_keyboard(Box::new(SynthControlsUpdater(button)))?; host.register_keyboard(Box::new(SynthControlsUpdater(sender)))?;
Ok(system) Ok(system)
}); });

View File

@ -18,6 +18,10 @@ impl SineWave {
} }
} }
pub fn set_frequency(&mut self, frequency: f32) {
self.frequency = frequency;
}
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.position = 0; 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) { pub fn reset(&mut self) {
self.position = 0; 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<f32> {
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)
}
}

View File

@ -51,6 +51,7 @@ pub trait Audio {
fn samples_per_second(&self) -> usize; fn samples_per_second(&self) -> usize;
fn space_available(&self) -> usize; fn space_available(&self) -> usize;
fn write_samples(&mut self, buffer: &[f32]); fn write_samples(&mut self, buffer: &[f32]);
fn flush(&mut self);
} }
pub trait BlitableSurface { pub trait BlitableSurface {

View File

@ -8,39 +8,94 @@ use crate::host::traits::{Host, Audio};
const DEV_NAME: &'static str = "sn76489"; 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 struct Sn76489 {
pub regs: [u8; 8], pub regs: [u8; 8],
pub first_byte: Option<u8>, pub first_byte: Option<u8>,
pub source: Box<dyn Audio>, pub source: Box<dyn Audio>,
pub sine: SquareWave, pub channels: Vec<Channel>,
} }
impl Sn76489 { impl Sn76489 {
pub fn create<H: Host>(host: &mut H) -> Result<Self, Error> { pub fn create<H: Host>(host: &mut H) -> Result<Self, Error> {
let source = host.create_audio_source()?; 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 { Ok(Self {
regs: [0; 8], regs: [0; 8],
first_byte: None, first_byte: None,
source, source,
sine, channels: vec![Channel::new(sample_rate); 3],
}) })
} }
} }
impl Steppable for Sn76489 { impl Steppable for Sn76489 {
fn step(&mut self, _system: &System) -> Result<ClockElapsed, Error> { fn step(&mut self, _system: &System) -> Result<ClockElapsed, Error> {
// TODO since you expect this step function to be called every 1ms of simulated time let rate = self.source.samples_per_second();
// you could assume that you should produce (sample_rate / 1000) samples let available = self.source.space_available();
let samples = if available < rate / 1000 { available } else { rate / 1000 };
if self.sine.frequency > 200.0 { if samples > 0 {
self.sine.frequency -= 1.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 Ok(1_000_000) // Every 1ms of simulated time
} }
} }
@ -62,13 +117,25 @@ impl Addressable for Sn76489 {
} }
if (data[0] & 0x80) == 0 { 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 { } else {
let reg = (data[0] & 0x70) >> 4; let reg = (data[0] & 0x70) >> 4;
if reg == 6 { self.first_byte = Some(data[0]);
self.first_byte = Some(data[0]); //self.regs[reg as usize] = data[0] & 0x0F;
} else { let attenuation = data[0] & 0x0F;
self.regs[reg as usize] = 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]); debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);

View File

@ -27,6 +27,7 @@ pub enum OperatorAlgorithm {
#[derive(Clone)] #[derive(Clone)]
pub struct Operator { pub struct Operator {
pub wave: SineWave, pub wave: SineWave,
pub frequency: f32,
pub multiplier: f32, pub multiplier: f32,
} }
@ -34,12 +35,13 @@ impl Operator {
pub fn new(sample_rate: usize) -> Self { pub fn new(sample_rate: usize) -> Self {
Self { Self {
wave: SineWave::new(400.0, sample_rate), wave: SineWave::new(400.0, sample_rate),
frequency: 400.0,
multiplier: 1.0, multiplier: 1.0,
} }
} }
pub fn set_frequency(&mut self, frequency: f32) { pub fn set_frequency(&mut self, frequency: f32) {
self.wave.frequency = frequency * self.multiplier; self.frequency = frequency;
} }
pub fn reset(&mut self) { pub fn reset(&mut self) {
@ -48,11 +50,11 @@ impl Operator {
pub fn set_multiplier(&mut self, frequency: f32, multiplier: f32) { pub fn set_multiplier(&mut self, frequency: f32, multiplier: f32) {
self.multiplier = multiplier; 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 // 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() self.wave.next().unwrap()
} }
} }
@ -91,46 +93,53 @@ impl Channel {
pub fn get_sample(&mut self) -> f32 { pub fn get_sample(&mut self) -> f32 {
match self.algorithm { match self.algorithm {
OperatorAlgorithm::A0 => { OperatorAlgorithm::A0 => {
self.operators[0].get_sample() let modulator0 = self.operators[0].get_sample(0.0);
* self.operators[1].get_sample() let modulator1 = self.operators[1].get_sample(modulator0);
* self.operators[2].get_sample() let modulator2 = self.operators[2].get_sample(modulator1);
* self.operators[3].get_sample() self.operators[3].get_sample(modulator2)
}, },
OperatorAlgorithm::A1 => { OperatorAlgorithm::A1 => {
let sample1 = (self.operators[0].get_sample() + self.operators[1].get_sample()) / 2.0; 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(); let sample2 = self.operators[2].get_sample(sample1);
let sample3 = self.operators[3].get_sample(); let sample3 = self.operators[3].get_sample(sample2);
sample1 * sample2 * sample3 sample3
}, },
OperatorAlgorithm::A2 => { OperatorAlgorithm::A2 => {
let mut sample = (self.operators[0].get_sample() + (self.operators[1].get_sample() * self.operators[2].get_sample())) / 2.0; let sample1 = self.operators[1].get_sample(0.0);
sample *= self.operators[3].get_sample(); let sample2 = self.operators[2].get_sample(sample1);
sample let sample3 = (self.operators[0].get_sample(0.0) + sample2) / 2.0;
let sample4 = self.operators[3].get_sample(sample3);
sample4
}, },
OperatorAlgorithm::A3 => { OperatorAlgorithm::A3 => {
let mut sample = ((self.operators[0].get_sample() * self.operators[1].get_sample()) + self.operators[2].get_sample()) / 2.0; let sample1 = self.operators[0].get_sample(0.0);
sample *= self.operators[3].get_sample(); let sample2 = self.operators[1].get_sample(sample1);
sample let sample3 = self.operators[2].get_sample(0.0);
let sample4 = self.operators[3].get_sample((sample2 + sample3) / 2.0);
sample4
}, },
OperatorAlgorithm::A4 => { OperatorAlgorithm::A4 => {
let sample1 = self.operators[0].get_sample() * self.operators[1].get_sample(); let sample1 = self.operators[0].get_sample(0.0);
let sample2 = self.operators[2].get_sample() * self.operators[3].get_sample(); let sample2 = self.operators[1].get_sample(sample1);
(sample1 + sample2) / 2.0 let sample3 = self.operators[2].get_sample(0.0);
let sample4 = self.operators[3].get_sample(sample3);
(sample2 + sample4) / 2.0
}, },
OperatorAlgorithm::A5 => { OperatorAlgorithm::A5 => {
let sample1 = self.operators[0].get_sample(); let sample1 = self.operators[0].get_sample(0.0);
let sample2 = (self.operators[1].get_sample() + self.operators[2].get_sample() + self.operators[3].get_sample()) / 3.0; let sample2 = (self.operators[1].get_sample(sample1) + self.operators[2].get_sample(sample1) + self.operators[3].get_sample(sample1)) / 3.0;
sample1 * sample2 sample2
}, },
OperatorAlgorithm::A6 => { OperatorAlgorithm::A6 => {
let sample1 = self.operators[0].get_sample() * self.operators[1].get_sample(); let sample1 = self.operators[0].get_sample(0.0);
(sample1 + self.operators[2].get_sample() + self.operators[3].get_sample()) / 3.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 => { OperatorAlgorithm::A7 => {
let sample = self.operators[0].get_sample() let sample = self.operators[0].get_sample(0.0)
+ self.operators[1].get_sample() + self.operators[1].get_sample(0.0)
+ self.operators[2].get_sample() + self.operators[2].get_sample(0.0)
+ self.operators[3].get_sample(); + self.operators[3].get_sample(0.0);
sample / 4.0 sample / 4.0
}, },
} }