assets_manager_kira/
lib.rs

1//! `kira` integration for `assets_manager`
2//!
3//! This crate provides wrappers around `kira` sounds types that implement
4//! `assets_manager` traits.
5
6#![cfg_attr(docsrs, feature(doc_cfg))]
7#![warn(missing_docs)]
8#![forbid(unsafe_code)]
9
10const AVAILABLE_EXTENSIONS: &[&str] = &[
11    #[cfg(feature = "ogg")]
12    "ogg",
13    #[cfg(feature = "mp3")]
14    "mp3",
15    #[cfg(feature = "flac")]
16    "flac",
17    #[cfg(feature = "wav")]
18    "wav",
19];
20
21pub use static_sound::StaticSound;
22pub use streaming::StreamingSound;
23
24mod static_sound {
25    use assets_manager::FileAsset;
26    use kira::sound::static_sound::{StaticSoundData, StaticSoundSettings};
27    use std::io::Cursor;
28
29    /// A wrapper around [`StaticSoundData`] that implements [`Asset`].
30    ///
31    /// # Example
32    ///
33    /// ```no_run
34    /// use kira::{backend::DefaultBackend, AudioManager, AudioManagerSettings};
35    /// use assets_manager_kira::StaticSound;
36    ///
37    /// let mut manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default())?;
38    /// let cache = assets_manager::AssetCache::new("assets")?;
39    ///
40    /// loop {
41    ///     let sound_data = cache.load::<StaticSound>("example.audio.beep")?;
42    ///     manager.play(sound_data.cloned())?;
43    ///     std::thread::sleep(std::time::Duration::from_secs(1));
44    /// }
45    ///
46    /// # Ok::<_, Box<dyn std::error::Error>>(())
47    /// ```
48    #[derive(Clone)]
49    #[repr(transparent)]
50    pub struct StaticSound(pub StaticSoundData);
51
52    impl StaticSound {
53        /// Returns the duration of the audio.
54        pub fn duration(&self) -> std::time::Duration {
55            self.0.duration()
56        }
57
58        /// Returns a clone of the `StaticSound` with the specified settings.
59        pub fn with_settings(&self, settings: StaticSoundSettings) -> Self {
60            Self(self.0.with_settings(settings))
61        }
62    }
63
64    impl FileAsset for StaticSound {
65        const EXTENSIONS: &'static [&'static str] = crate::AVAILABLE_EXTENSIONS;
66
67        fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Result<Self, assets_manager::BoxedError> {
68            let sound = StaticSoundData::from_cursor(Cursor::new(bytes.into_owned()))?;
69            Ok(StaticSound(sound))
70        }
71    }
72
73    impl kira::sound::SoundData for StaticSound {
74        type Error = <StaticSoundData as kira::sound::SoundData>::Error;
75        type Handle = <StaticSoundData as kira::sound::SoundData>::Handle;
76
77        #[inline]
78        fn into_sound(self) -> Result<(Box<dyn kira::sound::Sound>, Self::Handle), Self::Error> {
79            self.0.into_sound()
80        }
81    }
82
83    impl From<StaticSound> for StaticSoundData {
84        #[inline]
85        fn from(sound: StaticSound) -> Self {
86            sound.0
87        }
88    }
89
90    impl std::fmt::Debug for StaticSound {
91        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92            self.0.fmt(f)
93        }
94    }
95}
96
97#[cfg(not(target_arch = "wasm32"))]
98#[cfg_attr(docsrs, doc(cfg(not(target_arch = "wasm32"))))]
99mod streaming {
100    use assets_manager::FileAsset;
101    use kira::sound::{
102        FromFileError,
103        streaming::{StreamingSoundData, StreamingSoundSettings},
104    };
105    use std::io::Cursor;
106
107    /// A wrapper around [`StreamingSoundData`] that implements [`Asset`].
108    ///
109    /// # Example
110    ///
111    /// ```no_run
112    /// use kira::{backend::DefaultBackend, AudioManager, AudioManagerSettings};
113    /// use assets_manager_kira::StreamingSound;
114    ///
115    /// let mut manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default())?;
116    /// let cache = assets_manager::AssetCache::new("assets")?;
117    ///
118    /// loop {
119    ///     let sound_data = cache.load::<StreamingSound>("example.audio.beep")?;
120    ///     manager.play(sound_data.cloned())?;
121    ///     std::thread::sleep(std::time::Duration::from_secs(1));
122    /// }
123    ///
124    /// # Ok::<_, Box<dyn std::error::Error>>(())
125    /// ```
126    #[derive(Clone)]
127    pub struct StreamingSound {
128        /// Settings for the sound.
129        pub settings: StreamingSoundSettings,
130        bytes: assets_manager::SharedBytes,
131    }
132
133    impl StreamingSound {
134        /// Returns a clone of the `StreamingSound` with the specified settings.
135        pub fn with_settings(&self, settings: StreamingSoundSettings) -> Self {
136            Self {
137                settings,
138                bytes: self.bytes.clone(),
139            }
140        }
141
142        fn try_into_kira(self) -> Result<StreamingSoundData<FromFileError>, FromFileError> {
143            let mut sound = StreamingSoundData::from_cursor(Cursor::new(self.bytes))?;
144            sound.settings = self.settings;
145            Ok(sound)
146        }
147    }
148
149    impl FileAsset for StreamingSound {
150        const EXTENSIONS: &'static [&'static str] = crate::AVAILABLE_EXTENSIONS;
151
152        fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Result<Self, assets_manager::BoxedError> {
153            let bytes = assets_manager::SharedBytes::from(bytes);
154            let settings = StreamingSoundSettings::default();
155
156            // Check that the audio file is valid.
157            let _ = StreamingSoundData::from_cursor(Cursor::new(bytes.clone()))?;
158
159            Ok(StreamingSound { settings, bytes })
160        }
161    }
162
163    impl kira::sound::SoundData for StreamingSound {
164        type Error = <StreamingSoundData<FromFileError> as kira::sound::SoundData>::Error;
165        type Handle = <StreamingSoundData<FromFileError> as kira::sound::SoundData>::Handle;
166
167        #[inline]
168        fn into_sound(self) -> Result<(Box<dyn kira::sound::Sound>, Self::Handle), Self::Error> {
169            self.try_into_kira()?.into_sound()
170        }
171    }
172
173    impl From<StreamingSound> for StreamingSoundData<FromFileError> {
174        fn from(sound: StreamingSound) -> Self {
175            sound.try_into_kira().expect("reading succeded earlier")
176        }
177    }
178
179    impl std::fmt::Debug for StreamingSound {
180        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181            f.debug_struct("StreamingSound")
182                .field("settings", &self.settings)
183                .finish_non_exhaustive()
184        }
185    }
186}