Skip to main content

bevy_kira_components/sources/audio_file/
loader.rs

1//! Asset loader implementation for the [`AudioFile`] type.
2//!
3//! This loader either loads the audio data fully into memory, or simply copies the path into the asset, as kira has
4//! its own file streaming features.
5//!
6//! This means that the streaming feature is only available on desktop platforms, and not on the web.
7use bevy::asset::io::Reader;
8use bevy::asset::{AssetLoader, AsyncReadExt, LoadContext};
9use bevy::utils::BoxedFuture;
10use kira::sound::static_sound::StaticSoundSettings;
11use kira::sound::streaming::StreamingSoundSettings;
12use kira::sound::FromFileError;
13use serde::{Deserialize, Serialize};
14use thiserror::Error;
15
16use crate::sources::audio_file::AudioFile;
17
18/// Loads an [`AudioFile`].
19#[derive(Default)]
20pub struct AudioFileLoader;
21
22/// Possible errors that can be produced by [`AudioFileLoader`]
23#[non_exhaustive]
24#[derive(Debug, Error)]
25pub enum AudioFileLoaderError {
26    /// An [IO Error](std::io::Error)
27    #[error("Could not read the file: {0}")]
28    Io(#[from] std::io::Error),
29    /// An Error loading sound from a file. See [`FromFileError`]
30    #[error("Error while loading a sound: {0}")]
31    FileError(#[from] FromFileError),
32}
33
34/// Settings applied when loading the audio file.
35#[derive(Debug, Copy, Clone, Deserialize, Serialize, Default)]
36pub struct AudioAssetSettings {
37    /// Whether the loader should read the entire file into memory, or only load it on demand
38    /// during playback. Note that some features are not available when a file is streamed from
39    /// disk, and streaming is only available on desktop platforms.
40    pub should_stream: bool,
41}
42
43impl AssetLoader for AudioFileLoader {
44    type Asset = AudioFile;
45    type Settings = AudioAssetSettings;
46    type Error = AudioFileLoaderError;
47
48    fn load<'a>(
49        &'a self,
50        reader: &'a mut Reader,
51        settings: &'a AudioAssetSettings,
52        load_context: &'a mut LoadContext,
53    ) -> BoxedFuture<'a, Result<Self::Asset, Self::Error>> {
54        Box::pin(async move {
55            if settings.should_stream {
56                Ok(AudioFile::Streaming {
57                    path: load_context.path().to_path_buf(),
58                    settings: StreamingSoundSettings::new(),
59                })
60            } else {
61                let mut sound_bytes = vec![];
62                reader.read_to_end(&mut sound_bytes).await?;
63                Ok(AudioFile::Static(
64                    sound_bytes.into(),
65                    StaticSoundSettings::default(),
66                ))
67            }
68        })
69    }
70
71    fn extensions(&self) -> &[&str] {
72        &["wav", "flac", "mp3", "ogg", "oga", "spx"]
73    }
74}