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:
parent
c5b2e216cf
commit
7ee256e12e
|
@ -1,6 +1,7 @@
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
use sdl2::audio::{AudioCallback, AudioFormat};
|
use sdl2::audio::{AudioCallback, AudioFormat, AudioSpecDesired};
|
||||||
|
use sdl2::AudioSubsystem;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub use self::wav::*;
|
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)]
|
#[derive(Error, Debug)]
|
||||||
pub enum AudioBufferError {
|
pub enum AudioBufferError {
|
||||||
#[error("Error during format conversion: {0}")]
|
#[error("Error during format conversion: {0}")]
|
||||||
|
|
|
@ -23,6 +23,9 @@ pub enum SystemError {
|
||||||
|
|
||||||
#[error("System display error: {0}")]
|
#[error("System display error: {0}")]
|
||||||
DisplayError(String),
|
DisplayError(String),
|
||||||
|
|
||||||
|
#[error("System audio error: {0}")]
|
||||||
|
AudioError(#[from] crate::audio::AudioError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builder for configuring and constructing an instance of [`System`].
|
/// Builder for configuring and constructing an instance of [`System`].
|
||||||
|
@ -247,14 +250,7 @@ impl SystemBuilder {
|
||||||
channels: Some(TARGET_AUDIO_SPEC.channels()),
|
channels: Some(TARGET_AUDIO_SPEC.channels()),
|
||||||
samples: None,
|
samples: None,
|
||||||
};
|
};
|
||||||
|
let mut audio = Audio::new(audio_spec, &sdl_audio_subsystem)?;
|
||||||
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)),
|
|
||||||
};
|
|
||||||
audio.resume();
|
audio.resume();
|
||||||
|
|
||||||
// create input device objects, exposed to the application
|
// create input device objects, exposed to the application
|
||||||
|
@ -305,7 +301,7 @@ pub struct System {
|
||||||
target_framerate_delta: Option<i64>,
|
target_framerate_delta: Option<i64>,
|
||||||
next_tick: 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
|
/// 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
|
/// [`System::display`] is called. Regardless of the actual window size, this bitmap is always
|
||||||
|
|
Loading…
Reference in a new issue