1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use bevy::{
asset::{AssetLoader, LoadContext, LoadedAsset},
prelude::*,
reflect::TypeUuid,
utils::BoxedFuture,
};
use kira::sound::{handle::SoundHandle as KiraSoundHandle, Sound as KiraSound};
pub(crate) fn add_assets(app: &mut AppBuilder) {
app.add_asset::<SoundData>()
.add_asset_loader(SoundDataLoader);
}
#[derive(Clone, Debug, TypeUuid)]
#[uuid = "0b6b6127-a10a-4c67-938f-76f079a6f631"]
pub enum SoundData {
Sound(KiraSound),
SoundHandle(KiraSoundHandle),
}
#[derive(thiserror::Error, Debug)]
pub enum SoundDataLoaderError {
#[error("Non-unicode filenames are not supported")]
NonUnicodeFilename,
#[error("Error loading sound from file: {0}")]
FileError(#[from] kira::sound::error::SoundFromFileError),
}
#[derive(Default)]
struct SoundDataLoader;
impl AssetLoader for SoundDataLoader {
fn load<'a>(
&'a self,
bytes: &'a [u8],
load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, Result<(), anyhow::Error>> {
Box::pin(async move { Ok(load_sound(bytes, load_context).await?) })
}
fn extensions(&self) -> &[&str] {
&[
#[cfg(feature = "mp3")]
"mp3",
#[cfg(feature = "ogg")]
"ogg",
#[cfg(feature = "flac")]
"flac",
#[cfg(feature = "wav")]
"wav",
]
}
}
async fn load_sound<'a, 'b>(
bytes: &'a [u8],
load_context: &'a mut LoadContext<'b>,
) -> Result<(), SoundDataLoaderError> {
let sound = match load_context.path().extension() {
Some(ext) => match ext
.to_str()
.ok_or(SoundDataLoaderError::NonUnicodeFilename)?
{
#[cfg(feature = "mp3")]
"mp3" => KiraSound::from_mp3_reader(bytes, Default::default()),
#[cfg(feature = "flac")]
"flac" => KiraSound::from_flac_reader(bytes, Default::default()),
#[cfg(feature = "ogg")]
"ogg" => {
let reader = std::io::Cursor::new(bytes);
KiraSound::from_ogg_reader(reader, Default::default())
}
#[cfg(feature = "wav")]
"wav" => KiraSound::from_wav_reader(bytes, Default::default()),
_ => panic!("Unsupported sound extension, bevy should have caught this"),
},
None => {
panic!("File does not have extension, bevy should have caught this")
}
}?;
load_context.set_default_asset(LoadedAsset::new(SoundData::Sound(sound)));
Ok(())
}