attempt to use OS's audio resampling first
This commit is contained in:
parent
e308af9a2a
commit
df21f69128
2 changed files with 55 additions and 33 deletions
|
@ -98,7 +98,7 @@ pub fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emu.register_component(Sdl2RateControlledAudioComponent::new(&mut sdl_context)?)?;
|
emu.register_component(SimpleSdl2AudioComponent::new(&mut sdl_context)?)?;
|
||||||
|
|
||||||
emu.register_component(SimpleSdl2KeyboardComponent::new(&mut sdl_context)?)?;
|
emu.register_component(SimpleSdl2KeyboardComponent::new(&mut sdl_context)?)?;
|
||||||
emu.register_component(SimpleSdl2GamepadComponent::new(&mut sdl_context))?;
|
emu.register_component(SimpleSdl2GamepadComponent::new(&mut sdl_context))?;
|
||||||
|
|
|
@ -10,9 +10,11 @@ use sdl2::audio::{AudioCVT, AudioFormat, AudioFormatNum, AudioQueue, AudioSpec,
|
||||||
use crate::base::ControlFlow;
|
use crate::base::ControlFlow;
|
||||||
|
|
||||||
pub struct SimpleSdl2AudioComponent {
|
pub struct SimpleSdl2AudioComponent {
|
||||||
|
sdl_audio: sdl2::AudioSubsystem,
|
||||||
src_freq: f64,
|
src_freq: f64,
|
||||||
audio_buffer: Vec<i16>,
|
audio_buffer: Vec<i16>,
|
||||||
queue: AudioQueue<i16>,
|
queue: Option<AudioQueue<i16>>,
|
||||||
|
must_resample: bool,
|
||||||
started: bool,
|
started: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,9 +53,13 @@ impl RetroCallbacks for SimpleSdl2AudioComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_system_av_info(&mut self, av_info: &SystemAvInfo) -> Option<bool> {
|
fn set_system_av_info(&mut self, av_info: &SystemAvInfo) -> Option<bool> {
|
||||||
if Self::make_converter(av_info.timing.sample_rate, self.queue.spec()).is_ok() {
|
if let Some(queue) = &self.queue {
|
||||||
self.src_freq = av_info.timing.sample_rate;
|
if Self::make_converter(av_info.timing.sample_rate, queue.spec()).is_ok() {
|
||||||
Some(true)
|
self.src_freq = av_info.timing.sample_rate;
|
||||||
|
Some(true)
|
||||||
|
} else {
|
||||||
|
Some(false)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Some(false)
|
Some(false)
|
||||||
}
|
}
|
||||||
|
@ -62,29 +68,53 @@ impl RetroCallbacks for SimpleSdl2AudioComponent {
|
||||||
|
|
||||||
impl RetroComponent for SimpleSdl2AudioComponent {
|
impl RetroComponent for SimpleSdl2AudioComponent {
|
||||||
fn post_load_game(&mut self, retro: &mut LibretroWrapper, _rom: &Path) -> Result<(), Box<dyn Error + Send + Sync>> {
|
fn post_load_game(&mut self, retro: &mut LibretroWrapper, _rom: &Path) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
self.src_freq = retro.get_system_av_info().timing.sample_rate;
|
let timing = retro.get_system_av_info().timing;
|
||||||
self.queue.resume();
|
self.src_freq = timing.sample_rate;
|
||||||
|
|
||||||
|
let samples_per_frame = timing.sample_rate / timing.fps;
|
||||||
|
|
||||||
|
let desired_spec = AudioSpecDesired {
|
||||||
|
freq: Some(self.src_freq.round() as i32),
|
||||||
|
channels: Some(2),
|
||||||
|
samples: Some((2.0 * samples_per_frame).ceil() as u16),
|
||||||
|
};
|
||||||
|
|
||||||
|
let queue = AudioQueue::open_queue(&self.sdl_audio, None, &desired_spec)?;
|
||||||
|
if queue.spec().freq != desired_spec.freq.unwrap() {
|
||||||
|
self.must_resample = true;
|
||||||
|
eprintln!("warning: using naive resampling");
|
||||||
|
}
|
||||||
|
queue.resume();
|
||||||
|
|
||||||
|
self.queue = Some(queue);
|
||||||
self.started = false;
|
self.started = false;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn post_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow {
|
fn post_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow {
|
||||||
if self.src_freq != 0.0 {
|
if self.src_freq != 0.0 {
|
||||||
match Self::make_converter(self.src_freq, self.queue.spec()) {
|
let queue = self.queue.as_mut().unwrap();
|
||||||
Ok(converter) => {
|
if self.must_resample {
|
||||||
if !self.audio_buffer.is_empty() {
|
match Self::make_converter(self.src_freq, queue.spec()) {
|
||||||
let mut samples = std::mem::take(&mut self.audio_buffer);
|
Ok(converter) => {
|
||||||
samples = resample(&converter, samples);
|
if !self.audio_buffer.is_empty() {
|
||||||
self.audio_buffer = samples;
|
let mut samples = std::mem::take(&mut self.audio_buffer);
|
||||||
self.queue.queue(&self.audio_buffer);
|
samples = resample(&converter, samples);
|
||||||
self.audio_buffer.clear();
|
self.audio_buffer = samples;
|
||||||
|
queue.queue(&self.audio_buffer);
|
||||||
|
self.audio_buffer.clear();
|
||||||
|
}
|
||||||
|
ControlFlow::Continue
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Audio sample rate conversion failed: {:?}", e);
|
||||||
|
ControlFlow::Break
|
||||||
}
|
}
|
||||||
ControlFlow::Continue
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Audio sample rate conversion failed: {:?}", e);
|
|
||||||
ControlFlow::Break
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
queue.queue(self.audio_buffer.as_slice());
|
||||||
|
self.audio_buffer.clear();
|
||||||
|
ControlFlow::Continue
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ControlFlow::Continue
|
ControlFlow::Continue
|
||||||
|
@ -94,22 +124,14 @@ impl RetroComponent for SimpleSdl2AudioComponent {
|
||||||
|
|
||||||
impl SimpleSdl2AudioComponent {
|
impl SimpleSdl2AudioComponent {
|
||||||
pub fn new(sdl_context: &mut Sdl) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
pub fn new(sdl_context: &mut Sdl) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let audio = sdl_context.audio().unwrap();
|
let sdl_audio = sdl_context.audio()?;
|
||||||
let desired_spec = AudioSpecDesired {
|
|
||||||
freq: None,
|
|
||||||
channels: Some(2),
|
|
||||||
samples: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let queue = AudioQueue::open_queue(&audio, None, &desired_spec)?;
|
|
||||||
|
|
||||||
// default to the old libsnes default value until after load_game or set_system_av_info.
|
|
||||||
let src_freq = 32040.5;
|
|
||||||
|
|
||||||
Ok(SimpleSdl2AudioComponent {
|
Ok(SimpleSdl2AudioComponent {
|
||||||
src_freq,
|
sdl_audio,
|
||||||
|
src_freq: 32040.5, // nod to the old libsnes default til load_game or set_system_av_info
|
||||||
audio_buffer: Default::default(),
|
audio_buffer: Default::default(),
|
||||||
queue,
|
queue: None,
|
||||||
|
must_resample: false,
|
||||||
started: false,
|
started: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue