use crate::runtime::{NesRuntime, RuntimeError}; use super::clock::{FrameClock, NoopClock, PacingClock}; use super::config::HostConfig; use super::executor::{FrameExecution, FrameExecutor}; use super::io::{AudioOutput, InputProvider, VideoOutput}; pub struct RuntimeHostLoop { runtime: NesRuntime, executor: FrameExecutor, clock: C, } impl RuntimeHostLoop { pub fn new(runtime: NesRuntime, sample_rate: u32) -> Self { let executor = FrameExecutor::from_runtime(&runtime, sample_rate); let clock = PacingClock::from_runtime(&runtime); Self { runtime, executor, clock, } } pub fn with_config( runtime: NesRuntime, config: HostConfig, ) -> RuntimeHostLoop> { let executor = FrameExecutor::from_runtime(&runtime, config.sample_rate); let clock: Box = if config.pacing { Box::new(PacingClock::from_runtime(&runtime)) } else { Box::new(NoopClock) }; RuntimeHostLoop { runtime, executor, clock, } } } impl RuntimeHostLoop where C: FrameClock, { pub fn with_clock(runtime: NesRuntime, sample_rate: u32, clock: C) -> Self { let executor = FrameExecutor::from_runtime(&runtime, sample_rate); Self { runtime, executor, clock, } } pub fn runtime(&self) -> &NesRuntime { &self.runtime } pub fn runtime_mut(&mut self) -> &mut NesRuntime { &mut self.runtime } pub fn into_runtime(self) -> NesRuntime { self.runtime } pub fn executor(&self) -> &FrameExecutor { &self.executor } pub fn executor_mut(&mut self) -> &mut FrameExecutor { &mut self.executor } pub fn clock(&self) -> &C { &self.clock } pub fn clock_mut(&mut self) -> &mut C { &mut self.clock } pub fn run_frame( &mut self, input: &mut I, video: &mut V, audio: &mut A, ) -> Result where I: InputProvider, V: VideoOutput, A: AudioOutput, { let stats = self.run_frame_unpaced(input, video, audio)?; self.clock.wait_next_frame(); Ok(stats) } pub fn run_frame_unpaced( &mut self, input: &mut I, video: &mut V, audio: &mut A, ) -> Result where I: InputProvider, V: VideoOutput, A: AudioOutput, { self.executor .execute_frame(&mut self.runtime, input, video, audio) } pub fn run_frames( &mut self, frames: usize, input: &mut I, video: &mut V, audio: &mut A, ) -> Result where I: InputProvider, V: VideoOutput, A: AudioOutput, { let mut total_samples = 0usize; for _ in 0..frames { total_samples = total_samples.saturating_add(self.run_frame(input, video, audio)?.audio_samples); } Ok(total_samples) } pub fn run_frames_unpaced( &mut self, frames: usize, input: &mut I, video: &mut V, audio: &mut A, ) -> Result where I: InputProvider, V: VideoOutput, A: AudioOutput, { let mut total_samples = 0usize; for _ in 0..frames { total_samples = total_samples .saturating_add(self.run_frame_unpaced(input, video, audio)?.audio_samples); } Ok(total_samples) } }