use std::{cell::RefCell, rc::Rc};
use super::{
base_system::BaseSystem,
sound::{SoundDriver, SoundType},
tone_generator::ToneGenerator,
};
pub struct PSG {
sound: Rc<RefCell<dyn SoundDriver>>,
registers: [u8; 16],
reg_next: u8,
sound_tones: [ToneGenerator; 3],
}
impl PSG {
pub fn new(sound_type: SoundType, sys: Option<&mut BaseSystem>) -> Self {
let sound = sound_type.create(sys);
for i in 0..3 {
let _ = sound.borrow_mut().add_channel(i);
}
Self {
sound,
registers: [0; 16],
reg_next: 0,
sound_tones: [
ToneGenerator::new(),
ToneGenerator::new(),
ToneGenerator::new(),
],
}
}
pub fn write_port(&mut self, ad: u8, val: u8) {
match ad {
0xa0 => {
self.reg_next = val;
}
0xa1 => {
self.registers[self.reg_next as usize] = val;
if self.reg_next < 14 {
for i in 0..3 {
self.do_tones(i)
}
}
}
_ => {
log::error!("Sound, not implemented: out({:02x},{:02x})", ad, val);
}
}
}
pub fn read_port(&self, ad: u8) -> u8 {
if ad == 0xa2 {
if self.reg_next == 0x0e {
let bit_cass = self.cassete_get_next_bit() << 7;
return 0x3f | bit_cass;
}
if self.reg_next == 0x0f {
return 0;
}
return self.registers[self.reg_next as usize];
}
log::error!("Sound, not implemented: in({:02x})", ad);
0
}
pub fn cassete_get_next_bit(&self) -> u8 {
0
}
pub fn do_tones(&mut self, chn: usize) {
let freq =
(((self.registers[chn * 2 + 1] & 0x0f) as u16) << 8) | (self.registers[chn * 2]) as u16;
let envelope_enabled = (self.registers[8 + chn] & 0x10) != 0;
if freq > 0 {
let real_freq = 111861_f32 / (freq as f32);
if envelope_enabled {
} else {
let volume = (self.registers[8 + chn] & 0x0F) as f32;
self.sound_tones[chn].set_volume(volume);
self.sound_tones[chn].set_frequency(real_freq);
}
}
let is_active = self.registers[7] & (0x01 << chn) == 0;
self.sound_tones[chn].activate(is_active);
if is_active {
if freq > 0 {
self.feed_samples(chn);
let _ = self.sound.borrow_mut().play(chn);
}
} else {
let _ = self.sound.borrow_mut().pause(chn);
}
}
fn feed_samples(&mut self, chn: usize) {
let freq = self.sound_tones[chn].get_frequency();
let _ = self
.sound
.borrow_mut()
.feed_samples(chn, freq, self.sound_tones[chn].get_volume());
}
}