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 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 {
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 {

View File

@ -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<bool>);
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<bool>,
last: bool,
receiver: mpsc::Receiver<(Key, bool)>,
}
impl SynthControl {
pub fn new(button: HostData<bool>) -> 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<ClockElapsed, Error> {
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)
});

View File

@ -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<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 space_available(&self) -> usize;
fn write_samples(&mut self, buffer: &[f32]);
fn flush(&mut self);
}
pub trait BlitableSurface {

View File

@ -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<u8>,
pub source: Box<dyn Audio>,
pub sine: SquareWave,
pub channels: Vec<Channel>,
}
impl Sn76489 {
pub fn create<H: Host>(host: &mut H) -> Result<Self, Error> {
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<ClockElapsed, Error> {
// 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]);

View File

@ -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
},
}