bevy_kira_components/
lib.rs

1//! Add audio support to Bevy through the [`kira`] crate.
2//!
3//! This crate aims at creating a replacement for `bevy_audio` by instead integrating Kira, a crate
4//! for audio playback aimed at games, and used in several other Rust projects.
5//!
6//! This particular crate is an experiment in making a component-based ECS API, instead of a
7//! resource-based approach, currently taken by `bevy_kira_audio`.
8//!
9//! To get started playing sounds, insert an [`AudioBundle`](prelude::AudioBundle) on an entity.
10//! This is a generic bundle which supports any compatible sound source. An implementation over
11//! audio files is provided, with streaming support, using the
12//! [`AudioFileBundle`](prelude::AudioFileBundle) type alias.
13//!
14//! When an [`AudioFile`](prelude::AudioFile) is inserted, its playback will begin right away. To
15//! prevent that, use the [`start_paused`](prelude::AudioFileSettings) field from
16//! [`AudioFileBundle::settings`](prelude::AudioFileBundle::settings) and set it to false.
17//!
18//! The audio system creates an [`AudioHandle`](prelude::AudioHandle) component when registering an
19//! added sound for
20//! playback. This handle allows you to control the sound. For [`AudioFile`](prelude::AudioFile)s,
21//! this means pausing/resuming, setting the volume, panning, and playback rate of the sound.
22//!
23//! Spatial audio is supported built-in with the [`SpatialEmitter`](prelude::SpatialEmitter)
24//! component, which tells the plugin to add the entity as an emitter, provided it also has a
25//! [`GlobalTransform`] component attached. Its settings control the behavior of the spatial effect.
26//!
27//! ## Example
28//!
29//! ```rust
30//! use bevy::prelude::*;
31//! use bevy_kira_components::prelude::*;
32//!
33//! fn main() {
34//!     App::new()
35//!         .insert_non_send_resource(AudioSettings {
36//!             // Only needed for tests
37//!             backend_settings: AudioBackendSelector::Mock { sample_rate: 48000, },
38//!             ..default()
39//!         })
40//!         .add_plugins((DefaultPlugins, AudioPlugin))
41//!         .add_systems(Startup, add_sound)
42//!         .run();
43//! }
44//!
45//! fn add_sound(mut commands: Commands, asset_server: Res<AssetServer>) {
46//!     commands.spawn(AudioFileBundle {
47//!         source: asset_server.load("my_sound.ogg"),
48//!         ..default()
49//!     });
50//! }
51//! ```
52#![warn(missing_docs)]
53
54use bevy::prelude::*;
55use bevy::transform::TransformSystem;
56pub use kira;
57use kira::manager::{AudioManager, AudioManagerSettings};
58
59use crate::backend::AudioBackend;
60use crate::sources::audio_file::AudioFilePlugin;
61use crate::spatial::SpatialAudioPlugin;
62
63mod backend;
64pub mod diagnostics;
65pub mod sources;
66pub mod spatial;
67
68#[doc(hidden)]
69#[allow(missing_docs)]
70pub mod prelude {
71    pub use super::{AudioPlaybackSet, AudioPlugin, AudioSettings, AudioWorld};
72    pub use crate::backend::*;
73    pub use crate::sources::prelude::*;
74    pub use crate::spatial::prelude::*;
75}
76
77/// Type of settings for the audio engine. Insert it as a resource before adding the plugin to
78/// change the default settings.
79pub type AudioSettings = AudioManagerSettings<AudioBackend>;
80
81/// System set used in grouping systems that setup audio sources. Used in the
82/// [`AudioSourcePlugin`](prelude::AudioSourcePlugin)'s systems. Useful to place systems right
83/// after to be able to react to added audio assets.
84#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, SystemSet)]
85pub struct AudioSourceSetup;
86
87/// General audio system set, used by the systems in this plugin.
88#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, SystemSet)]
89pub enum AudioPlaybackSet {
90    /// Systems related to setting up audio sources, registering them with the audio engine, and
91    /// bookkeeping handles.
92    Setup,
93    /// Systems related to keeping the audio engine in sync with Bevy's world. Mainly used by the
94    /// spatial systems to copy position and rotation information from listeners and emitters.
95    Update,
96    /// Systems that clean up resources. Handles that have finished playing or are no longer
97    /// useful, are removed automatically here.
98    Cleanup,
99}
100
101/// Adds audio to Bevy games via the [`kira`] crate.
102#[derive(Debug, Default)]
103pub struct AudioPlugin;
104
105impl Plugin for AudioPlugin {
106    fn build(&self, app: &mut App) {
107        app.init_resource::<AudioWorld>()
108            .add_plugins((
109                #[cfg(feature = "diagnostics")]
110                diagnostics::KiraStatisticsDiagnosticPlugin,
111                SpatialAudioPlugin,
112                AudioFilePlugin,
113            ))
114            .configure_sets(PreUpdate, AudioPlaybackSet::Setup)
115            .configure_sets(
116                PostUpdate,
117                AudioPlaybackSet::Update.after(TransformSystem::TransformPropagate),
118            );
119    }
120}
121
122/// Main resource holding all the bookkeeping necessary to link the ECS data to the audio engine.
123#[derive(Resource)]
124pub struct AudioWorld {
125    pub(crate) audio_manager: AudioManager<AudioBackend>,
126}
127
128impl FromWorld for AudioWorld {
129    fn from_world(world: &mut World) -> Self {
130        let audio_manager_settings = world
131            .remove_non_send_resource::<AudioSettings>()
132            .unwrap_or_default();
133        let audio_manager =
134            AudioManager::new(audio_manager_settings).expect("Cannot create audio backend");
135        Self { audio_manager }
136    }
137}
138
139#[derive(Component)]
140#[doc(hidden)]
141/// Internal marker for entities with audio components. Needed to be able to query in a
142/// non-generic way for having added audio support through the [`AudioBundle`] struct.
143pub struct InternalAudioMarker;