2021-12-06 22:51:57 +00:00
|
|
|
|
2022-10-09 16:40:20 +00:00
|
|
|
use moa_core::{info, warn, debug};
|
2022-09-25 06:14:03 +00:00
|
|
|
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable};
|
|
|
|
use moa_core::host::{Host, Audio};
|
|
|
|
use moa_core::host::audio::{SquareWave};
|
2021-12-12 23:20:09 +00:00
|
|
|
|
2021-12-06 22:51:57 +00:00
|
|
|
|
2023-03-06 04:19:49 +00:00
|
|
|
const DEV_NAME: &str = "sn76489";
|
2021-12-06 22:51:57 +00:00
|
|
|
|
2022-01-26 19:12:09 +00:00
|
|
|
#[derive(Clone)]
|
2022-01-27 03:15:46 +00:00
|
|
|
pub struct ToneGenerator {
|
2022-01-26 19:12:09 +00:00
|
|
|
on: bool,
|
|
|
|
attenuation: f32,
|
|
|
|
wave: SquareWave,
|
|
|
|
}
|
|
|
|
|
2022-01-27 03:15:46 +00:00
|
|
|
impl ToneGenerator {
|
2022-01-26 19:12:09 +00:00
|
|
|
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;
|
|
|
|
}
|
2022-01-27 03:15:46 +00:00
|
|
|
info!("set attenuation to {} {}", self.attenuation, self.on);
|
2022-01-26 19:12:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_counter(&mut self, count: usize) {
|
|
|
|
let frequency = 3_579_545.0 / (count as f32 * 32.0);
|
|
|
|
self.wave.set_frequency(frequency);
|
2022-01-27 03:15:46 +00:00
|
|
|
info!("set frequency to {}", frequency);
|
2022-01-26 19:12:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_sample(&mut self) -> f32 {
|
2022-10-02 17:29:34 +00:00
|
|
|
self.wave.next().unwrap() / (self.attenuation + 1.0)
|
2022-01-26 19:12:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-01-27 03:15:46 +00:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct NoiseGenerator {
|
|
|
|
on: bool,
|
|
|
|
attenuation: f32,
|
|
|
|
}
|
|
|
|
|
2023-03-06 04:19:49 +00:00
|
|
|
impl Default for NoiseGenerator {
|
|
|
|
fn default() -> Self {
|
2022-01-27 03:15:46 +00:00
|
|
|
Self {
|
|
|
|
on: false,
|
|
|
|
attenuation: 0.0,
|
|
|
|
}
|
|
|
|
}
|
2023-03-06 04:19:49 +00:00
|
|
|
}
|
2022-01-27 03:15:46 +00:00
|
|
|
|
2023-03-06 04:19:49 +00:00
|
|
|
impl NoiseGenerator {
|
2022-01-27 03:15:46 +00:00
|
|
|
pub fn set_attenuation(&mut self, attenuation: u8) {
|
|
|
|
if attenuation == 0x0F {
|
|
|
|
self.on = false;
|
|
|
|
} else {
|
|
|
|
self.on = true;
|
|
|
|
self.attenuation = (attenuation << 1) as f32;
|
|
|
|
}
|
|
|
|
info!("set attenuation to {} {}", self.attenuation, self.on);
|
|
|
|
}
|
|
|
|
|
2022-09-10 05:31:55 +00:00
|
|
|
pub fn set_control(&mut self, _bits: u8) {
|
2022-01-27 03:15:46 +00:00
|
|
|
//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 {
|
|
|
|
// TODO this isn't implemented yet
|
|
|
|
0.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-12-12 23:20:09 +00:00
|
|
|
pub struct Sn76489 {
|
|
|
|
pub first_byte: Option<u8>,
|
|
|
|
pub source: Box<dyn Audio>,
|
2022-01-27 03:15:46 +00:00
|
|
|
pub tones: Vec<ToneGenerator>,
|
|
|
|
pub noise: NoiseGenerator,
|
2021-12-12 23:20:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Sn76489 {
|
|
|
|
pub fn create<H: Host>(host: &mut H) -> Result<Self, Error> {
|
|
|
|
let source = host.create_audio_source()?;
|
2022-01-26 19:12:09 +00:00
|
|
|
let sample_rate = source.samples_per_second();
|
2021-12-12 23:20:09 +00:00
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
first_byte: None,
|
|
|
|
source,
|
2022-01-27 03:15:46 +00:00
|
|
|
tones: vec![ToneGenerator::new(sample_rate); 3],
|
2023-03-06 04:19:49 +00:00
|
|
|
noise: NoiseGenerator::default(),
|
2021-12-12 23:20:09 +00:00
|
|
|
})
|
|
|
|
}
|
2021-12-06 22:51:57 +00:00
|
|
|
}
|
|
|
|
|
2021-12-12 23:20:09 +00:00
|
|
|
impl Steppable for Sn76489 {
|
2022-10-08 20:26:17 +00:00
|
|
|
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
|
2022-01-26 19:12:09 +00:00
|
|
|
let rate = self.source.samples_per_second();
|
|
|
|
let available = self.source.space_available();
|
|
|
|
let samples = if available < rate / 1000 { available } else { rate / 1000 };
|
|
|
|
|
|
|
|
if samples > 0 {
|
|
|
|
//if available >= rate / 1000 {
|
|
|
|
let mut buffer = vec![0.0; samples];
|
2023-03-06 04:19:49 +00:00
|
|
|
for buffered_sample in buffer.iter_mut().take(samples) {
|
2022-01-26 19:12:09 +00:00
|
|
|
let mut sample = 0.0;
|
|
|
|
|
|
|
|
for ch in 0..3 {
|
2022-01-27 03:15:46 +00:00
|
|
|
if self.tones[ch].on {
|
|
|
|
sample += self.tones[ch].get_sample();
|
2022-01-26 19:12:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-27 03:15:46 +00:00
|
|
|
if self.noise.on {
|
|
|
|
sample += self.noise.get_sample();
|
|
|
|
}
|
|
|
|
|
2023-03-06 04:19:49 +00:00
|
|
|
*buffered_sample = sample.clamp(-1.0, 1.0);
|
2022-01-26 19:12:09 +00:00
|
|
|
}
|
2022-10-08 20:26:17 +00:00
|
|
|
self.source.write_samples(system.clock, &buffer);
|
2022-01-26 19:12:09 +00:00
|
|
|
} else {
|
|
|
|
self.source.flush();
|
2021-12-06 22:51:57 +00:00
|
|
|
}
|
2021-12-12 23:20:09 +00:00
|
|
|
|
|
|
|
Ok(1_000_000) // Every 1ms of simulated time
|
2021-12-06 22:51:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-12 23:20:09 +00:00
|
|
|
impl Addressable for Sn76489 {
|
2021-12-06 22:51:57 +00:00
|
|
|
fn len(&self) -> usize {
|
|
|
|
0x01
|
|
|
|
}
|
|
|
|
|
2021-12-13 20:00:24 +00:00
|
|
|
fn read(&mut self, _addr: Address, _data: &mut [u8]) -> Result<(), Error> {
|
2022-10-09 16:40:20 +00:00
|
|
|
warn!("{}: !!! device can't be read", DEV_NAME);
|
2021-12-06 22:51:57 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
|
2021-12-12 23:20:09 +00:00
|
|
|
if addr != 0 {
|
2022-10-09 16:40:20 +00:00
|
|
|
warn!("{}: !!! unhandled write {:0x} to {:0x}", DEV_NAME, data[0], addr);
|
2021-12-12 23:20:09 +00:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2022-01-27 03:15:46 +00:00
|
|
|
if (data[0] & 0x80) != 0 {
|
|
|
|
let reg = (data[0] & 0x70) >> 4;
|
|
|
|
let value = data[0] & 0x0F;
|
2022-01-26 19:12:09 +00:00
|
|
|
match reg {
|
2022-01-27 03:15:46 +00:00
|
|
|
1 => self.tones[0].set_attenuation(value),
|
|
|
|
3 => self.tones[1].set_attenuation(value),
|
|
|
|
5 => self.tones[2].set_attenuation(value),
|
|
|
|
6 => self.noise.set_control(value),
|
|
|
|
7 => self.noise.set_attenuation(value),
|
|
|
|
_ => { self.first_byte = Some(data[0]); },
|
2022-01-26 19:12:09 +00:00
|
|
|
}
|
2021-12-12 23:20:09 +00:00
|
|
|
} else {
|
2022-01-27 03:15:46 +00:00
|
|
|
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);
|
2022-01-26 19:12:09 +00:00
|
|
|
match reg {
|
2022-01-27 03:15:46 +00:00
|
|
|
0 => self.tones[0].set_counter(value),
|
|
|
|
2 => self.tones[1].set_counter(value),
|
|
|
|
4 => self.tones[2].set_counter(value),
|
2022-01-26 19:12:09 +00:00
|
|
|
_ => { },
|
2021-12-12 23:20:09 +00:00
|
|
|
}
|
2021-12-06 22:51:57 +00:00
|
|
|
}
|
2021-12-12 23:20:09 +00:00
|
|
|
debug!("{}: write to register {:x} with {:x}", DEV_NAME, addr, data[0]);
|
2021-12-06 22:51:57 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-12 23:20:09 +00:00
|
|
|
impl Transmutable for Sn76489 {
|
2021-12-06 22:51:57 +00:00
|
|
|
fn as_addressable(&mut self) -> Option<&mut dyn Addressable> {
|
|
|
|
Some(self)
|
|
|
|
}
|
|
|
|
|
2021-12-12 23:20:09 +00:00
|
|
|
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
|
|
|
|
Some(self)
|
|
|
|
}
|
2021-12-06 22:51:57 +00:00
|
|
|
}
|
|
|
|
|