custom rodio source for audio (#145)

support custom rodio source for audio
This commit is contained in:
Cory Forsstrom 2020-09-08 13:56:45 -07:00 committed by GitHub
parent 9c850057c0
commit 2667c24656
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 20 deletions

2
.gitignore vendored
View file

@ -5,4 +5,4 @@ Cargo.lock
.cargo/config
/.idea
/.vscode
/benches/target
/benches/target

View file

@ -1,17 +1,23 @@
use crate::AudioSource;
use crate::{AudioSource, Decodable};
use bevy_asset::{Assets, Handle};
use bevy_ecs::Res;
use parking_lot::RwLock;
use rodio::{Decoder, Device, Sink};
use std::{collections::VecDeque, io::Cursor};
use rodio::{Device, Sink};
use std::collections::VecDeque;
/// Used to play audio on the current "audio device"
pub struct AudioOutput {
pub struct AudioOutput<P = AudioSource>
where
P: Decodable,
{
device: Device,
queue: RwLock<VecDeque<Handle<AudioSource>>>,
queue: RwLock<VecDeque<Handle<P>>>,
}
impl Default for AudioOutput {
impl<P> Default for AudioOutput<P>
where
P: Decodable,
{
fn default() -> Self {
Self {
device: rodio::default_output_device().unwrap(),
@ -20,18 +26,23 @@ impl Default for AudioOutput {
}
}
impl AudioOutput {
pub fn play_source(&self, audio_source: &AudioSource) {
impl<P> AudioOutput<P>
where
P: Decodable,
<P as Decodable>::Decoder: rodio::Source + Send + Sync,
<<P as Decodable>::Decoder as Iterator>::Item: rodio::Sample + Send + Sync,
{
pub fn play_source(&self, audio_source: &P) {
let sink = Sink::new(&self.device);
sink.append(Decoder::new(Cursor::new(audio_source.clone())).unwrap());
sink.append(audio_source.decoder());
sink.detach();
}
pub fn play(&self, audio_source: Handle<AudioSource>) {
pub fn play(&self, audio_source: Handle<P>) {
self.queue.write().push_front(audio_source);
}
pub fn try_play_queued(&self, audio_sources: &Assets<AudioSource>) {
pub fn try_play_queued(&self, audio_sources: &Assets<P>) {
let mut queue = self.queue.write();
let len = queue.len();
let mut i = 0;
@ -49,9 +60,11 @@ impl AudioOutput {
}
/// Plays audio currently queued in the [AudioOutput] resource
pub(crate) fn play_queued_audio_system(
audio_sources: Res<Assets<AudioSource>>,
audio_output: Res<AudioOutput>,
) {
pub fn play_queued_audio_system<P>(audio_sources: Res<Assets<P>>, audio_output: Res<AudioOutput<P>>)
where
P: Decodable,
<P as Decodable>::Decoder: rodio::Source + Send + Sync,
<<P as Decodable>::Decoder as Iterator>::Item: rodio::Sample + Send + Sync,
{
audio_output.try_play_queued(&audio_sources);
}

View file

@ -1,6 +1,6 @@
use anyhow::Result;
use bevy_asset::AssetLoader;
use std::{path::Path, sync::Arc};
use std::{io::Cursor, path::Path, sync::Arc};
/// A source of audio data
#[derive(Clone)]
@ -30,3 +30,17 @@ impl AssetLoader<AudioSource> for Mp3Loader {
EXTENSIONS
}
}
pub trait Decodable: Send + Sync + 'static {
type Decoder;
fn decoder(&self) -> Self::Decoder;
}
impl Decodable for AudioSource {
type Decoder = rodio::Decoder<Cursor<AudioSource>>;
fn decoder(&self) -> Self::Decoder {
rodio::Decoder::new(Cursor::new(self.clone())).unwrap()
}
}

View file

@ -5,7 +5,7 @@ pub use audio_output::*;
pub use audio_source::*;
pub mod prelude {
pub use crate::{AudioOutput, AudioSource};
pub use crate::{AudioOutput, AudioSource, Decodable};
}
use bevy_app::prelude::*;
@ -18,9 +18,12 @@ pub struct AudioPlugin;
impl Plugin for AudioPlugin {
fn build(&self, app: &mut AppBuilder) {
app.init_resource::<AudioOutput>()
app.init_resource::<AudioOutput<AudioSource>>()
.add_asset::<AudioSource>()
.add_asset_loader::<AudioSource, Mp3Loader>()
.add_system_to_stage(stage::POST_UPDATE, play_queued_audio_system.system());
.add_system_to_stage(
stage::POST_UPDATE,
play_queued_audio_system::<AudioSource>.system(),
);
}
}