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)
This commit is contained in:
Gered 2022-05-29 13:51:55 -04:00
parent c5b2e216cf
commit 7ee256e12e
2 changed files with 68 additions and 10 deletions

View file

@ -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<usize> 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<AudioDevice>,
}
impl Audio {
pub fn new(desired_spec: AudioSpecDesired, sdl_audio_subsystem: &AudioSubsystem) -> Result<Self, AudioError> {
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<AudioDevice> {
self.sdl_audio_device.lock()
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Error, Debug)]
pub enum AudioBufferError {
#[error("Error during format conversion: {0}")]

View file

@ -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<i64>,
next_tick: i64,
pub audio: sdl2::audio::AudioDevice<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