diff --git a/src/sound/envelope.rs b/src/sound/envelope.rs index bd04d85..7dd53a0 100644 --- a/src/sound/envelope.rs +++ b/src/sound/envelope.rs @@ -61,7 +61,7 @@ impl VolumeEnvelope { } pub fn set_register(&mut self, register: u8) { - self.register_value = register & !(1 << 6); + self.register_value = register; // & !(1 << 6); // TODO: Where does this come from? if register & (1 << 6) != 0 { self.start(); } @@ -70,10 +70,8 @@ impl VolumeEnvelope { impl AudioModule for VolumeEnvelope { fn transform(&self, sample: u8) -> u8 { - // Use a linear volume gain - let volume = 255f32 * self.current_volume as f32 / 15 as f32; if sample > 0 { - volume as u8 + self.current_volume } else { 0 } diff --git a/src/sound/mod.rs b/src/sound/mod.rs index acbfa37..4a341a6 100644 --- a/src/sound/mod.rs +++ b/src/sound/mod.rs @@ -57,9 +57,9 @@ impl Channel1 { 0xFF14 => { self.stored_regs[4] = val; // Set higher - self.wave_gen.set_higher_freq(val); + self.wave_gen.set_higher_freq(val & 0b111); - if val & 1 << 7 != 0 { + if val & (1 << 7) != 0 { self.wave_gen.reset(); self.envelope.start(); } @@ -138,9 +138,9 @@ impl Channel2 { } 0xFF19 => { // Set higher - self.wave_gen.set_higher_freq(val); + self.wave_gen.set_higher_freq(val & 0b111); - if val & 1 << 7 != 0 { + if val & (1 << 7) != 0 { self.wave_gen.reset(); self.envelope.start(); } @@ -152,7 +152,14 @@ impl Channel2 { } pub fn read_byte(&self, addr: u16) -> u8 { + use crate::sound::square::DutyCycle::*; match addr { + 0xFF16 => match self.wave_gen.duty_cycle { + Duty0 => 0, // 12.5% + Duty1 => 0b0100_0000, // 25.0% + Duty2 => 0b1000_0000, // 50.0% + Duty3 => 0b1100_0000, // 75.0% + }, _ => { println!("Channel2 does not support reading ({:04X})", addr); 0 @@ -192,18 +199,56 @@ impl Channel2 { } } +#[derive(Debug)] +enum Channel3VolumeSetting { + Muted, + Original, + Half, + Quarter, +} + +impl From for Channel3VolumeSetting { + fn from(o: u8) -> Self { + use Channel3VolumeSetting::*; + match o { + 0 => Muted, + 1 => Original, + 2 => Half, + 3 => Quarter, + _ => unreachable!("Invalid channel volume setting"), + } + } +} + +impl Default for Channel3VolumeSetting { + fn default() -> Self { + Self::Muted + } +} + +impl Channel3VolumeSetting { + fn transform(&self, sample: u8) -> u8 { + match self { + Self::Muted => 0, + Self::Original => sample, + Self::Half => sample >> 1, + Self::Quarter => sample >> 2, + } + } +} + #[derive(Debug, Default)] struct Channel3 { // Timer -> Wave -> Length Counter -> Volume -> Mixer wave_gen: wave::WaveGenerator, length_counter: length::LengthCounter, - // TODO: Volume + volume_ctrl: Channel3VolumeSetting, tick_state: u8, } impl Channel3 { pub fn write_byte(&mut self, addr: u16, val: u8) { - // println!("C3 WB: {:04X} = {:02X} ({:08b})", addr, val, val); + // OFF flag -> "bit 7 of NR30" match addr { 0xFF1A => { self.wave_gen.enabled = (val & (1 << 7)) > 0; @@ -211,22 +256,20 @@ impl Channel3 { 0xFF1B => { self.length_counter.set_length(val); } - 0xFF1C => { - // Output volume, TODO. - } + 0xFF1C => self.volume_ctrl = ((val >> 5) & 0b11).into(), 0xFF1D => { // Set lower frequency self.wave_gen.set_lower_freq(val); } 0xFF1E => { // Set higher - self.wave_gen.set_higher_freq(val); + self.wave_gen.set_higher_freq(val & 0b111); - if val & 1 << 7 != 0 { + if val & (1 << 7) != 0 { self.wave_gen.reset(); } - self.length_counter.set_enabled(val & 1 << 6); + self.length_counter.set_enabled(val & (1 << 6)); } 0xFF30..=0xFF3F => { self.wave_gen.set_sample_pair((addr - 0xFF30) as usize, val); @@ -237,6 +280,7 @@ impl Channel3 { pub fn read_byte(&self, addr: u16) -> u8 { match addr { + 0xFF30..=0xFF3F => self.wave_gen.get_sample_pair((addr - 0xFF30) as usize), _ => panic!("Channel3 does not support reading ({:04X})", addr), } } @@ -247,9 +291,9 @@ impl Channel3 { pub fn sample(&self) -> u8 { let input = self.wave_gen.sample(); - // Follow the chain + // TODO(?): Follow the chain // let input = self.length_counter.transform(input); - input + self.volume_ctrl.transform(input) } pub fn clock(&mut self) { @@ -286,56 +330,72 @@ pub struct Sound { pub struct SoundManager { pub sound_object: Arc>, + handle: Option>, + do_exit: Arc>, +} + +impl Drop for SoundManager { + fn drop(&mut self) { + *self.do_exit.lock().unwrap() = true; + self.handle.take().and_then(|h| h.join().ok()); + } } impl SoundManager { pub fn new() -> Self { - let res = SoundManager { + let mut res = SoundManager { sound_object: Arc::new(Mutex::new(Sound::new())), + handle: None, + do_exit: Arc::new(Mutex::new(false)), }; res.launch_thread(); res } - pub fn launch_thread(&self) { + fn launch_thread(&mut self) { let obj = self.sound_object.clone(); if false { return; } - thread::Builder::new() - .name("Audio".into()) - .spawn(move || { - // PulseAudio playback object - let playback = Playback::new("GBC", "Output", None, (OUTPUT_SAMPLE_RATE) as _); - // Counter, used for calling the 512 Hz timer - let mut counter = 0; + let do_exit = self.do_exit.clone(); + self.handle = Some( + thread::Builder::new() + .name("Audio".into()) + .spawn(move || { + // PulseAudio playback object + let playback = Playback::new("GBC", "Output", None, (OUTPUT_SAMPLE_RATE) as _); - loop { - let (s1, s2) = { - let mut c_obj = obj.lock().unwrap(); + // Counter, used for calling the 512 Hz timer + let mut counter = 0; - // Check for 512 Hz timer - if counter >= (OUTPUT_SAMPLE_RATE / 512) { - c_obj.clock(); - counter = 0; - } else { - counter += 1; - } + while !*do_exit.lock().unwrap() { + let (s1, s2) = { + let mut c_obj = obj.lock().unwrap(); - // Sample clock - c_obj.sample_clock(); + // Check for 512 Hz timer + if counter >= (OUTPUT_SAMPLE_RATE / 512) { + c_obj.clock(); + counter = 0; + } else { + counter += 1; + } - // Get sample - c_obj.sample() - }; - let samps = [[s1, s2]]; - // No sleep needed, it seems like the playback.write is blocking - playback.write(&samps[..]); - } - }) - .unwrap(); + // Sample clock + c_obj.sample_clock(); + + // Get sample + c_obj.sample() + }; + let samps = [[s1, s2]]; + //let samps = [[0f32, 0f32]]; + // No sleep needed, it seems like the playback.write is blocking + playback.write(&samps[..]); + } + }) + .unwrap(), + ); } } @@ -359,72 +419,82 @@ impl Sound { pub fn sample(&self) -> (u8, u8) { // Some basic mixing // Output value - let mut s = [0u16; 2]; + let mut s = (0, 0); let s01_volume = self.sound_channel_volume_control & 7; let s02_volume = (self.sound_channel_volume_control >> 4) & 7; + /* + if self.sound_channel_volume_control & 0b1000 != 0 { + + VIN! + } + + if self.sound_channel_volume_control & 0b1000_0000 != 0 { + VIN! + } + */ + let c1_sample = self.channel1.sample(); let c2_sample = self.channel2.sample(); let c3_sample = self.channel3.sample(); let c4_sample = 0; if self.enabled != 0 { - if s01_volume > 0 { - if self.sound_output_terminal_selector & 1 > 0 { - // Output Channel1 - s[0] += c1_sample as u16; - } - if self.sound_output_terminal_selector & 2 > 0 && false { - // Output Channel2 - s[0] += c2_sample as u16; - } - if self.sound_output_terminal_selector & 4 > 0 { - // Output Channel3 - s[0] += c3_sample as u16; - } - if self.sound_output_terminal_selector & 8 > 0 { - // Output Channel4 - s[0] += c4_sample as u16; - } + if self.sound_output_terminal_selector & 1 > 0 { + // Output Channel1 + s.0 += c1_sample; + } + if self.sound_output_terminal_selector & 2 > 0 { + // Output Channel2 + s.0 += c2_sample; + } + if self.sound_output_terminal_selector & 4 > 0 { + // Output Channel3 + s.0 += c3_sample; + } + if self.sound_output_terminal_selector & 8 > 0 { + // Output Channel4 + s.0 += c4_sample; } - if s02_volume > 0 { - if self.sound_output_terminal_selector & 0x10 > 0 && false { - // Output Channel1 - s[1] += c1_sample as u16; - } - if self.sound_output_terminal_selector & 0x20 > 0 { - // Output Channel2 - s[1] += c2_sample as u16; - } - if self.sound_output_terminal_selector & 0x40 > 0 { - // Output Channel3 - s[1] += c3_sample as u16; - } - if self.sound_output_terminal_selector & 0x80 > 0 { - // Output Channel4 - s[1] += c4_sample as u16; - } + if self.sound_output_terminal_selector & 0x10 > 0 { + // Output Channel1 + s.1 += c1_sample; + } + if self.sound_output_terminal_selector & 0x20 > 0 { + // Output Channel2 + s.1 += c2_sample; + } + if self.sound_output_terminal_selector & 0x40 > 0 { + // Output Channel3 + s.1 += c3_sample; + } + if self.sound_output_terminal_selector & 0x80 > 0 { + // Output Channel4 + s.1 += c4_sample; } } - // (self.channel1.sample() >> 1) + (self.channel2.sample() >> 1) + (self.channel3.sample() >> 1) - ((s[0] >> 2) as _, (s[1] >> 2) as _) + + s.0 *= s01_volume + 1; + s.1 *= s02_volume + 1; + s } pub fn write_byte(&mut self, addr: u16, val: u8) { + // Bit 7 of NR52 = 0 -> everything reset + // If all sound off no mode register can be set // println!("Snd: {:04X} = {:02X} ({:08b})", addr, val, val); match addr { 0xFF10..=0xFF14 => self.channel1.write_byte(addr, val), 0xFF16..=0xFF19 => self.channel2.write_byte(addr, val), 0xFF1A..=0xFF1E => self.channel3.write_byte(addr, val), - + // TODO: Channel 4 0xFF24 => self.sound_channel_volume_control = val, 0xFF25 => self.sound_output_terminal_selector = val, 0xFF26 => self.enabled = val, 0xFF30..=0xFF3F => self.channel3.write_byte(addr, val), _ => { - // panic!("Sound: Write {:02X} to {:04X} unsupported", val, addr); println!("Sound: Write {:02X} to {:04X} unsupported", val, addr); } } diff --git a/src/sound/square.rs b/src/sound/square.rs index ab761cd..8c4962a 100644 --- a/src/sound/square.rs +++ b/src/sound/square.rs @@ -20,7 +20,7 @@ impl Default for DutyCycle { pub struct SquareWaveGenerator { frequency: f32, time: f32, - duty_cycle: DutyCycle, + pub duty_cycle: DutyCycle, gb_reg_freq: u16, @@ -66,15 +66,14 @@ impl SquareWaveGenerator { } pub fn sweep_clock(&mut self) { - // self.sweep_freq_shadow = self.frequency; - if self.sweep_change_period > 0 { - if self.sweep_change > 0 { - if self.sweep_clock >= self.sweep_change_period { - self.sweep_clock = 0; - let change = self.frequency / (2f32.powi(self.sweep_change as _)); - self.frequency += if self.sweep_dec { change } else { -change }; - } - } + // This should be sampled at 128Hz + if self.sweep_change_period > 0 + && self.sweep_clock >= self.sweep_change_period + && self.sweep_change > 0 + { + self.sweep_clock = 0; + let change = self.frequency / (2f32.powi(self.sweep_change as _)); + self.frequency += if self.sweep_dec { -change } else { change }; } } diff --git a/src/sound/wave.rs b/src/sound/wave.rs index d7caac5..7895e48 100644 --- a/src/sound/wave.rs +++ b/src/sound/wave.rs @@ -2,7 +2,7 @@ use crate::sound::AudioComponent; use crate::sound::OUTPUT_SAMPLE_RATE; -#[derive(Debug, Default)] +#[derive(Debug, Default, Copy, Clone)] struct SamplePair(u8); impl SamplePair { @@ -21,6 +21,12 @@ impl From for SamplePair { } } +impl Into for SamplePair { + fn into(self: Self) -> u8 { + self.0 + } +} + #[derive(Debug, Default)] pub struct WaveGenerator { frequency: f32, @@ -72,6 +78,10 @@ impl WaveGenerator { pub fn set_sample_pair(&mut self, nr: usize, val: u8) { self.samples[nr] = val.into(); } + + pub fn get_sample_pair(&self, nr: usize) -> u8 { + self.samples[nr].into() + } } impl AudioComponent for WaveGenerator {