Skip to content

Commit

Permalink
custom rodio source for audio (bevyengine#145)
Browse files Browse the repository at this point in the history
support custom rodio source for audio
  • Loading branch information
tarkah authored and mrk-its committed Oct 6, 2020
1 parent 164aed6 commit 64846d8
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ Cargo.lock
.cargo/config
/.idea
/.vscode
/benches/target
/benches/target
43 changes: 28 additions & 15 deletions crates/bevy_audio/src/audio_output.rs
Original file line number Diff line number Diff line change
@@ -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(),
Expand All @@ -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;
Expand All @@ -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);
}
16 changes: 15 additions & 1 deletion crates/bevy_audio/src/audio_source.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -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()
}
}
9 changes: 6 additions & 3 deletions crates/bevy_audio/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand All @@ -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(),
);
}
}

0 comments on commit 64846d8

Please sign in to comment.