mirror of
https://github.com/transistorfet/moa.git
synced 2024-11-21 19:30:52 +00:00
Fixed audio glitch (but haven't cleaned up code)
This commit is contained in:
parent
749a9d2250
commit
f464bfa1e0
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
});
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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]);
|
||||
|
@ -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
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user