Skip to main content

bevy_audio/
lib.rs

1#![forbid(unsafe_code)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc(
4    html_logo_url = "https://bevy.org/assets/icon.png",
5    html_favicon_url = "https://bevy.org/assets/icon.png"
6)]
7
8//! Audio support for the game engine Bevy
9//!
10//! ```no_run
11//! # use bevy_ecs::prelude::*;
12//! # use bevy_audio::{AudioPlayer, AudioPlugin, AudioSource, PlaybackSettings};
13//! # use bevy_asset::{AssetPlugin, AssetServer};
14//! # use bevy_app::{App, AppExit, NoopPluginGroup as MinimalPlugins, Startup};
15//! fn main() {
16//!    App::new()
17//!         .add_plugins((MinimalPlugins, AssetPlugin::default(), AudioPlugin::default()))
18//!         .add_systems(Startup, play_background_audio)
19//!         .run();
20//! }
21//!
22//! fn play_background_audio(asset_server: Res<AssetServer>, mut commands: Commands) {
23//!     commands.spawn((
24//!         AudioPlayer::new(asset_server.load("background_audio.ogg")),
25//!         PlaybackSettings::LOOP,
26//!     ));
27//! }
28//! ```
29
30extern crate alloc;
31
32mod audio;
33mod audio_output;
34mod audio_source;
35mod pitch;
36mod sinks;
37mod volume;
38
39/// The audio prelude.
40///
41/// This includes the most common types in this crate, re-exported for your convenience.
42pub mod prelude {
43    #[doc(hidden)]
44    pub use crate::{
45        AudioPlayer, AudioSink, AudioSinkPlayback, AudioSource, Decodable, GlobalVolume, Pitch,
46        PlaybackSettings, SpatialAudioSink, SpatialListener,
47    };
48}
49
50pub use audio::*;
51pub use audio_source::*;
52pub use pitch::*;
53pub use volume::*;
54
55pub use rodio::{cpal::Sample as CpalSample, source::Source, Sample};
56pub use sinks::*;
57
58use bevy_app::prelude::*;
59use bevy_asset::{Asset, AssetApp};
60use bevy_ecs::prelude::*;
61use bevy_transform::TransformSystems;
62
63use audio_output::*;
64
65/// Set for the audio playback systems, so they can share a run condition
66#[derive(SystemSet, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
67struct AudioPlaybackSystems;
68
69/// Adds support for audio playback to a Bevy Application
70///
71/// Insert an [`AudioPlayer`] onto your entities to play audio.
72#[derive(Default)]
73pub struct AudioPlugin {
74    /// The global volume for all audio entities.
75    pub global_volume: GlobalVolume,
76    /// The scale factor applied to the positions of audio sources and listeners for
77    /// spatial audio.
78    pub default_spatial_scale: SpatialScale,
79}
80
81impl Plugin for AudioPlugin {
82    fn build(&self, app: &mut App) {
83        app.insert_resource(self.global_volume)
84            .insert_resource(DefaultSpatialScale(self.default_spatial_scale))
85            .configure_sets(
86                PostUpdate,
87                AudioPlaybackSystems
88                    .run_if(audio_output_available)
89                    .after(TransformSystems::Propagate), // For spatial audio transforms
90            )
91            .add_systems(
92                PostUpdate,
93                (update_emitter_positions, update_listener_positions).in_set(AudioPlaybackSystems),
94            )
95            .init_resource::<AudioOutput>();
96
97        #[cfg(any(feature = "mp3", feature = "flac", feature = "wav", feature = "vorbis"))]
98        {
99            app.add_audio_source::<AudioSource>();
100            app.init_asset_loader::<AudioLoader>();
101        }
102
103        app.add_audio_source::<Pitch>();
104    }
105}
106
107impl AddAudioSource for App {
108    fn add_audio_source<T>(&mut self) -> &mut Self
109    where
110        T: Decodable + Asset,
111        f32: rodio::cpal::FromSample<T::DecoderItem>,
112    {
113        self.init_asset::<T>().add_systems(
114            PostUpdate,
115            (play_queued_audio_system::<T>, cleanup_finished_audio::<T>)
116                .in_set(AudioPlaybackSystems),
117        );
118        self
119    }
120}