audio: improve it by essentially switching to i8

This commit is contained in:
Kevin Hamacher 2020-02-20 21:15:34 +01:00
parent cd48f4c4c8
commit 195d94ddb0
4 changed files with 120 additions and 91 deletions

View File

@ -4,7 +4,11 @@ version = "0.1.0"
authors = ["Kevin Hamacher <kevin.hamacher@rub.de>"] authors = ["Kevin Hamacher <kevin.hamacher@rub.de>"]
edition = '2018' edition = '2018'
[features]
default = ["audio"]
audio = ["pulse-simple"]
[dependencies] [dependencies]
sdl2 = "*" sdl2 = "*"
libc = "*" libc = "*"
pulse-simple = "*" pulse-simple = { version = "*", optional = true }

View File

@ -71,9 +71,9 @@ impl VolumeEnvelope {
impl AudioModule<u8> for VolumeEnvelope { impl AudioModule<u8> for VolumeEnvelope {
fn transform(&self, sample: u8) -> u8 { fn transform(&self, sample: u8) -> u8 {
if sample > 0 { if sample > 0 {
self.current_volume 128 + self.current_volume
} else { } else {
0 128 - self.current_volume
} }
} }
} }

View File

@ -1,16 +1,21 @@
#[cfg(feature = "audio")]
extern crate pulse_simple; extern crate pulse_simple;
mod envelope; mod envelope;
mod length; mod length;
mod square; mod square;
mod wave; mod wave;
#[cfg(feature = "audio")]
use self::pulse_simple::Playback; use self::pulse_simple::Playback;
use std::sync::{ use std::sync::{
atomic::{AtomicBool, Ordering}, atomic::{AtomicBool, Ordering},
Arc, Mutex, Arc, Mutex,
}; };
#[cfg(feature = "audio")]
use std::thread; use std::thread;
use std::convert::TryFrom;
const OUTPUT_SAMPLE_RATE: usize = 48100; const OUTPUT_SAMPLE_RATE: usize = 48100;
//const OUTPUT_SAMPLE_RATE: usize = 32768; //const OUTPUT_SAMPLE_RATE: usize = 32768;
@ -233,10 +238,11 @@ impl Default for Channel3VolumeSetting {
impl Channel3VolumeSetting { impl Channel3VolumeSetting {
fn transform(&self, sample: u8) -> u8 { fn transform(&self, sample: u8) -> u8 {
match self { match self {
Self::Muted => 0, Self::Muted => 128,
Self::Original => sample, // Actually making it louder as the wave src is quite silent.
Self::Half => sample >> 1, Self::Original => ((sample - 120) << 1) + 112,
Self::Quarter => sample >> 2, Self::Half => sample,
Self::Quarter => ((sample - 120) >> 1) + 124,
} }
} }
} }
@ -296,7 +302,7 @@ impl Channel3 {
pub fn sample(&self) -> u8 { pub fn sample(&self) -> u8 {
let input = self.wave_gen.sample(); let input = self.wave_gen.sample();
// TODO(?): Follow the chain // TODO(?): Follow the chain
// let input = self.length_counter.transform(input); let input = self.length_counter.transform(input);
self.volume_ctrl.transform(input) self.volume_ctrl.transform(input)
} }
@ -309,10 +315,6 @@ impl Channel3 {
// TODO: Sweep // TODO: Sweep
} }
if self.tick_state == 7 {
// self.envelope.clock();
}
self.tick_state += 1; self.tick_state += 1;
if self.tick_state == 8 { if self.tick_state == 8 {
@ -336,6 +338,7 @@ pub struct SoundManager {
pub sound_object: Arc<Mutex<Sound>>, pub sound_object: Arc<Mutex<Sound>>,
handle: Option<std::thread::JoinHandle<()>>, handle: Option<std::thread::JoinHandle<()>>,
do_exit: Arc<AtomicBool>, do_exit: Arc<AtomicBool>,
sound_enabled: bool,
} }
impl Drop for SoundManager { impl Drop for SoundManager {
@ -351,6 +354,7 @@ impl SoundManager {
sound_object: Arc::new(Mutex::new(Sound::new())), sound_object: Arc::new(Mutex::new(Sound::new())),
handle: None, handle: None,
do_exit: Arc::new(AtomicBool::new(false)), do_exit: Arc::new(AtomicBool::new(false)),
sound_enabled: true,
}; };
res.launch_thread(); res.launch_thread();
@ -359,48 +363,57 @@ impl SoundManager {
fn launch_thread(&mut self) { fn launch_thread(&mut self) {
let obj = self.sound_object.clone(); let obj = self.sound_object.clone();
if false {
return;
}
let do_exit = self.do_exit.clone(); let do_exit = self.do_exit.clone();
self.handle = Some( #[cfg(feature = "audio")]
thread::Builder::new() {
.name("Audio".into()) if self.sound_enabled {
.spawn(move || { self.handle = Some(
// PulseAudio playback object thread::Builder::new()
let playback = Playback::new("GBC", "Output", None, (OUTPUT_SAMPLE_RATE) as _); .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 // Counter, used for calling the 512 Hz timer
let mut counter = 0; let mut counter = 0;
while !do_exit.load(Ordering::Relaxed) { while !do_exit.load(Ordering::Relaxed) {
for _ in 0..100 { for _ in 0..100 {
let (s1, s2) = { if let Some((s1, s2)) = {
let mut c_obj = obj.lock().unwrap(); let mut c_obj = obj.lock().unwrap();
// Check for 512 Hz timer // Check for 512 Hz timer
if counter >= (OUTPUT_SAMPLE_RATE / 512) { if counter >= (OUTPUT_SAMPLE_RATE / 512) {
c_obj.clock(); c_obj.clock();
counter = 0; counter = 0;
} else { } else {
counter += 1; 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[..]);
}
} }
std::thread::sleep(std::time::Duration::from_millis(1));
// Sample clock }
c_obj.sample_clock(); })
.unwrap(),
// Get sample );
c_obj.sample() } else {
}; println!("Sound will be redirected to /dev/null ;)");
let samps = [[s1, s2]]; self.handle = None;
playback.write(&samps[..]); }
} }
std::thread::sleep(std::time::Duration::from_millis(1));
}
})
.unwrap(),
);
} }
} }
@ -421,7 +434,11 @@ impl Sound {
self.channel3.sample_clock(); 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 // Some basic mixing
// Output value // Output value
let mut s = (0, 0); let mut s = (0, 0);
@ -442,47 +459,55 @@ impl Sound {
let c1_sample = self.channel1.sample(); let c1_sample = self.channel1.sample();
let c2_sample = self.channel2.sample(); let c2_sample = self.channel2.sample();
let c3_sample = self.channel3.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 {
if self.sound_output_terminal_selector & 1 > 0 { // Output Channel1
// Output Channel1 s.0 += i16::try_from(c1_sample).unwrap() - 128;
s.0 += c1_sample; }
} if self.sound_output_terminal_selector & 2 > 0 {
if self.sound_output_terminal_selector & 2 > 0 { // Output Channel2
// Output Channel2 s.0 += i16::try_from(c2_sample).unwrap() - 128;
s.0 += c2_sample; }
} if self.sound_output_terminal_selector & 4 > 0 {
if self.sound_output_terminal_selector & 4 > 0 { // Output Channel3
// Output Channel3 s.0 += i16::try_from(c3_sample).unwrap() - 128;
s.0 += c3_sample; }
} if self.sound_output_terminal_selector & 8 > 0 {
if self.sound_output_terminal_selector & 8 > 0 { // Output Channel4
// Output Channel4 s.0 += i16::try_from(c4_sample).unwrap() - 128;
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;
}
} }
s.0 *= s01_volume + 1; if self.sound_output_terminal_selector & 0x10 > 0 {
s.1 *= s02_volume + 1; // Output Channel1
s 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) { pub fn write_byte(&mut self, addr: u16, val: u8) {

View File

@ -66,11 +66,11 @@ impl WaveGenerator {
let sample = &self.samples[position / 2]; let sample = &self.samples[position / 2];
match position % 2 { match position % 2 {
0 => sample.first(), 0 => sample.first() + 120,
_ => sample.second(), _ => sample.second() + 120,
} }
} else { } else {
0 128
} }
} }