Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_audio/src/audio_source.rs
6598 views
1
use alloc::sync::Arc;
2
use bevy_asset::{io::Reader, Asset, AssetLoader, LoadContext};
3
use bevy_reflect::TypePath;
4
use std::io::Cursor;
5
6
/// A source of audio data
7
#[derive(Asset, Debug, Clone, TypePath)]
8
pub struct AudioSource {
9
/// Raw data of the audio source.
10
///
11
/// The data must be one of the file formats supported by Bevy (`wav`, `ogg`, `flac`, or `mp3`).
12
/// However, support for these file formats is not part of Bevy's [`default feature set`](https://docs.rs/bevy/latest/bevy/index.html#default-features).
13
/// In order to be able to use these file formats, you will have to enable the appropriate [`optional features`](https://docs.rs/bevy/latest/bevy/index.html#optional-features).
14
///
15
/// It is decoded using [`rodio::decoder::Decoder`](https://docs.rs/rodio/latest/rodio/decoder/struct.Decoder.html).
16
/// The decoder has conditionally compiled methods
17
/// depending on the features enabled.
18
/// If the format used is not enabled,
19
/// then this will panic with an `UnrecognizedFormat` error.
20
pub bytes: Arc<[u8]>,
21
}
22
23
impl AsRef<[u8]> for AudioSource {
24
fn as_ref(&self) -> &[u8] {
25
&self.bytes
26
}
27
}
28
29
/// Loads files as [`AudioSource`] [`Assets`](bevy_asset::Assets)
30
///
31
/// This asset loader supports different audio formats based on the enable Bevy features.
32
/// The feature `bevy/vorbis` enables loading from `.ogg` files and is enabled by default.
33
/// Other file endings can be loaded from with additional features:
34
/// `.mp3` with `bevy/mp3`
35
/// `.flac` with `bevy/flac`
36
/// `.wav` with `bevy/wav`
37
#[derive(Default)]
38
pub struct AudioLoader;
39
40
impl AssetLoader for AudioLoader {
41
type Asset = AudioSource;
42
type Settings = ();
43
type Error = std::io::Error;
44
45
async fn load(
46
&self,
47
reader: &mut dyn Reader,
48
_settings: &Self::Settings,
49
_load_context: &mut LoadContext<'_>,
50
) -> Result<AudioSource, Self::Error> {
51
let mut bytes = Vec::new();
52
reader.read_to_end(&mut bytes).await?;
53
Ok(AudioSource {
54
bytes: bytes.into(),
55
})
56
}
57
58
fn extensions(&self) -> &[&str] {
59
&[
60
#[cfg(feature = "mp3")]
61
"mp3",
62
#[cfg(feature = "flac")]
63
"flac",
64
#[cfg(feature = "wav")]
65
"wav",
66
#[cfg(feature = "vorbis")]
67
"oga",
68
#[cfg(feature = "vorbis")]
69
"ogg",
70
#[cfg(feature = "vorbis")]
71
"spx",
72
]
73
}
74
}
75
76
/// A type implementing this trait can be converted to a [`rodio::Source`] type.
77
///
78
/// It must be [`Send`] and [`Sync`] in order to be registered.
79
/// Types that implement this trait usually contain raw sound data that can be converted into an iterator of samples.
80
/// This trait is implemented for [`AudioSource`].
81
/// Check the example [`decodable`](https://github.com/bevyengine/bevy/blob/latest/examples/audio/decodable.rs) for how to implement this trait on a custom type.
82
pub trait Decodable: Send + Sync + 'static {
83
/// The type of the audio samples.
84
/// Usually a [`u16`], [`i16`] or [`f32`], as those implement [`rodio::Sample`].
85
/// Other types can implement the [`rodio::Sample`] trait as well.
86
type DecoderItem: rodio::Sample + Send + Sync;
87
88
/// The type of the iterator of the audio samples,
89
/// which iterates over samples of type [`Self::DecoderItem`].
90
/// Must be a [`rodio::Source`] so that it can provide information on the audio it is iterating over.
91
type Decoder: rodio::Source + Send + Iterator<Item = Self::DecoderItem>;
92
93
/// Build and return a [`Self::Decoder`] of the implementing type
94
fn decoder(&self) -> Self::Decoder;
95
}
96
97
impl Decodable for AudioSource {
98
type DecoderItem = <rodio::Decoder<Cursor<AudioSource>> as Iterator>::Item;
99
type Decoder = rodio::Decoder<Cursor<AudioSource>>;
100
101
fn decoder(&self) -> Self::Decoder {
102
rodio::Decoder::new(Cursor::new(self.clone())).unwrap()
103
}
104
}
105
106
/// A trait that allows adding a custom audio source to the object.
107
/// This is implemented for [`App`][bevy_app::App] to allow registering custom [`Decodable`] types.
108
pub trait AddAudioSource {
109
/// Registers an audio source.
110
/// The type must implement [`Decodable`],
111
/// so that it can be converted to a [`rodio::Source`] type,
112
/// and [`Asset`], so that it can be registered as an asset.
113
/// To use this method on [`App`][bevy_app::App],
114
/// the [audio][super::AudioPlugin] and [asset][bevy_asset::AssetPlugin] plugins must be added first.
115
fn add_audio_source<T>(&mut self) -> &mut Self
116
where
117
T: Decodable + Asset,
118
f32: rodio::cpal::FromSample<T::DecoderItem>;
119
}
120
121