audio: initial (very minimal) audio plugin
This commit is contained in:
		
							parent
							
								
									af109174dd
								
							
						
					
					
						commit
						3eb393548d
					
				@ -17,6 +17,7 @@ members = [
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
# bevy
 | 
			
		||||
bevy_audio = { path = "crates/bevy_audio" }
 | 
			
		||||
bevy_app = { path = "crates/bevy_app" }
 | 
			
		||||
bevy_asset = { path = "crates/bevy_asset" }
 | 
			
		||||
bevy_type_registry = { path = "crates/bevy_type_registry" }
 | 
			
		||||
@ -115,6 +116,10 @@ path = "examples/asset/hot_asset_reloading.rs"
 | 
			
		||||
name = "asset_loading"
 | 
			
		||||
path = "examples/asset/asset_loading.rs"
 | 
			
		||||
 | 
			
		||||
[[example]]
 | 
			
		||||
name = "audio"
 | 
			
		||||
path = "examples/audio/audio.rs"
 | 
			
		||||
 | 
			
		||||
[[example]]
 | 
			
		||||
name = "custom_diagnostic"
 | 
			
		||||
path = "examples/diagnostics/custom_diagnostic.rs"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								assets/sounds/Windless Slopes.mp3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/sounds/Windless Slopes.mp3
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										14
									
								
								crates/bevy_audio/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								crates/bevy_audio/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
			
		||||
[package]
 | 
			
		||||
authors = ["Carter Anderson <mcanders1@gmail.com>"]
 | 
			
		||||
edition = "2018"
 | 
			
		||||
name = "bevy_audio"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
 | 
			
		||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
bevy_app = {path = "../bevy_app"}
 | 
			
		||||
bevy_asset = {path = "../bevy_asset"}
 | 
			
		||||
bevy_ecs = {path = "../bevy_ecs"}
 | 
			
		||||
anyhow = "1.0"
 | 
			
		||||
rodio = {version = "0.11", default-features = false, features = ["mp3"]}
 | 
			
		||||
							
								
								
									
										54
									
								
								crates/bevy_audio/src/audio_output.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								crates/bevy_audio/src/audio_output.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,54 @@
 | 
			
		||||
use crate::AudioSource;
 | 
			
		||||
use bevy_asset::{Assets, Handle};
 | 
			
		||||
use bevy_ecs::Res;
 | 
			
		||||
use rodio::{Decoder, Device, Sink};
 | 
			
		||||
use std::{collections::VecDeque, io::Cursor, sync::RwLock};
 | 
			
		||||
 | 
			
		||||
pub struct AudioOutput {
 | 
			
		||||
    device: Device,
 | 
			
		||||
    queue: RwLock<VecDeque<Handle<AudioSource>>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for AudioOutput {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            device: rodio::default_output_device().unwrap(),
 | 
			
		||||
            queue: Default::default(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl AudioOutput {
 | 
			
		||||
    pub fn play(&self, audio_source: &AudioSource) {
 | 
			
		||||
        let sink = Sink::new(&self.device);
 | 
			
		||||
        sink.append(Decoder::new(Cursor::new(audio_source.clone())).unwrap());
 | 
			
		||||
        sink.detach();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn queue_play(&self, audio_source: Handle<AudioSource>) {
 | 
			
		||||
        self.queue.write().unwrap().push_front(audio_source);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn try_play_queued(&self, audio_sources: &Assets<AudioSource>) {
 | 
			
		||||
        let mut queue = self.queue.write().unwrap();
 | 
			
		||||
        let len = queue.len();
 | 
			
		||||
        let mut i = 0;
 | 
			
		||||
        while i < len {
 | 
			
		||||
            let audio_source_handle = queue.pop_back().unwrap();
 | 
			
		||||
            if let Some(audio_source) = audio_sources.get(&audio_source_handle) {
 | 
			
		||||
                self.play(audio_source);
 | 
			
		||||
            } else {
 | 
			
		||||
                // audio source hasn't loaded yet. add it back to the queue
 | 
			
		||||
                queue.push_front(audio_source_handle);
 | 
			
		||||
            }
 | 
			
		||||
            i += 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn play_queued_audio_system(
 | 
			
		||||
    audio_sources: Res<Assets<AudioSource>>,
 | 
			
		||||
    audio_output: Res<AudioOutput>,
 | 
			
		||||
) {
 | 
			
		||||
    audio_output.try_play_queued(&audio_sources);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								crates/bevy_audio/src/audio_source.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								crates/bevy_audio/src/audio_source.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use bevy_asset::AssetLoader;
 | 
			
		||||
use std::{sync::Arc, path::Path};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct AudioSource {
 | 
			
		||||
    pub bytes: Arc<Vec<u8>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl AsRef<[u8]> for AudioSource {
 | 
			
		||||
    fn as_ref(&self) -> &[u8] {
 | 
			
		||||
        &self.bytes
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Default)]
 | 
			
		||||
pub struct Mp3Loader;
 | 
			
		||||
 | 
			
		||||
impl AssetLoader<AudioSource> for Mp3Loader {
 | 
			
		||||
    fn from_bytes(&self, _asset_path: &Path, bytes: Vec<u8>) -> Result<AudioSource> {
 | 
			
		||||
        Ok(AudioSource { bytes: Arc::new(bytes) })
 | 
			
		||||
    }
 | 
			
		||||
    fn extensions(&self) -> &[&str] {
 | 
			
		||||
        static EXTENSIONS: &[&str] = &["mp3"];
 | 
			
		||||
        EXTENSIONS
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								crates/bevy_audio/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								crates/bevy_audio/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
mod audio_output;
 | 
			
		||||
mod audio_source;
 | 
			
		||||
 | 
			
		||||
pub use audio_output::*;
 | 
			
		||||
pub use audio_source::*;
 | 
			
		||||
 | 
			
		||||
use bevy_app::{stage, AppBuilder, AppPlugin};
 | 
			
		||||
use bevy_asset::AddAsset;
 | 
			
		||||
use bevy_ecs::IntoQuerySystem;
 | 
			
		||||
 | 
			
		||||
#[derive(Default)]
 | 
			
		||||
pub struct AudioPlugin;
 | 
			
		||||
 | 
			
		||||
impl AppPlugin for AudioPlugin {
 | 
			
		||||
    fn build(&self, app: &mut AppBuilder) {
 | 
			
		||||
        app.init_resource::<AudioOutput>()
 | 
			
		||||
            .add_asset::<AudioSource>()
 | 
			
		||||
            .add_asset_loader::<AudioSource, Mp3Loader>()
 | 
			
		||||
            .add_system_to_stage(stage::POST_UPDATE, play_queued_audio_system.system());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								examples/audio/audio.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								examples/audio/audio.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
use bevy::prelude::*;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    App::build()
 | 
			
		||||
        .add_default_plugins()
 | 
			
		||||
        .add_startup_system(setup.system())
 | 
			
		||||
        .run();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn setup(asset_server: Res<AssetServer>, audio_output: Res<AudioOutput>) {
 | 
			
		||||
    let music = asset_server
 | 
			
		||||
        .load("assets/sounds/Windless Slopes.mp3")
 | 
			
		||||
        .unwrap();
 | 
			
		||||
    audio_output.queue_play(music);
 | 
			
		||||
}
 | 
			
		||||
@ -19,6 +19,7 @@ impl AddDefaultPlugins for AppBuilder {
 | 
			
		||||
        self.add_plugin(bevy_ui::UiPlugin::default());
 | 
			
		||||
        self.add_plugin(bevy_gltf::GltfPlugin::default());
 | 
			
		||||
        self.add_plugin(bevy_text::TextPlugin::default());
 | 
			
		||||
        self.add_plugin(bevy_audio::AudioPlugin::default());
 | 
			
		||||
 | 
			
		||||
        #[cfg(feature = "bevy_winit")]
 | 
			
		||||
        self.add_plugin(bevy_winit::WinitPlugin::default());
 | 
			
		||||
 | 
			
		||||
@ -46,6 +46,7 @@ pub use bevy_app as app;
 | 
			
		||||
pub use glam as math;
 | 
			
		||||
 | 
			
		||||
pub use bevy_asset as asset;
 | 
			
		||||
pub use bevy_audio as audio;
 | 
			
		||||
pub use bevy_core as core;
 | 
			
		||||
pub use bevy_diagnostic as diagnostic;
 | 
			
		||||
pub use bevy_ecs as ecs;
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ pub use crate::{
 | 
			
		||||
        EventReader, Events,
 | 
			
		||||
    },
 | 
			
		||||
    asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle},
 | 
			
		||||
    audio::{AudioOutput, AudioSource},
 | 
			
		||||
    core::{
 | 
			
		||||
        time::{Time, Timer},
 | 
			
		||||
        transform::FaceToward,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user