audio: improve it by essentially switching to i8
This commit is contained in:
parent
cd48f4c4c8
commit
195d94ddb0
@ -4,7 +4,11 @@ version = "0.1.0"
|
||||
authors = ["Kevin Hamacher <kevin.hamacher@rub.de>"]
|
||||
edition = '2018'
|
||||
|
||||
[features]
|
||||
default = ["audio"]
|
||||
audio = ["pulse-simple"]
|
||||
|
||||
[dependencies]
|
||||
sdl2 = "*"
|
||||
libc = "*"
|
||||
pulse-simple = "*"
|
||||
pulse-simple = { version = "*", optional = true }
|
||||
|
||||
@ -71,9 +71,9 @@ impl VolumeEnvelope {
|
||||
impl AudioModule<u8> for VolumeEnvelope {
|
||||
fn transform(&self, sample: u8) -> u8 {
|
||||
if sample > 0 {
|
||||
self.current_volume
|
||||
128 + self.current_volume
|
||||
} else {
|
||||
0
|
||||
128 - self.current_volume
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
195
src/sound/mod.rs
195
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<Mutex<Sound>>,
|
||||
handle: Option<std::thread::JoinHandle<()>>,
|
||||
do_exit: Arc<AtomicBool>,
|
||||
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) {
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user