From 7ee256e12ec3d55ddfba07ef19204114ab9ae5db Mon Sep 17 00:00:00 2001 From: gered Date: Sun, 29 May 2022 13:51:55 -0400 Subject: [PATCH] add Audio struct to wrap underlying SDL AudioDevice doesn't provide much value currently, but serves as a base for future extension (e.g. queuing play commands, global volume changes, etc) --- libretrogd/src/audio/mod.rs | 64 +++++++++++++++++++++++++++++++++++- libretrogd/src/system/mod.rs | 14 +++----- 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/libretrogd/src/audio/mod.rs b/libretrogd/src/audio/mod.rs index 16ee496..d5a6033 100644 --- a/libretrogd/src/audio/mod.rs +++ b/libretrogd/src/audio/mod.rs @@ -1,6 +1,7 @@ use std::ops::{Index, IndexMut}; -use sdl2::audio::{AudioCallback, AudioFormat}; +use sdl2::audio::{AudioCallback, AudioFormat, AudioSpecDesired}; +use sdl2::AudioSubsystem; use thiserror::Error; pub use self::wav::*; @@ -283,6 +284,67 @@ impl IndexMut for AudioDevice { ////////////////////////////////////////////////////////////////////////////////////////////////// +#[derive(Debug, Error)] +pub enum AudioError { + #[error("Failed to open audio device for playback: {0}")] + OpenDeviceFailed(String), +} + +pub struct Audio { + spec: AudioSpec, + sdl_audio_device: sdl2::audio::AudioDevice, +} + +impl Audio { + pub fn new(desired_spec: AudioSpecDesired, sdl_audio_subsystem: &AudioSubsystem) -> Result { + let mut spec = None; + let sdl_audio_device = match sdl_audio_subsystem.open_playback(None, &desired_spec, |opened_spec| { + let our_spec = AudioSpec::new(opened_spec.freq as u32, opened_spec.channels, opened_spec.format); + spec = Some(our_spec); + AudioDevice::new(our_spec) + }) { + Ok(audio_device) => audio_device, + Err(error) => return Err(AudioError::OpenDeviceFailed(error)), + }; + + if let Some(spec) = spec { + Ok(Audio { + spec, + sdl_audio_device, + }) + } else { + Err(AudioError::OpenDeviceFailed(String::from("Device initialization failed to set AudioSpec"))) + } + } + + #[inline] + pub fn spec(&self) -> &AudioSpec { + &self.spec + } + + #[inline] + pub fn status(&self) -> sdl2::audio::AudioStatus { + self.sdl_audio_device.status() + } + + #[inline] + pub fn pause(&mut self) { + self.sdl_audio_device.pause() + } + + #[inline] + pub fn resume(&mut self) { + self.sdl_audio_device.resume() + } + + #[inline] + pub fn lock(&mut self) -> sdl2::audio::AudioDeviceLockGuard { + self.sdl_audio_device.lock() + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////// + #[derive(Error, Debug)] pub enum AudioBufferError { #[error("Error during format conversion: {0}")] diff --git a/libretrogd/src/system/mod.rs b/libretrogd/src/system/mod.rs index f32670b..674e90e 100644 --- a/libretrogd/src/system/mod.rs +++ b/libretrogd/src/system/mod.rs @@ -23,6 +23,9 @@ pub enum SystemError { #[error("System display error: {0}")] DisplayError(String), + + #[error("System audio error: {0}")] + AudioError(#[from] crate::audio::AudioError), } /// Builder for configuring and constructing an instance of [`System`]. @@ -247,14 +250,7 @@ impl SystemBuilder { channels: Some(TARGET_AUDIO_SPEC.channels()), samples: None, }; - - let audio = match sdl_audio_subsystem.open_playback(None, &audio_spec, |spec| { - let our_spec = AudioSpec::new(spec.freq as u32, spec.channels, spec.format); - AudioDevice::new(our_spec) - }) { - Ok(audio_device) => audio_device, - Err(error) => return Err(SystemError::InitError(error)), - }; + let mut audio = Audio::new(audio_spec, &sdl_audio_subsystem)?; audio.resume(); // create input device objects, exposed to the application @@ -305,7 +301,7 @@ pub struct System { target_framerate_delta: Option, next_tick: i64, - pub audio: sdl2::audio::AudioDevice, + pub audio: Audio, /// The primary backbuffer [`Bitmap`] that will be rendered to the screen whenever /// [`System::display`] is called. Regardless of the actual window size, this bitmap is always