Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_audio/src/audio.rs
6598 views
1
use crate::{AudioSource, Decodable, Volume};
2
use bevy_asset::{Asset, Handle};
3
use bevy_ecs::prelude::*;
4
use bevy_math::Vec3;
5
use bevy_reflect::prelude::*;
6
use bevy_transform::components::Transform;
7
8
/// The way Bevy manages the sound playback.
9
#[derive(Debug, Clone, Copy, Reflect)]
10
#[reflect(Clone)]
11
pub enum PlaybackMode {
12
/// Play the sound once. Do nothing when it ends.
13
///
14
/// Note: It is not possible to reuse an [`AudioPlayer`] after it has finished playing and
15
/// the underlying [`AudioSink`](crate::AudioSink) or [`SpatialAudioSink`](crate::SpatialAudioSink) has been drained.
16
///
17
/// To replay a sound, the audio components provided by [`AudioPlayer`] must be removed and
18
/// added again.
19
Once,
20
/// Repeat the sound forever.
21
Loop,
22
/// Despawn the entity and its children when the sound finishes playing.
23
Despawn,
24
/// Remove the audio components from the entity, when the sound finishes playing.
25
Remove,
26
}
27
28
/// Initial settings to be used when audio starts playing.
29
///
30
/// If you would like to control the audio while it is playing, query for the
31
/// [`AudioSink`](crate::AudioSink) or [`SpatialAudioSink`](crate::SpatialAudioSink)
32
/// components. Changes to this component will *not* be applied to already-playing audio.
33
#[derive(Component, Clone, Copy, Debug, Reflect)]
34
#[reflect(Clone, Default, Component, Debug)]
35
pub struct PlaybackSettings {
36
/// The desired playback behavior.
37
pub mode: PlaybackMode,
38
/// Volume to play at.
39
pub volume: Volume,
40
/// Speed to play at.
41
pub speed: f32,
42
/// Create the sink in paused state.
43
/// Useful for "deferred playback", if you want to prepare
44
/// the entity, but hear the sound later.
45
pub paused: bool,
46
/// Whether to create the sink in muted state or not.
47
///
48
/// This is useful for audio that should be initially muted. You can still
49
/// set the initial volume and it is applied when the audio is unmuted.
50
pub muted: bool,
51
/// Enables spatial audio for this source.
52
///
53
/// See also: [`SpatialListener`].
54
///
55
/// Note: Bevy does not currently support HRTF or any other high-quality 3D sound rendering
56
/// features. Spatial audio is implemented via simple left-right stereo panning.
57
pub spatial: bool,
58
/// Optional scale factor applied to the positions of this audio source and the listener,
59
/// overriding the default value configured on [`AudioPlugin::default_spatial_scale`](crate::AudioPlugin::default_spatial_scale).
60
pub spatial_scale: Option<SpatialScale>,
61
/// The point in time in the audio clip where playback should start. If set to `None`, it will
62
/// play from the beginning of the clip.
63
///
64
/// If the playback mode is set to `Loop`, each loop will start from this position.
65
pub start_position: Option<core::time::Duration>,
66
/// How long the audio should play before stopping. If set, the clip will play for at most
67
/// the specified duration. If set to `None`, it will play for as long as it can.
68
///
69
/// If the playback mode is set to `Loop`, each loop will last for this duration.
70
pub duration: Option<core::time::Duration>,
71
}
72
73
impl Default for PlaybackSettings {
74
fn default() -> Self {
75
Self::ONCE
76
}
77
}
78
79
impl PlaybackSettings {
80
/// Will play the associated audio source once.
81
///
82
/// Note: It is not possible to reuse an [`AudioPlayer`] after it has finished playing and
83
/// the underlying [`AudioSink`](crate::AudioSink) or [`SpatialAudioSink`](crate::SpatialAudioSink) has been drained.
84
///
85
/// To replay a sound, the audio components provided by [`AudioPlayer`] must be removed and
86
/// added again.
87
pub const ONCE: PlaybackSettings = PlaybackSettings {
88
mode: PlaybackMode::Once,
89
volume: Volume::Linear(1.0),
90
speed: 1.0,
91
paused: false,
92
muted: false,
93
spatial: false,
94
spatial_scale: None,
95
start_position: None,
96
duration: None,
97
};
98
99
/// Will play the associated audio source in a loop.
100
pub const LOOP: PlaybackSettings = PlaybackSettings {
101
mode: PlaybackMode::Loop,
102
..PlaybackSettings::ONCE
103
};
104
105
/// Will play the associated audio source once and despawn the entity afterwards.
106
pub const DESPAWN: PlaybackSettings = PlaybackSettings {
107
mode: PlaybackMode::Despawn,
108
..PlaybackSettings::ONCE
109
};
110
111
/// Will play the associated audio source once and remove the audio components afterwards.
112
pub const REMOVE: PlaybackSettings = PlaybackSettings {
113
mode: PlaybackMode::Remove,
114
..PlaybackSettings::ONCE
115
};
116
117
/// Helper to start in a paused state.
118
pub const fn paused(mut self) -> Self {
119
self.paused = true;
120
self
121
}
122
123
/// Helper to start muted.
124
pub const fn muted(mut self) -> Self {
125
self.muted = true;
126
self
127
}
128
129
/// Helper to set the volume from start of playback.
130
pub const fn with_volume(mut self, volume: Volume) -> Self {
131
self.volume = volume;
132
self
133
}
134
135
/// Helper to set the speed from start of playback.
136
pub const fn with_speed(mut self, speed: f32) -> Self {
137
self.speed = speed;
138
self
139
}
140
141
/// Helper to enable or disable spatial audio.
142
pub const fn with_spatial(mut self, spatial: bool) -> Self {
143
self.spatial = spatial;
144
self
145
}
146
147
/// Helper to use a custom spatial scale.
148
pub const fn with_spatial_scale(mut self, spatial_scale: SpatialScale) -> Self {
149
self.spatial_scale = Some(spatial_scale);
150
self
151
}
152
153
/// Helper to use a custom playback start position.
154
pub const fn with_start_position(mut self, start_position: core::time::Duration) -> Self {
155
self.start_position = Some(start_position);
156
self
157
}
158
159
/// Helper to use a custom playback duration.
160
pub const fn with_duration(mut self, duration: core::time::Duration) -> Self {
161
self.duration = Some(duration);
162
self
163
}
164
}
165
166
/// Settings for the listener for spatial audio sources.
167
///
168
/// This is accompanied by [`Transform`] and [`GlobalTransform`](bevy_transform::prelude::GlobalTransform).
169
/// Only one entity with a [`SpatialListener`] should be present at any given time.
170
#[derive(Component, Clone, Debug, Reflect)]
171
#[require(Transform)]
172
#[reflect(Clone, Default, Component, Debug)]
173
pub struct SpatialListener {
174
/// Left ear position relative to the [`GlobalTransform`](bevy_transform::prelude::GlobalTransform).
175
pub left_ear_offset: Vec3,
176
/// Right ear position relative to the [`GlobalTransform`](bevy_transform::prelude::GlobalTransform).
177
pub right_ear_offset: Vec3,
178
}
179
180
impl Default for SpatialListener {
181
fn default() -> Self {
182
Self::new(4.)
183
}
184
}
185
186
impl SpatialListener {
187
/// Creates a new [`SpatialListener`] component.
188
///
189
/// `gap` is the distance between the left and right "ears" of the listener. Ears are
190
/// positioned on the x axis.
191
pub fn new(gap: f32) -> Self {
192
SpatialListener {
193
left_ear_offset: Vec3::X * gap / -2.0,
194
right_ear_offset: Vec3::X * gap / 2.0,
195
}
196
}
197
}
198
199
/// A scale factor applied to the positions of audio sources and listeners for
200
/// spatial audio.
201
///
202
/// Default is `Vec3::ONE`.
203
#[derive(Clone, Copy, Debug, Reflect)]
204
#[reflect(Clone, Default)]
205
pub struct SpatialScale(pub Vec3);
206
207
impl SpatialScale {
208
/// Create a new [`SpatialScale`] with the same value for all 3 dimensions.
209
pub const fn new(scale: f32) -> Self {
210
Self(Vec3::splat(scale))
211
}
212
213
/// Create a new [`SpatialScale`] with the same value for `x` and `y`, and `0.0`
214
/// for `z`.
215
pub const fn new_2d(scale: f32) -> Self {
216
Self(Vec3::new(scale, scale, 0.0))
217
}
218
}
219
220
impl Default for SpatialScale {
221
fn default() -> Self {
222
Self(Vec3::ONE)
223
}
224
}
225
226
/// The default scale factor applied to the positions of audio sources and listeners for
227
/// spatial audio. Can be overridden for individual sounds in [`PlaybackSettings`].
228
///
229
/// You may need to adjust this scale to fit your world's units.
230
///
231
/// Default is `Vec3::ONE`.
232
#[derive(Resource, Default, Clone, Copy, Reflect)]
233
#[reflect(Resource, Default, Clone)]
234
pub struct DefaultSpatialScale(pub SpatialScale);
235
236
/// A component for playing a sound.
237
///
238
/// Insert this component onto an entity to trigger an audio source to begin playing.
239
///
240
/// If the handle refers to an unavailable asset (such as if it has not finished loading yet),
241
/// the audio will not begin playing immediately. The audio will play when the asset is ready.
242
///
243
/// When Bevy begins the audio playback, an [`AudioSink`](crate::AudioSink) component will be
244
/// added to the entity. You can use that component to control the audio settings during playback.
245
///
246
/// Playback can be configured using the [`PlaybackSettings`] component. Note that changes to the
247
/// [`PlaybackSettings`] component will *not* affect already-playing audio.
248
#[derive(Component, Reflect)]
249
#[reflect(Component, Clone)]
250
#[require(PlaybackSettings)]
251
pub struct AudioPlayer<Source = AudioSource>(pub Handle<Source>)
252
where
253
Source: Asset + Decodable;
254
255
impl<Source> Clone for AudioPlayer<Source>
256
where
257
Source: Asset + Decodable,
258
{
259
fn clone(&self) -> Self {
260
Self(self.0.clone())
261
}
262
}
263
264
impl AudioPlayer<AudioSource> {
265
/// Creates a new [`AudioPlayer`] with the given [`Handle<AudioSource>`].
266
///
267
/// For convenience reasons, this hard-codes the [`AudioSource`] type. If you want to
268
/// initialize an [`AudioPlayer`] with a different type, just initialize it directly using normal
269
/// tuple struct syntax.
270
pub fn new(source: Handle<AudioSource>) -> Self {
271
Self(source)
272
}
273
}
274
275