// Square wave generator use crate::sound::AudioComponent; use crate::sound::OUTPUT_SAMPLE_RATE; #[derive(Debug)] pub enum DutyCycle { Duty0, // 12.5% Duty1, // 25.0% Duty2, // 50.0% Duty3, // 75.0% } impl Default for DutyCycle { fn default() -> Self { DutyCycle::Duty2 } } #[derive(Debug, Default)] pub struct SquareWaveGenerator { frequency: f32, time: f32, pub duty_cycle: DutyCycle, gb_reg_freq: u16, // Sweep settings (if existing) sweep_change_period: u8, // selects the inc/dec mode of the sweep. Dec if set sweep_dec: bool, // Sweep speed (n/128th) sweep_change: u8, // Current sweep clock cycle sweep_clock: u8, // sweep_freq_shadow: f32, } impl SquareWaveGenerator { fn update_frequency(&mut self) { self.frequency = 131072f32 / ((2048 - self.gb_reg_freq) as f32); } pub fn set_lower_freq(&mut self, freq: u8) { self.gb_reg_freq &= 0xFF00; self.gb_reg_freq |= freq as u16; self.update_frequency(); } pub fn set_higher_freq(&mut self, freq: u8) { self.gb_reg_freq &= 0x00FF; self.gb_reg_freq |= ((freq & 7) as u16) << 8; self.update_frequency(); } pub fn set_sweep_reg(&mut self, reg: u8) { //Bit 6-4 - Sweep Time //Bit 3 - Sweep Increase/Decrease // 0: Addition (frequency increases) // 1: Subtraction (frequency decreases) //Bit 2-0 - Number of sweep shift (n: 0-7) self.sweep_change_period = (reg >> 4) & 0b0111; self.sweep_dec = reg & (1 << 3) > 0; self.sweep_change = reg & 0b111; self.sweep_clock = 0; } pub fn sweep_clock(&mut self) { // This should be sampled at 128Hz if self.sweep_change_period > 0 // enabled && self.sweep_clock >= self.sweep_change_period // sweep time hit { self.sweep_clock = 0; let change = self.frequency / (2f32.powi(self.sweep_change as _)); self.frequency += if self.sweep_dec { -change } else { change }; } } pub fn reset(&mut self) { self.time = 0f32; } pub fn sample(&self) -> u8 { if self.frequency > 0f32 { let mut temp = self.time * self.frequency; temp -= temp.trunc(); match self.duty_cycle { DutyCycle::Duty0 => { if temp < 0.125 { 255 } else { 0 } } DutyCycle::Duty1 => { if temp < 0.25 { 255 } else { 0 } } DutyCycle::Duty2 => { if temp < 0.5 { 255 } else { 0 } } DutyCycle::Duty3 => { if temp < 0.75 { 255 } else { 0 } } } } else { 0 } } pub fn set_duty_cycle(&mut self, bits: u8) { self.duty_cycle = match bits { 0 => DutyCycle::Duty0, 1 => DutyCycle::Duty1, 2 => DutyCycle::Duty2, _ => DutyCycle::Duty3, }; } } impl AudioComponent for SquareWaveGenerator { fn clock(&mut self) { self.time += 1f32 / (OUTPUT_SAMPLE_RATE as f32); } }