concinnity_core/components/
audio_cue.rs1use crate::components::AudioBus;
4use crate::ecs::AudioClipHandle;
5use crate::ecs::asset_id::AssetId;
6use crate::ecs::asset_id::de_opt_asset_ref;
7use crate::ecs::de_opt_audio_clip_handle;
8
9#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
25#[serde(default)]
26pub struct AudioCue {
27 #[serde(skip)]
29 pub asset_id: AssetId,
30 #[serde(deserialize_with = "de_opt_asset_ref")]
32 pub screen: Option<AssetId>,
33 #[serde(deserialize_with = "de_opt_audio_clip_handle")]
35 pub clip: Option<AudioClipHandle>,
36 pub kind: CueKind,
38 pub volume: f32,
40 pub bus: Option<AudioBus>,
43 pub priority: i32,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, Default)]
51#[serde(rename_all = "lowercase")]
52pub enum CueKind {
53 Music,
56 #[default]
58 Sound,
59}
60
61impl Default for AudioCue {
62 fn default() -> Self {
63 Self {
64 asset_id: AssetId::default(),
65 screen: None,
66 clip: None,
67 kind: CueKind::Sound,
68 volume: 1.0,
69 bus: None,
70 priority: 0,
71 }
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn a_blank_cue_is_a_one_shot_sound_at_unit_gain() {
81 let c = AudioCue::default();
82 assert_eq!(c.kind, CueKind::Sound);
83 assert_eq!(c.volume, 1.0);
84 assert!(c.clip.is_none());
85 assert!(c.screen.is_none());
86 assert!(c.bus.is_none());
87 assert_eq!(c.priority, 0);
88 assert_eq!(CueKind::default(), CueKind::Sound);
89 }
90
91 #[test]
92 fn a_music_cue_parses_its_clip_and_screen_by_name() {
93 crate::test_support::install_resolvers();
94 let c: AudioCue =
95 serde_json::from_str(r#"{"clip":"theme","screen":"menu","kind":"music","volume":0.4}"#)
96 .unwrap();
97 assert_eq!(c.clip, Some(AudioClipHandle(5)));
98 assert_eq!(c.screen, Some(AssetId(4)));
99 assert_eq!(c.kind, CueKind::Music);
100 assert_eq!(c.volume, 0.4);
101 assert_eq!(
102 serde_json::to_string(&CueKind::Music).unwrap(),
103 r#""music""#
104 );
105
106 let bytes = postcard::to_allocvec(&c).unwrap();
107 let back: AudioCue = postcard::from_bytes(&bytes).unwrap();
108 assert_eq!(back.clip, Some(AudioClipHandle(5)));
109 assert_eq!(back.screen, Some(AssetId(4)));
110 assert_eq!(back.kind, CueKind::Music);
111 assert_eq!(back.asset_id, AssetId::default());
112 }
113
114 #[test]
115 fn a_voice_cue_parses_its_bus_and_priority() {
116 crate::test_support::install_resolvers();
117 let c: AudioCue =
118 serde_json::from_str(r#"{"clip":"line","screen":"menu","bus":"voice","priority":5}"#)
119 .unwrap();
120 assert_eq!(c.bus, Some(AudioBus::Voice));
121 assert_eq!(c.priority, 5);
122
123 let bytes = postcard::to_allocvec(&c).unwrap();
124 let back: AudioCue = postcard::from_bytes(&bytes).unwrap();
125 assert_eq!(back.bus, Some(AudioBus::Voice));
126 assert_eq!(back.priority, 5);
127 }
128}