diff --git a/ferretro_components/examples/multifunction_emulator.rs b/ferretro_components/examples/multifunction_emulator.rs index 1f657fb..99c8a96 100644 --- a/ferretro_components/examples/multifunction_emulator.rs +++ b/ferretro_components/examples/multifunction_emulator.rs @@ -41,7 +41,9 @@ pub fn main() -> Result<(), Box> { let mut sdl_context = sdl2::init()?; - emu.register_component(StderrLogComponent { prefix: "{log} ".to_string() })?; + let mut stderr_log = StderrLogComponent::default(); + stderr_log.prefix = "{log} ".to_string(); + emu.register_component(stderr_log)?; // must register before opengl so it can have priority in queries about what N64 plugin to use // (only supports software-rendered 2D frames currently) @@ -60,8 +62,7 @@ pub fn main() -> Result<(), Box> { emu.register_component(SimpleSdl2GamepadComponent::new(&mut sdl_context))?; - let sleep_fps = SleepFramerateLimitComponent::new(emu.libretro_core()); - emu.register_component(sleep_fps)?; + emu.register_component(SleepFramerateLimitComponent::new())?; emu.register_component(PathBufComponent { sys_path: opt.system.clone(), diff --git a/ferretro_components/src/provided/sdl2/audio.rs b/ferretro_components/src/provided/sdl2/audio.rs index f7cfab9..afd0396 100644 --- a/ferretro_components/src/provided/sdl2/audio.rs +++ b/ferretro_components/src/provided/sdl2/audio.rs @@ -54,25 +54,28 @@ impl RetroCallbacks for SimpleSdl2AudioComponent { } impl RetroComponent for SimpleSdl2AudioComponent { - fn post_load_game(&mut self, _retro: &mut LibretroWrapper, _rom: &Path) -> Result<(), Box> { + fn post_load_game(&mut self, retro: &mut LibretroWrapper, _rom: &Path) -> Result<(), Box> { + self.src_freq = retro.get_system_av_info().timing.sample_rate; self.queue.resume(); Ok(()) } fn post_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow { if let Ok(converter) = Self::make_converter(self.src_freq, self.queue.spec()) { - let mut samples = std::mem::take(&mut self.audio_buffer); - samples = resample(&converter, samples); - self.audio_buffer = samples; - self.queue.queue(&self.audio_buffer); - self.audio_buffer.clear(); + if !self.audio_buffer.is_empty() { + let mut samples = std::mem::take(&mut self.audio_buffer); + samples = resample(&converter, samples); + self.audio_buffer = samples; + self.queue.queue(&self.audio_buffer); + self.audio_buffer.clear(); + } } ControlFlow::Continue } } impl SimpleSdl2AudioComponent { - pub fn new(sdl_context: &mut Sdl, retro: &LibretroWrapper) -> Result> { + pub fn new(sdl_context: &mut Sdl, _retro: &LibretroWrapper) -> Result> { let audio = sdl_context.audio().unwrap(); let desired_spec = AudioSpecDesired { freq: None, @@ -82,12 +85,8 @@ impl SimpleSdl2AudioComponent { let queue = AudioQueue::open_queue(&audio, None, &desired_spec)?; - let mut src_freq = retro.get_system_av_info().timing.sample_rate; - // HACK: some cores don't report this 'til we get an env call to set_system_av_info, - // so we can just default to the old libsnes default value. - if src_freq == 0.0 { - src_freq = 32040.5; - } + // default to the old libsnes default value until after load_game or set_system_av_info. + let src_freq = 32040.5; Ok(SimpleSdl2AudioComponent { src_freq, diff --git a/ferretro_components/src/provided/sdl2/opengl.rs b/ferretro_components/src/provided/sdl2/opengl.rs index 212907b..8162456 100644 --- a/ferretro_components/src/provided/sdl2/opengl.rs +++ b/ferretro_components/src/provided/sdl2/opengl.rs @@ -6,6 +6,7 @@ use std::os::raw::c_uint; use sdl2::Sdl; use sdl2::rect::Rect; use sdl2::render::WindowCanvas; +use std::path::Path; /// Create a root window in SDL2 with an OpenGL context and attaches libretro's /// `hw_get_proc_address` calls to that of the [sdl2::VideoSubsystem]. @@ -34,12 +35,12 @@ impl SimpleSdl2OpenglComponent { unsafe { CStr::from_ptr(sys_info.library_name) }.to_string_lossy() ); - let geometry = retro.get_system_av_info().geometry; let pixel_format = sdl2::pixels::PixelFormatEnum::ARGB1555; let video = sdl_context.video()?; + // default to old libsnes 256x224 window size until load_game (prereq of get_system_av_info) let window = video - .window(title.as_str(), geometry.base_width, geometry.base_height) + .window(title.as_str(), 256, 224) .opengl() .build()?; @@ -90,7 +91,13 @@ impl SimpleSdl2OpenglComponent { } } -impl RetroComponent for SimpleSdl2OpenglComponent {} +impl RetroComponent for SimpleSdl2OpenglComponent { + fn post_load_game(&mut self, retro: &mut LibretroWrapper, _rom: &Path) -> crate::base::Result<()> { + self.set_geometry(&retro.get_system_av_info().geometry); + Ok(()) + } +} + impl RetroCallbacks for SimpleSdl2OpenglComponent { fn video_refresh(&mut self, frame: &VideoFrame) { match frame { diff --git a/ferretro_components/src/provided/stdlib/fps.rs b/ferretro_components/src/provided/stdlib/fps.rs index 7664db9..a47c1a1 100644 --- a/ferretro_components/src/provided/stdlib/fps.rs +++ b/ferretro_components/src/provided/stdlib/fps.rs @@ -2,6 +2,7 @@ use crate::base::ControlFlow; use crate::prelude::*; use std::time::{Duration, Instant}; +use std::path::Path; /// Uses [std::thread::sleep] to maintain the target FPS specified by the core. /// @@ -14,6 +15,10 @@ pub struct SleepFramerateLimitComponent { } impl RetroComponent for SleepFramerateLimitComponent { + fn post_load_game(&mut self, retro: &mut LibretroWrapper, _rom: &Path) -> crate::base::Result<()> { + self.fps = retro.get_system_av_info().timing.fps; + Ok(()) + } fn pre_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow { self.did_sleep = false; ControlFlow::Continue @@ -38,11 +43,11 @@ impl RetroCallbacks for SleepFramerateLimitComponent { } impl SleepFramerateLimitComponent { - pub fn new(retro: &mut LibretroWrapper) -> Self { + pub fn new() -> Self { SleepFramerateLimitComponent { did_sleep: false, started_video: false, - fps: retro.get_system_av_info().timing.fps, + fps: 60.0, // default until load_game frame_begin: Instant::now(), } } diff --git a/ferretro_components/src/provided/stdlib/logs.rs b/ferretro_components/src/provided/stdlib/logs.rs index 426121f..1217067 100644 --- a/ferretro_components/src/provided/stdlib/logs.rs +++ b/ferretro_components/src/provided/stdlib/logs.rs @@ -6,17 +6,29 @@ use std::os::raw::c_uint; use std::path::PathBuf; /// Write's the core's own log statements to stderr. -#[derive(Default)] pub struct StderrLogComponent { /// May be set to add a prefix to each logged line. pub prefix: String, + /// The most verbose log level that should be printed. + pub level: ferretro_base::retro::ffi::LogLevel, +} + +impl Default for StderrLogComponent { + fn default() -> Self { + StderrLogComponent { + prefix: String::new(), + level: ferretro_base::retro::ffi::LogLevel::Info, + } + } } impl RetroComponent for StderrLogComponent {} impl RetroCallbacks for StderrLogComponent { fn log_print(&mut self, level: ferretro_base::retro::ffi::LogLevel, msg: &str) { - eprint!("{}[{:?}] {}", self.prefix, level, msg); + if level >= self.level { + eprint!("{}[{:?}] {}", self.prefix, level, msg); + } } }