add doc comments for audio functionality
This commit is contained in:
parent
44984c716c
commit
b856ab2fc6
|
@ -10,6 +10,7 @@ pub enum AudioBufferError {
|
|||
ConversionError(String),
|
||||
}
|
||||
|
||||
/// Holds audio sample data that can be played via [`AudioDevice`].
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AudioBuffer {
|
||||
spec: AudioSpec,
|
||||
|
@ -17,6 +18,8 @@ pub struct AudioBuffer {
|
|||
}
|
||||
|
||||
impl AudioBuffer {
|
||||
/// Creates and returns a new, empty, [`AudioBuffer`] that will hold audio sample data in the
|
||||
/// spec/format given.
|
||||
pub fn new(spec: AudioSpec) -> Self {
|
||||
AudioBuffer {
|
||||
spec,
|
||||
|
@ -24,11 +27,14 @@ impl AudioBuffer {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the spec of the audio sample data that this buffer contains.
|
||||
#[inline]
|
||||
pub fn spec(&self) -> &AudioSpec {
|
||||
&self.spec
|
||||
}
|
||||
|
||||
/// Converts the audio sample data in this buffer to the spec given, returning the newly
|
||||
/// converted buffer.
|
||||
pub fn convert(self, to_spec: &AudioSpec) -> Result<Self, AudioBufferError> {
|
||||
if self.spec == *to_spec {
|
||||
Ok(self)
|
||||
|
|
|
@ -192,6 +192,8 @@ impl DataChunk {
|
|||
}
|
||||
|
||||
impl AudioBuffer {
|
||||
/// Loads the bytes of a WAV file into an [`AudioBuffer`]. The returned buffer will be in its
|
||||
/// original format and may need to be converted before it can be played.
|
||||
pub fn load_wav_bytes<T: ReadBytesExt + Seek>(reader: &mut T) -> Result<AudioBuffer, WavError> {
|
||||
let file_size = reader.stream_size()?;
|
||||
|
||||
|
@ -285,6 +287,8 @@ impl AudioBuffer {
|
|||
Ok(audio_buffer)
|
||||
}
|
||||
|
||||
/// Loads a WAV file into an [`AudioBuffer`]. The returned buffer will be in its original
|
||||
/// format and may need to be converted before it can be played.
|
||||
pub fn load_wav_file(path: &Path) -> Result<AudioBuffer, WavError> {
|
||||
let f = File::open(path)?;
|
||||
let mut reader = BufReader::new(f);
|
||||
|
|
|
@ -5,12 +5,27 @@ use thiserror::Error;
|
|||
|
||||
use crate::audio::*;
|
||||
|
||||
/// Represents a "channel" of audio playback that will be mixed together with all of the other
|
||||
/// actively playing audio channels to get the final audio playback.
|
||||
pub struct AudioChannel {
|
||||
/// Whether the channel is currently playing or not.
|
||||
pub playing: bool,
|
||||
/// Whether this channel is playing on a loop or not. If not, once the end of the [`data`]
|
||||
/// buffer is reached, or the [`AudioGenerator::gen_sample`] method returns `None`, playback
|
||||
/// on this channel will automatically stop and [`playing`] will be changed to `false`.
|
||||
pub loops: bool,
|
||||
/// The audio data buffer (samples) that this channel will play from, **only** if [`generator`]
|
||||
/// is `None`.
|
||||
pub data: Vec<u8>,
|
||||
/// An [`AudioGenerator`] instance that will be used to dynamically generate audio data to play
|
||||
/// on this channel _instead of_ playing from [`data`]. Set this to `None` to play from audio
|
||||
/// data in [`data`] instead.
|
||||
pub generator: Option<Box<dyn AudioGenerator>>,
|
||||
/// The volume level to play this channel at. 1.0 is "normal", 0.0 is completely silent.
|
||||
pub volume: f32,
|
||||
/// The current playback position (index). 0 is the start of playback. The end position is
|
||||
/// either the (current) size of the [`data`] buffer or dependant on the implementation of this
|
||||
/// channel's current [`generator`] if not `None`.
|
||||
pub position: usize,
|
||||
}
|
||||
|
||||
|
@ -26,6 +41,7 @@ impl AudioChannel {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the audio sample for the given position, or `None` if that position is invalid.
|
||||
#[inline]
|
||||
fn data_at(&mut self, position: usize) -> Option<u8> {
|
||||
if let Some(generator) = &mut self.generator {
|
||||
|
@ -79,6 +95,8 @@ impl AudioChannel {
|
|||
}
|
||||
}
|
||||
|
||||
/// Resets the audio channel to a "blank slate", clearing the audio buffer, setting no current
|
||||
/// audio generator, and turning playback off.
|
||||
#[inline]
|
||||
pub fn reset(&mut self) {
|
||||
self.data.clear();
|
||||
|
@ -87,6 +105,9 @@ impl AudioChannel {
|
|||
self.playing = false;
|
||||
}
|
||||
|
||||
/// Copies the data from the given audio buffer into this channel's buffer (clearing it first,
|
||||
/// and extending the size of the buffer if necessary) and then begins playback from position 0.
|
||||
/// This also sets the associated [`generator`] to `None`.
|
||||
#[inline]
|
||||
pub fn play_buffer(&mut self, buffer: &AudioBuffer, loops: bool) {
|
||||
self.data.clear();
|
||||
|
@ -97,6 +118,8 @@ impl AudioChannel {
|
|||
self.loops = loops;
|
||||
}
|
||||
|
||||
/// Begins playback on this channel from the given [`AudioGenerator`] instance from position 0.
|
||||
/// This also clears the existing audio buffer contents.
|
||||
#[inline]
|
||||
pub fn play_generator(&mut self, generator: Box<dyn AudioGenerator>, loops: bool) {
|
||||
self.data.clear();
|
||||
|
@ -106,11 +129,15 @@ impl AudioChannel {
|
|||
self.loops = loops;
|
||||
}
|
||||
|
||||
/// Returns true if this channel has something that can be played back currently.
|
||||
#[inline]
|
||||
pub fn is_playable(&self) -> bool {
|
||||
!self.data.is_empty() || self.generator.is_some()
|
||||
}
|
||||
|
||||
/// Begins playback on this channel, only if playback is currently possible with its current
|
||||
/// state (if it has some sample data in the buffer or if an [`AudioGenerator`] is set).
|
||||
/// Resets the position to 0 if playback is started and returns true, otherwise returns false.
|
||||
#[inline]
|
||||
pub fn play(&mut self, loops: bool) -> bool {
|
||||
if self.is_playable() {
|
||||
|
@ -123,6 +150,7 @@ impl AudioChannel {
|
|||
}
|
||||
}
|
||||
|
||||
/// Stops playback on this channel.
|
||||
#[inline]
|
||||
pub fn stop(&mut self) {
|
||||
self.playing = false;
|
||||
|
@ -140,12 +168,17 @@ pub enum AudioDeviceError {
|
|||
ChannelIndexOutOfRange(usize),
|
||||
}
|
||||
|
||||
/// Represents the audio device and performs mixing of all of the [`AudioChannel`]s that are
|
||||
/// currently playing. You should not be creating this manually, but obtaining it as needed via
|
||||
/// [`Audio::lock`].
|
||||
pub struct AudioDevice {
|
||||
spec: AudioSpec,
|
||||
channels: Vec<AudioChannel>,
|
||||
pub volume: f32,
|
||||
}
|
||||
|
||||
/// SDL audio callback implementation which performs audio mixing, generating the final sample data
|
||||
/// that will be played by the system's audio device.
|
||||
impl AudioCallback for AudioDevice {
|
||||
type Channel = u8;
|
||||
|
||||
|
@ -164,6 +197,7 @@ impl AudioCallback for AudioDevice {
|
|||
}
|
||||
|
||||
impl AudioDevice {
|
||||
/// Creates a new [`AudioDevice`] instance, using the given spec as its playback format.
|
||||
pub fn new(spec: AudioSpec) -> Self {
|
||||
let mut channels = Vec::new();
|
||||
for _ in 0..NUM_CHANNELS {
|
||||
|
@ -176,16 +210,21 @@ impl AudioDevice {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the spec that this device is currently set to play. All audio to be played via
|
||||
/// this device must be pre-converted to match this spec!
|
||||
#[inline]
|
||||
pub fn spec(&self) -> &AudioSpec {
|
||||
&self.spec
|
||||
}
|
||||
|
||||
/// Returns true if any of the audio channels are currently playing, false otherwise.
|
||||
#[inline]
|
||||
pub fn is_playing(&self) -> bool {
|
||||
self.channels.iter().any(|channel| channel.playing)
|
||||
}
|
||||
|
||||
/// Stops the specified channel's playback, or does nothing if that channel was not currently
|
||||
/// playing. This does not affect the channel's other state (data buffer, etc).
|
||||
pub fn stop_channel(&mut self, channel_index: usize) -> Result<(), AudioDeviceError> {
|
||||
if channel_index >= NUM_CHANNELS {
|
||||
Err(AudioDeviceError::ChannelIndexOutOfRange(channel_index))
|
||||
|
@ -195,12 +234,17 @@ impl AudioDevice {
|
|||
}
|
||||
}
|
||||
|
||||
/// Stops playback of all channels.
|
||||
pub fn stop_all(&mut self) {
|
||||
for channel in self.channels.iter_mut() {
|
||||
channel.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to play the given [`AudioBuffer`] on the first channel found that is not already
|
||||
/// playing. If a free channel is found, playback will be started by copying the buffer's
|
||||
/// contents to the channel. The index of the channel is returned. If playback was not started
|
||||
/// because no channel is free currently, then `None` is returned.
|
||||
pub fn play_buffer(
|
||||
&mut self,
|
||||
buffer: &AudioBuffer,
|
||||
|
@ -218,6 +262,8 @@ impl AudioDevice {
|
|||
}
|
||||
}
|
||||
|
||||
/// Plays the given [`AudioBuffer`] on the specified channel. Whatever that channel was playing
|
||||
/// will be interrupted and replaced with a copy of the given buffer's data.
|
||||
pub fn play_buffer_on_channel(
|
||||
&mut self,
|
||||
channel_index: usize,
|
||||
|
@ -234,6 +280,10 @@ impl AudioDevice {
|
|||
}
|
||||
}
|
||||
|
||||
/// Tries to play the given [`AudioGenerator`] on the first channel found that is not already
|
||||
/// playing. If a free channel is found, playback will be started and the index of the channel
|
||||
/// will be returned. If playback was not started because no channel is free currently, then
|
||||
/// `None` is returned.
|
||||
pub fn play_generator(
|
||||
&mut self,
|
||||
generator: Box<dyn AudioGenerator>,
|
||||
|
@ -247,6 +297,8 @@ impl AudioDevice {
|
|||
}
|
||||
}
|
||||
|
||||
/// Plays the given [`AudioGenerator`] on the specified channel. Whatever that channel was
|
||||
/// playing will be interrupted and replaced.
|
||||
pub fn play_generator_on_channel(
|
||||
&mut self,
|
||||
channel_index: usize,
|
||||
|
@ -261,41 +313,51 @@ impl AudioDevice {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator of any [`AudioChannel`]s that are currently playing.
|
||||
#[inline]
|
||||
pub fn playing_channels_iter(&mut self) -> impl Iterator<Item = &AudioChannel> {
|
||||
self.channels.iter().filter(|channel| channel.playing)
|
||||
}
|
||||
|
||||
/// Returns an iterator of mutable [`AudioChannel`]s that are currently playing.
|
||||
#[inline]
|
||||
pub fn playing_channels_iter_mut(&mut self) -> impl Iterator<Item = &mut AudioChannel> {
|
||||
self.channels.iter_mut().filter(|channel| channel.playing)
|
||||
}
|
||||
|
||||
/// Returns an iterator of [`AudioChannel`]s that are not currently playing.
|
||||
#[inline]
|
||||
pub fn stopped_channels_iter(&mut self) -> impl Iterator<Item = &AudioChannel> {
|
||||
self.channels.iter().filter(|channel| !channel.playing)
|
||||
}
|
||||
|
||||
/// Returns an iterator of mutable [`AudioChannel`]s that are not currently playing.
|
||||
#[inline]
|
||||
pub fn stopped_channels_iter_mut(&mut self) -> impl Iterator<Item = &mut AudioChannel> {
|
||||
self.channels.iter_mut().filter(|channel| !channel.playing)
|
||||
}
|
||||
|
||||
/// Returns an iterator of all [`AudioChannel`]s.
|
||||
#[inline]
|
||||
pub fn channels_iter(&mut self) -> impl Iterator<Item = &AudioChannel> {
|
||||
self.channels.iter()
|
||||
}
|
||||
|
||||
/// Returns an iterator of all [`AudioChannel`]s as mutable references.
|
||||
#[inline]
|
||||
pub fn channels_iter_mut(&mut self) -> impl Iterator<Item = &mut AudioChannel> {
|
||||
self.channels.iter_mut()
|
||||
}
|
||||
|
||||
/// Returns a reference to the specified [`AudioChannel`] or `None` if the index specified
|
||||
/// is not valid.
|
||||
#[inline]
|
||||
pub fn get(&self, index: usize) -> Option<&AudioChannel> {
|
||||
self.channels.get(index)
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the specified [`AudioChannel`] or `None` if the index
|
||||
/// specified is not valid.
|
||||
#[inline]
|
||||
pub fn get_mut(&mut self, index: usize) -> Option<&mut AudioChannel> {
|
||||
self.channels.get_mut(index)
|
||||
|
@ -305,6 +367,8 @@ impl AudioDevice {
|
|||
impl Index<usize> for AudioDevice {
|
||||
type Output = AudioChannel;
|
||||
|
||||
/// Returns a reference to the specified [`AudioChannel`] or panics if the index specified is
|
||||
/// not valid.
|
||||
#[inline]
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
self.get(index).unwrap()
|
||||
|
@ -312,6 +376,8 @@ impl Index<usize> for AudioDevice {
|
|||
}
|
||||
|
||||
impl IndexMut<usize> for AudioDevice {
|
||||
/// Returns a mutable reference to the specified [`AudioChannel`] or panics if the index
|
||||
/// specified is not valid.
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
self.get_mut(index).unwrap()
|
||||
|
|
|
@ -10,6 +10,7 @@ pub mod buffer;
|
|||
pub mod device;
|
||||
pub mod queue;
|
||||
|
||||
/// The number of simultaneously playing audio channels supported by this library currently.
|
||||
pub const NUM_CHANNELS: usize = 8;
|
||||
|
||||
pub const AUDIO_FREQUENCY_44KHZ: u32 = 44100;
|
||||
|
@ -18,11 +19,15 @@ pub const AUDIO_FREQUENCY_11KHZ: u32 = 11025;
|
|||
|
||||
pub const SILENCE: u8 = AudioFormatNum::SILENCE;
|
||||
|
||||
/// The target audio frequency supported by this library currently.
|
||||
pub const TARGET_AUDIO_FREQUENCY: u32 = AUDIO_FREQUENCY_22KHZ;
|
||||
/// The number of channels per audio buffer supported by this library currently.
|
||||
pub const TARGET_AUDIO_CHANNELS: u8 = 1;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Represents an "audio specification" for an audio buffer or the audio device itself. Useful
|
||||
/// to know what format an audio buffer is in and to specify conversion formats, etc.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct AudioSpec {
|
||||
frequency: u32,
|
||||
|
@ -31,6 +36,13 @@ pub struct AudioSpec {
|
|||
}
|
||||
|
||||
impl AudioSpec {
|
||||
/// Creates a new `AudioSpec` with the properties specified.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `frequency`: the frequency of the audio
|
||||
/// * `channels`: the number of channels of the audio (e.g. 1 = mono, 2 = stereo, etc)
|
||||
/// * `format`: indicates the format of the bytes making up the audio buffer.
|
||||
pub fn new(frequency: u32, channels: u8, format: AudioFormat) -> Self {
|
||||
AudioSpec {
|
||||
frequency,
|
||||
|
@ -49,6 +61,8 @@ impl AudioSpec {
|
|||
self.channels
|
||||
}
|
||||
|
||||
/// An SDL2 [`sdl2::audio::AudioFormat`] value indicating the audio format of the bytes making
|
||||
/// up an audio buffer.
|
||||
#[inline]
|
||||
pub fn format(&self) -> AudioFormat {
|
||||
self.format
|
||||
|
@ -57,7 +71,12 @@ impl AudioSpec {
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// NOTE: this is currently hardcoded such that 8-bit samples must always be used!
|
||||
|
||||
/// Used to implement custom/dynamic audio generation.
|
||||
pub trait AudioGenerator: Send {
|
||||
/// Generates and returns the sample for the given playback position. `None` is returned if
|
||||
/// there is no sample for that position (e.g. it might be past the "end").
|
||||
fn gen_sample(&mut self, position: usize) -> Option<u8>;
|
||||
}
|
||||
|
||||
|
@ -69,12 +88,20 @@ pub enum AudioError {
|
|||
OpenDeviceFailed(String),
|
||||
}
|
||||
|
||||
/// Top-level abstraction over the system's audio output device. To play audio or change other
|
||||
/// playback properties, you will need to lock the audio device via [`Audio::lock`] to obtain an
|
||||
/// [`AudioDevice`].
|
||||
pub struct Audio {
|
||||
spec: AudioSpec,
|
||||
sdl_audio_device: sdl2::audio::AudioDevice<AudioDevice>,
|
||||
}
|
||||
|
||||
impl Audio {
|
||||
/// Creates a new [`Audio`] instance, wrapping the given SDL [`sdl2::audio::AudioSubsystem`].
|
||||
/// The `desired_spec` given specifies the target audio playback format.
|
||||
///
|
||||
/// Ideally, you should not be creating an instance of this yourself and should just use the
|
||||
/// one provided by [`crate::system::System`].
|
||||
pub fn new(
|
||||
desired_spec: AudioSpecDesired,
|
||||
sdl_audio_subsystem: &AudioSubsystem,
|
||||
|
@ -106,26 +133,36 @@ impl Audio {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns current audio device's audio specification/format for playback. All [`AudioBuffer`]s
|
||||
/// that are to be used for playback must be converted to match this before they can be played.
|
||||
#[inline]
|
||||
pub fn spec(&self) -> &AudioSpec {
|
||||
&self.spec
|
||||
}
|
||||
|
||||
/// Returns the current status of the audio device (e.g. whether it is paused, stopped, etc).
|
||||
#[inline]
|
||||
pub fn status(&self) -> sdl2::audio::AudioStatus {
|
||||
self.sdl_audio_device.status()
|
||||
}
|
||||
|
||||
/// Pauses all audio playback.
|
||||
#[inline]
|
||||
pub fn pause(&mut self) {
|
||||
self.sdl_audio_device.pause()
|
||||
}
|
||||
|
||||
/// Resumes all audio playback.
|
||||
#[inline]
|
||||
pub fn resume(&mut self) {
|
||||
self.sdl_audio_device.resume()
|
||||
}
|
||||
|
||||
/// Locks the audio device so that new audio data can be provided or playback altered. A
|
||||
/// [`AudioDevice`] instance is returned on successful lock which can be used to interact with
|
||||
/// the actual system's audio playback. The audio device is unlocked once this instance is
|
||||
/// dropped. Ideally, you will want to keep the audio device for **as _short_ a time as
|
||||
/// possible!**
|
||||
#[inline]
|
||||
pub fn lock(&mut self) -> sdl2::audio::AudioDeviceLockGuard<AudioDevice> {
|
||||
self.sdl_audio_device.lock()
|
||||
|
|
|
@ -35,12 +35,18 @@ pub enum AudioCommand {
|
|||
},
|
||||
}
|
||||
|
||||
/// A convenience abstraction that can be used to queue up commands to be issued to an
|
||||
/// [`AudioDevice`]. This can be more useful to utilize in applications versus needing to directly
|
||||
/// lock the [`AudioDevice`] and then determine what your application needs to do and issue those
|
||||
/// commands that time. [`AudioQueue`] lets you play/stop audio in more of a "fire-and-forget"
|
||||
/// manner.
|
||||
pub struct AudioQueue {
|
||||
spec: AudioSpec,
|
||||
commands: VecDeque<AudioCommand>,
|
||||
}
|
||||
|
||||
impl AudioQueue {
|
||||
/// Creates and returns a new [`AudioQueue`] instance.
|
||||
pub fn new(audio: &Audio) -> Self {
|
||||
AudioQueue {
|
||||
spec: audio.spec,
|
||||
|
@ -48,11 +54,15 @@ impl AudioQueue {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the spec that this queue is currently set to play. All audio to be played via
|
||||
/// this queue must be pre-converted to match this spec! This spec is a copy of the one that
|
||||
/// was obtained from the [`Audio`] instance used to create this [`AudioQueue`].
|
||||
#[inline]
|
||||
pub fn spec(&self) -> &AudioSpec {
|
||||
&self.spec
|
||||
}
|
||||
|
||||
/// Queues a stop command for the given channel.
|
||||
pub fn stop_channel(&mut self, channel_index: usize) -> Result<(), AudioDeviceError> {
|
||||
if channel_index >= NUM_CHANNELS {
|
||||
Err(AudioDeviceError::ChannelIndexOutOfRange(channel_index))
|
||||
|
@ -62,10 +72,14 @@ impl AudioQueue {
|
|||
}
|
||||
}
|
||||
|
||||
/// Queues a command that will stop playback on all channels.
|
||||
pub fn stop_all(&mut self) {
|
||||
self.commands.push_back(AudioCommand::StopAllChannels);
|
||||
}
|
||||
|
||||
/// Queues a command to play a copy of the given [`AudioBuffer`]'s data. The buffer will be
|
||||
/// played on the first channel found that is not already playing. If all channels are already
|
||||
/// playing, then nothing will be done.
|
||||
pub fn play_buffer(
|
||||
&mut self,
|
||||
buffer: &AudioBuffer,
|
||||
|
@ -82,6 +96,10 @@ impl AudioQueue {
|
|||
}
|
||||
}
|
||||
|
||||
/// Queues a command to play the given [`AudioBuffer`]'s data. The buffer will be played on
|
||||
/// the first channel found that is not already playing. If all channels are already playing,
|
||||
/// then nothing will be done. This method is more performant than [`AudioQueue::play_buffer`],
|
||||
/// as that method will always immediately copy the given buffer to create the queued command.
|
||||
pub fn play_buffer_rc(
|
||||
&mut self,
|
||||
buffer: Rc<AudioBuffer>,
|
||||
|
@ -98,6 +116,9 @@ impl AudioQueue {
|
|||
}
|
||||
}
|
||||
|
||||
/// Queues a command to play a copy of the given [`AudioBuffer`]'s data on the channel
|
||||
/// specified. Whatever that channel was playing will be interrupted to begin playing this
|
||||
/// buffer.
|
||||
pub fn play_buffer_on_channel(
|
||||
&mut self,
|
||||
channel_index: usize,
|
||||
|
@ -118,6 +139,10 @@ impl AudioQueue {
|
|||
}
|
||||
}
|
||||
|
||||
/// Queues a command to play the given [`AudioBuffer`]'s data on the channel specified. Whatever
|
||||
/// that channel was playing will be interrupted to begin playing this buffer. This method is
|
||||
/// more performant than [`AudioQueue::play_buffer_on_channel`], as that method will always
|
||||
/// immediately copy the given buffer to create the queued command.
|
||||
pub fn play_buffer_rc_on_channel(
|
||||
&mut self,
|
||||
channel_index: usize,
|
||||
|
@ -138,6 +163,8 @@ impl AudioQueue {
|
|||
}
|
||||
}
|
||||
|
||||
/// Queues a command to play the given [`AudioGenerator`] on the first channel found that is
|
||||
/// not already playing. If all channels are already playing, then nothing will be done.
|
||||
pub fn play_generator(
|
||||
&mut self,
|
||||
generator: Box<dyn AudioGenerator>,
|
||||
|
@ -147,6 +174,8 @@ impl AudioQueue {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Queues a command to play the given [`AudioGenerator`] on the channel specified. Whatever
|
||||
/// that channel was playing will be interrupted to begin playing this generator.
|
||||
pub fn play_generator_on_channel(
|
||||
&mut self,
|
||||
channel_index: usize,
|
||||
|
@ -161,6 +190,8 @@ impl AudioQueue {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Flushes the queued commands, issuing them in the same order they were created, to the
|
||||
/// given [`AudioDevice`].
|
||||
pub fn apply_to_device(&mut self, device: &mut AudioDevice) -> Result<(), AudioDeviceError> {
|
||||
loop {
|
||||
if let Some(command) = self.commands.pop_front() {
|
||||
|
@ -197,6 +228,10 @@ impl AudioQueue {
|
|||
}
|
||||
}
|
||||
|
||||
/// Flushes the queued commands, issuing them in the same order they were created, to the
|
||||
/// given [`Audio`] instance. This method automatically handles obtaining a locked
|
||||
/// [`AudioDevice`], and so is a bit more convenient to use if you don't actually need to
|
||||
/// interact with the [`AudioDevice`] itself in your code.
|
||||
pub fn apply(&mut self, audio: &mut Audio) -> Result<(), AudioDeviceError> {
|
||||
let mut device = audio.lock();
|
||||
self.apply_to_device(&mut device)
|
||||
|
|
|
@ -303,7 +303,13 @@ pub struct System {
|
|||
target_framerate_delta: Option<i64>,
|
||||
next_tick: i64,
|
||||
|
||||
/// An [`Audio`] instance that allows interacting with the system's audio output device.
|
||||
pub audio: Audio,
|
||||
|
||||
/// An [`AudioQueue`] instance that can queue up playback/stop commands to be issued to the
|
||||
/// system's [`Audio`] instance a bit more flexibly. If you use this, your application must
|
||||
/// manually call [`AudioQueue::apply`] or [`AudioQueue::apply_to_device`] in your loop to
|
||||
/// flush the queued commands, otherwise this queue will not do anything.
|
||||
pub audio_queue: AudioQueue,
|
||||
|
||||
/// The primary backbuffer [`Bitmap`] that will be rendered to the screen whenever
|
||||
|
|
Loading…
Reference in a new issue