From 195d94ddb000eaab8974378d6ee7e5bb463a88b4 Mon Sep 17 00:00:00 2001 From: Kevin Hamacher Date: Thu, 20 Feb 2020 21:15:34 +0100 Subject: [PATCH] audio: improve it by essentially switching to i8 --- Cargo.toml | 6 +- src/sound/envelope.rs | 4 +- src/sound/mod.rs | 195 ++++++++++++++++++++++++------------------ src/sound/wave.rs | 6 +- 4 files changed, 120 insertions(+), 91 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 377eb28..6a5ff9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,11 @@ version = "0.1.0" authors = ["Kevin Hamacher "] edition = '2018' +[features] +default = ["audio"] +audio = ["pulse-simple"] + [dependencies] sdl2 = "*" libc = "*" -pulse-simple = "*" +pulse-simple = { version = "*", optional = true } diff --git a/src/sound/envelope.rs b/src/sound/envelope.rs index 7dd53a0..6e0d013 100644 --- a/src/sound/envelope.rs +++ b/src/sound/envelope.rs @@ -71,9 +71,9 @@ impl VolumeEnvelope { impl AudioModule for VolumeEnvelope { fn transform(&self, sample: u8) -> u8 { if sample > 0 { - self.current_volume + 128 + self.current_volume } else { - 0 + 128 - self.current_volume } } } diff --git a/src/sound/mod.rs b/src/sound/mod.rs index 6a89cfd..9e1bdec 100644 --- a/src/sound/mod.rs +++ b/src/sound/mod.rs @@ -1,16 +1,21 @@ +#[cfg(feature = "audio")] extern crate pulse_simple; mod envelope; mod length; mod square; mod wave; +#[cfg(feature = "audio")] use self::pulse_simple::Playback; use std::sync::{ atomic::{AtomicBool, Ordering}, Arc, Mutex, }; +#[cfg(feature = "audio")] use std::thread; +use std::convert::TryFrom; + const OUTPUT_SAMPLE_RATE: usize = 48100; //const OUTPUT_SAMPLE_RATE: usize = 32768; @@ -233,10 +238,11 @@ impl Default for Channel3VolumeSetting { impl Channel3VolumeSetting { fn transform(&self, sample: u8) -> u8 { match self { - Self::Muted => 0, - Self::Original => sample, - Self::Half => sample >> 1, - Self::Quarter => sample >> 2, + Self::Muted => 128, + // Actually making it louder as the wave src is quite silent. + Self::Original => ((sample - 120) << 1) + 112, + Self::Half => sample, + Self::Quarter => ((sample - 120) >> 1) + 124, } } } @@ -296,7 +302,7 @@ impl Channel3 { pub fn sample(&self) -> u8 { let input = self.wave_gen.sample(); // TODO(?): Follow the chain - // let input = self.length_counter.transform(input); + let input = self.length_counter.transform(input); self.volume_ctrl.transform(input) } @@ -309,10 +315,6 @@ impl Channel3 { // TODO: Sweep } - if self.tick_state == 7 { - // self.envelope.clock(); - } - self.tick_state += 1; if self.tick_state == 8 { @@ -336,6 +338,7 @@ pub struct SoundManager { pub sound_object: Arc>, handle: Option>, do_exit: Arc, + sound_enabled: bool, } impl Drop for SoundManager { @@ -351,6 +354,7 @@ impl SoundManager { sound_object: Arc::new(Mutex::new(Sound::new())), handle: None, do_exit: Arc::new(AtomicBool::new(false)), + sound_enabled: true, }; res.launch_thread(); @@ -359,48 +363,57 @@ impl SoundManager { fn launch_thread(&mut self) { let obj = self.sound_object.clone(); - if false { - return; - } - 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 _); + #[cfg(feature = "audio")] + { + if self.sound_enabled { + 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 _); - // Counter, used for calling the 512 Hz timer - let mut counter = 0; + // Counter, used for calling the 512 Hz timer + let mut counter = 0; - while !do_exit.load(Ordering::Relaxed) { - for _ in 0..100 { - let (s1, s2) = { - let mut c_obj = obj.lock().unwrap(); + while !do_exit.load(Ordering::Relaxed) { + for _ in 0..100 { + if let Some((s1, s2)) = { + let mut c_obj = obj.lock().unwrap(); - // Check for 512 Hz timer - if counter >= (OUTPUT_SAMPLE_RATE / 512) { - c_obj.clock(); - counter = 0; - } else { - counter += 1; + // Check for 512 Hz timer + if counter >= (OUTPUT_SAMPLE_RATE / 512) { + c_obj.clock(); + counter = 0; + } else { + counter += 1; + } + + // Sample clock + c_obj.sample_clock(); + + // Get sample + c_obj.sample() + } { + let samps = [[s1, s2]]; + playback.write(&samps[..]); + } else { + let samps = [[128, 128]]; + playback.write(&samps[..]); + } } - - // Sample clock - c_obj.sample_clock(); - - // Get sample - c_obj.sample() - }; - let samps = [[s1, s2]]; - playback.write(&samps[..]); - } - std::thread::sleep(std::time::Duration::from_millis(1)); - } - }) - .unwrap(), - ); + std::thread::sleep(std::time::Duration::from_millis(1)); + } + }) + .unwrap(), + ); + } else { + println!("Sound will be redirected to /dev/null ;)"); + self.handle = None; + } + } } } @@ -421,7 +434,11 @@ impl Sound { self.channel3.sample_clock(); } - pub fn sample(&self) -> (u8, u8) { + pub fn sample(&self) -> Option<(u8, u8)> { + if self.enabled == 0 { + return None; + } + // Some basic mixing // Output value let mut s = (0, 0); @@ -442,47 +459,55 @@ impl Sound { let c1_sample = self.channel1.sample(); let c2_sample = self.channel2.sample(); let c3_sample = self.channel3.sample(); - let c4_sample = 0; + let c4_sample = 128; - if self.enabled != 0 { - 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 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; - } + if self.sound_output_terminal_selector & 1 > 0 { + // Output Channel1 + s.0 += i16::try_from(c1_sample).unwrap() - 128; + } + if self.sound_output_terminal_selector & 2 > 0 { + // Output Channel2 + s.0 += i16::try_from(c2_sample).unwrap() - 128; + } + if self.sound_output_terminal_selector & 4 > 0 { + // Output Channel3 + s.0 += i16::try_from(c3_sample).unwrap() - 128; + } + if self.sound_output_terminal_selector & 8 > 0 { + // Output Channel4 + s.0 += i16::try_from(c4_sample).unwrap() - 128; } - s.0 *= s01_volume + 1; - s.1 *= s02_volume + 1; - s + if self.sound_output_terminal_selector & 0x10 > 0 { + // Output Channel1 + s.1 += i16::try_from(c1_sample).unwrap() - 128; + } + if self.sound_output_terminal_selector & 0x20 > 0 { + // Output Channel2 + s.1 += i16::try_from(c2_sample).unwrap() - 128; + } + if self.sound_output_terminal_selector & 0x40 > 0 { + // Output Channel3 + s.1 += i16::try_from(c3_sample).unwrap() - 128; + } + if self.sound_output_terminal_selector & 0x80 > 0 { + // Output Channel4 + s.1 += i16::try_from(c4_sample).unwrap() - 128; + } + + // TODO: This is too loud (overflowing u8) for some reason, so we're + // backing off a little bit from this. + /* + if s.0 > 30 || s.1 > 30 { + println!("Would overflow! s={:?} s1vol={} s2vol={}", s, s01_volume, s02_volume); + } + */ + //s.0 *= i16::try_from(s01_volume).unwrap(); // + 1; + //s.1 *= i16::try_from(s02_volume).unwrap(); // + 1; + + let s = (128 + s.0, 128 + s.1); + let s = (u8::try_from(s.0).unwrap(), u8::try_from(s.1).unwrap()); + Some(s) } pub fn write_byte(&mut self, addr: u16, val: u8) { diff --git a/src/sound/wave.rs b/src/sound/wave.rs index 1eed2bd..41e22c4 100644 --- a/src/sound/wave.rs +++ b/src/sound/wave.rs @@ -66,11 +66,11 @@ impl WaveGenerator { let sample = &self.samples[position / 2]; match position % 2 { - 0 => sample.first(), - _ => sample.second(), + 0 => sample.first() + 120, + _ => sample.second() + 120, } } else { - 0 + 128 } }