mod channel;
mod dc_filter;
mod decimator;
mod envelope_generator;
mod error;
mod interpolator;
mod noise_generator;
pub mod math;
pub use channel::Channel;
pub use envelope_generator::EnvelopeGenerator;
pub use error::Error;
pub use noise_generator::NoiseGenerator;
use decimator::{DECIMATE_FACTOR, Decimator, FIR_SIZE};
use dc_filter::DCFilter;
use interpolator::Interpolator;
const AY_DAC_TABLE: [f64; 32] = [
0.0, 0.0, 0.00999465934234, 0.00999465934234,
0.0144502937362, 0.0144502937362, 0.0210574502174, 0.0210574502174,
0.0307011520562, 0.0307011520562, 0.0455481803616, 0.0455481803616,
0.0644998855573, 0.0644998855573, 0.107362478065, 0.107362478065,
0.126588845655, 0.126588845655, 0.20498970016, 0.20498970016,
0.292210269322, 0.292210269322, 0.372838941024, 0.372838941024,
0.492530708782, 0.492530708782, 0.635324635691, 0.635324635691,
0.805584802014, 0.805584802014, 1.0, 1.0
];
const YM_DAC_TABLE: [f64; 32] = [
0.0, 0.0, 0.00465400167849, 0.00772106507973,
0.0109559777218, 0.0139620050355, 0.0169985503929, 0.0200198367285,
0.024368657969, 0.029694056611, 0.0350652323186, 0.0403906309606,
0.0485389486534, 0.0583352407111, 0.0680552376593, 0.0777752346075,
0.0925154497597, 0.111085679408, 0.129747463188, 0.148485542077,
0.17666895552, 0.211551079576, 0.246387426566, 0.281101701381,
0.333730067903, 0.400427252613, 0.467383840696, 0.53443198291,
0.635172045472, 0.75800717174, 0.879926756695, 1.0
];
pub enum ChipType {
AY,
YM
}
impl ChipType {
fn log2lin_table(&self) -> &'static [f64; 32] {
match self {
ChipType::AY => &AY_DAC_TABLE,
ChipType::YM => &YM_DAC_TABLE
}
}
}
pub struct PSG {
channels: [Channel; 3],
noise_generator: NoiseGenerator,
envelope_generator: EnvelopeGenerator,
log2lin_table: &'static [f64; 32],
x: f64,
step: f64,
left_interpolator: Interpolator,
right_interpolator: Interpolator,
left_decimator: Decimator,
right_decimator: Decimator,
decimator_index: usize,
dc_filter: DCFilter
}
impl PSG {
pub fn new(clock_rate: f64, sample_rate: u32) -> Result<Self, Error> {
let step = clock_rate / (sample_rate as f64 * 8.0 * DECIMATE_FACTOR as f64);
if step >= 1.0 {
return Err(Error::ClockRateTooHigh);
}
Ok(Self {
channels: [Channel::new(), Channel::new(), Channel::new()],
noise_generator: NoiseGenerator::new(),
envelope_generator: EnvelopeGenerator::new(),
log2lin_table: ChipType::YM.log2lin_table(),
x: 0.0,
step,
left_interpolator: Interpolator::new(),
right_interpolator: Interpolator::new(),
left_decimator: Decimator::new(),
right_decimator: Decimator::new(),
decimator_index: 0,
dc_filter: DCFilter::new()
})
}
pub fn set_chip_type(&mut self, chip_type: ChipType) {
self.log2lin_table = chip_type.log2lin_table();
}
fn render_tick(&mut self) -> (f64, f64) {
let noise = self.noise_generator.render();
let envelope = self.envelope_generator.render();
self.channels.iter_mut().fold((0.0, 0.0), |(left, right), channel| {
let mut level = (channel.render() | channel.tone_off as u8) & (noise | channel.noise_off as u8);
level *= if channel.envelope_on {
envelope
} else {
channel.amplitude * 2 + 1
};
let amplitude = self.log2lin_table[level as usize];
(left + amplitude * channel.pan_left, right + amplitude * channel.pan_right)
})
}
pub fn render(&mut self) -> (f64, f64) {
let decimator_start = FIR_SIZE - self.decimator_index * DECIMATE_FACTOR;
self.decimator_index = (self.decimator_index + 1) % (FIR_SIZE / DECIMATE_FACTOR - 1);
for offset in (0..DECIMATE_FACTOR).rev() {
self.x += self.step;
if self.x >= 1.0 {
self.x -= 1.0;
let (left, right) = self.render_tick();
self.left_interpolator.feed(left);
self.right_interpolator.feed(right);
}
self.left_decimator.buffer[decimator_start + offset] = self.left_interpolator.interpolate(self.x);
self.right_decimator.buffer[decimator_start + offset] = self.right_interpolator.interpolate(self.x);
}
self.dc_filter.render(
self.left_decimator.render(decimator_start),
self.right_decimator.render(decimator_start)
)
}
pub fn channel(&self, index: u8) -> &Channel {
&self.channels[index as usize]
}
pub fn channel_mut(&mut self, index: u8) -> &mut Channel {
&mut self.channels[index as usize]
}
pub fn noise_generator(&self) -> &NoiseGenerator {
&self.noise_generator
}
pub fn noise_generator_mut(&mut self) -> &mut NoiseGenerator {
&mut self.noise_generator
}
pub fn envelope_generator(&self) -> &EnvelopeGenerator {
&self.envelope_generator
}
pub fn envelope_generator_mut(&mut self) -> &mut EnvelopeGenerator {
&mut self.envelope_generator
}
pub fn set_tone_period(&mut self, channel: u8, period: u16) {
self.channels[channel as usize].set_period(period);
}
pub fn set_amplitude(&mut self, channel: u8, amplitude: u8) {
self.channels[channel as usize].set_amplitude(amplitude);
}
pub fn set_tone_disabled(&mut self, channel: u8, disabled: bool) {
self.channels[channel as usize].set_tone_disabled(disabled);
}
pub fn set_noise_disabled(&mut self, channel: u8, disabled: bool) {
self.channels[channel as usize].set_noise_disabled(disabled);
}
pub fn set_envelope_enabled(&mut self, channel: u8, enabled: bool) {
self.channels[channel as usize].set_envelope_enabled(enabled);
}
pub fn set_noise_period(&mut self, period: u8) {
self.noise_generator.set_period(period);
}
pub fn set_mixer(&mut self, mixer: u8) {
self.channels[0].set_tone_disabled(mixer & 0x01 != 0);
self.channels[1].set_tone_disabled(mixer & 0x02 != 0);
self.channels[2].set_tone_disabled(mixer & 0x04 != 0);
self.channels[0].set_noise_disabled(mixer & 0x08 != 0);
self.channels[1].set_noise_disabled(mixer & 0x10 != 0);
self.channels[2].set_noise_disabled(mixer & 0x20 != 0);
}
pub fn set_envelope_period(&mut self, period: u16) {
self.envelope_generator.set_period(period);
}
pub fn set_envelope_shape(&mut self, shape: u8) {
self.envelope_generator.set_shape(shape);
}
pub fn set_register(&mut self, register: u8, value: u8) {
match register {
0 => self.channels[0].set_period_lsb(value),
1 => self.channels[0].set_period_msb(value),
2 => self.channels[1].set_period_lsb(value),
3 => self.channels[1].set_period_msb(value),
4 => self.channels[2].set_period_lsb(value),
5 => self.channels[2].set_period_msb(value),
6 => self.noise_generator.set_period(value),
7 => self.set_mixer(value),
8 => self.channels[0].set_amplitude_and_envelope_enabled(value),
9 => self.channels[1].set_amplitude_and_envelope_enabled(value),
10 => self.channels[2].set_amplitude_and_envelope_enabled(value),
11 => self.envelope_generator.set_period_lsb(value),
12 => self.envelope_generator.set_period_msb(value),
13 => self.envelope_generator.set_shape(value),
14 => (), 15 => (), _ => ()
}
}
}