Skip to content

Commit

Permalink
init draft of custom rodio source for audio
Browse files Browse the repository at this point in the history
  • Loading branch information
tarkah committed Aug 19, 2020
1 parent 6ffe069 commit fc26e1d
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 21 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
**/*.rs.bk
Cargo.lock
.cargo/config
/.idea
/.idea
/.vscode
43 changes: 28 additions & 15 deletions crates/bevy_audio/src/audio_output.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
use crate::AudioSource;
use crate::Decodable;
use bevy_asset::{Assets, Handle};
use bevy_ecs::Res;
use rodio::{Decoder, Device, Sink};
use std::{collections::VecDeque, io::Cursor, sync::RwLock};
use rodio::{Device, Sink};
use std::{collections::VecDeque, sync::RwLock};

/// Used to play audio on the current "audio device"
pub struct AudioOutput {
pub struct AudioOutput<P>
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 @@ -19,18 +25,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().unwrap().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().unwrap();
let len = queue.len();
let mut i = 0;
Expand All @@ -48,9 +59,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(),
);
}
}
2 changes: 1 addition & 1 deletion examples/audio/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn main() {
.run();
}

fn setup(asset_server: Res<AssetServer>, audio_output: Res<AudioOutput>) {
fn setup(asset_server: Res<AssetServer>, audio_output: Res<AudioOutput<AudioSource>>) {
let music = asset_server
.load("assets/sounds/Windless Slopes.mp3")
.unwrap();
Expand Down

0 comments on commit fc26e1d

Please sign in to comment.