Skip to main content

concinnity_core/components/
audio_clip.rs

1// Baked audio-clip schema.
2
3use crate::ecs::PayloadLocator;
4use crate::ecs::asset_id::AssetId;
5use alloc::string::String;
6
7/// A baked audio clip: the sound an [AudioEmitter](#audioemitter) plays.
8///
9/// The build reads the `source` file (any format the engine can decode:
10/// `.ogg`, `.wav`, `.flac`, `.mp3`) and packs it into the world.
11///
12/// An `AudioClip` is inert on its own: reference it from an
13/// [AudioEmitter](#audioemitter)'s `clip` field to place the sound in the world.
14///
15/// ```rust
16/// # use concinnity_core::components::AudioClip;
17/// AudioClip {
18///     source: "audio/fire_crackle.ogg".into(),
19///     ..Default::default()
20/// };
21/// ```
22#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
23#[serde(default)]
24#[derive(Default)]
25pub struct AudioClip {
26    /// Asset identity; injected via `inject_name`. Not part of `args`.
27    #[serde(skip)]
28    pub asset_id: AssetId,
29    /// Path to the source audio file.
30    pub source: String,
31    /// Injected at load time from the compiled blob payload.
32    #[serde(skip)]
33    pub locator: Option<PayloadLocator>,
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39
40    #[test]
41    fn a_blank_clip_names_no_source() {
42        let c = AudioClip::default();
43        assert!(c.source.is_empty());
44        assert_eq!(c.asset_id, AssetId::default());
45        assert!(c.locator.is_none());
46    }
47
48    #[test]
49    fn the_source_path_is_the_only_authored_field() {
50        let c: AudioClip = serde_json::from_str(r#"{"source":"audio/theme.wav"}"#).unwrap();
51        assert_eq!(c.source, "audio/theme.wav");
52        // Identity and payload location are injected, so neither is authorable
53        // nor carried on the wire.
54        assert_eq!(
55            serde_json::to_string(&c).unwrap(),
56            r#"{"source":"audio/theme.wav"}"#
57        );
58
59        let bytes = postcard::to_allocvec(&c).unwrap();
60        let back: AudioClip = postcard::from_bytes(&bytes).unwrap();
61        assert_eq!(back.source, "audio/theme.wav");
62        assert_eq!(back.asset_id, AssetId::default());
63        assert!(back.locator.is_none());
64    }
65}