mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 06:00:20 +00:00
audio: initial (very minimal) audio plugin
This commit is contained in:
parent
af109174dd
commit
3eb393548d
10 changed files with 139 additions and 0 deletions
|
@ -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 a new issue