1use core::{
2 ecs::Entity,
3 prefab::{Prefab, PrefabError, PrefabProxy},
4 state::StateToken,
5 Scalar,
6};
7use serde::{Deserialize, Serialize};
8use std::{
9 borrow::Cow,
10 collections::HashMap,
11 sync::{
12 atomic::{AtomicBool, Ordering},
13 Arc,
14 },
15};
16
17#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
18pub(crate) enum AudioSourceDirtyMode {
19 None,
20 Param,
21 All,
22}
23
24impl Default for AudioSourceDirtyMode {
25 fn default() -> Self {
26 Self::None
27 }
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct AudioSourceConfig {
32 pub audio: Cow<'static, str>,
33 #[serde(default)]
34 pub streaming: bool,
35 #[serde(default)]
36 pub looped: bool,
37 #[serde(default = "AudioSourceConfig::default_playback_rate")]
38 pub playback_rate: Scalar,
39 #[serde(default = "AudioSourceConfig::default_volume")]
40 pub volume: Scalar,
41 #[serde(default)]
42 pub play: bool,
43}
44
45impl AudioSourceConfig {
46 fn default_playback_rate() -> Scalar {
47 1.0
48 }
49
50 fn default_volume() -> Scalar {
51 1.0
52 }
53
54 pub fn new(audio: Cow<'static, str>) -> Self {
55 Self {
56 audio,
57 streaming: false,
58 looped: false,
59 playback_rate: 1.0,
60 volume: 1.0,
61 play: false,
62 }
63 }
64
65 pub fn audio(mut self, value: Cow<'static, str>) -> Self {
66 self.audio = value;
67 self
68 }
69
70 pub fn streaming(mut self, value: bool) -> Self {
71 self.streaming = value;
72 self
73 }
74
75 pub fn looped(mut self, value: bool) -> Self {
76 self.looped = value;
77 self
78 }
79
80 pub fn playback_rate(mut self, value: Scalar) -> Self {
81 self.playback_rate = value;
82 self
83 }
84
85 pub fn volume(mut self, value: Scalar) -> Self {
86 self.volume = value;
87 self
88 }
89
90 pub fn play(mut self, value: bool) -> Self {
91 self.play = value;
92 self
93 }
94}
95
96impl Prefab for AudioSourceConfig {}
97
98#[derive(Debug, Clone)]
99pub struct AudioSource {
100 audio: Cow<'static, str>,
101 streaming: bool,
102 looped: bool,
103 playback_rate: Scalar,
104 volume: Scalar,
105 play: bool,
106 pub(crate) current_time: Option<Scalar>,
107
108 pub(crate) ready: Arc<AtomicBool>,
109
110 pub(crate) dirty: AudioSourceDirtyMode,
111}
112
113impl Default for AudioSource {
114 fn default() -> Self {
115 Self {
116 audio: "".into(),
117 streaming: false,
118 looped: false,
119 playback_rate: 1.0,
120 volume: 1.0,
121 play: false,
122 current_time: None,
123 ready: Arc::new(AtomicBool::new(false)),
124 dirty: AudioSourceDirtyMode::None,
125 }
126 }
127}
128
129impl From<AudioSourceConfig> for AudioSource {
130 fn from(config: AudioSourceConfig) -> Self {
131 Self::new_complex(
132 config.audio,
133 config.streaming,
134 config.looped,
135 config.playback_rate,
136 config.volume,
137 config.play,
138 )
139 }
140}
141
142impl AudioSource {
143 pub fn new(audio: Cow<'static, str>, streaming: bool) -> Self {
144 Self {
145 audio,
146 streaming,
147 looped: false,
148 playback_rate: 1.0,
149 volume: 1.0,
150 play: false,
151 current_time: None,
152 ready: Arc::new(AtomicBool::new(false)),
153 dirty: AudioSourceDirtyMode::All,
154 }
155 }
156
157 pub fn new_play(audio: Cow<'static, str>, streaming: bool, play: bool) -> Self {
158 Self {
159 audio,
160 streaming,
161 looped: false,
162 playback_rate: 1.0,
163 volume: 1.0,
164 play,
165 current_time: None,
166 ready: Arc::new(AtomicBool::new(false)),
167 dirty: AudioSourceDirtyMode::All,
168 }
169 }
170
171 pub fn new_complex(
172 audio: Cow<'static, str>,
173 streaming: bool,
174 looped: bool,
175 playback_rate: Scalar,
176 volume: Scalar,
177 play: bool,
178 ) -> Self {
179 Self {
180 audio,
181 streaming,
182 looped,
183 playback_rate,
184 volume,
185 play,
186 current_time: None,
187 ready: Arc::new(AtomicBool::new(false)),
188 dirty: AudioSourceDirtyMode::All,
189 }
190 }
191
192 pub fn audio(&self) -> &str {
193 &self.audio
194 }
195
196 pub fn streaming(&self) -> bool {
197 self.streaming
198 }
199
200 pub fn looped(&self) -> bool {
201 self.looped
202 }
203
204 pub fn set_looped(&mut self, looped: bool) {
205 self.looped = looped;
206 self.dirty = self.dirty.max(AudioSourceDirtyMode::Param);
207 }
208
209 pub fn playback_rate(&self) -> Scalar {
210 self.playback_rate
211 }
212
213 pub fn set_playback_rate(&mut self, playback_rate: Scalar) {
214 self.playback_rate = playback_rate;
215 self.dirty = self.dirty.max(AudioSourceDirtyMode::Param);
216 }
217
218 pub fn volume(&self) -> Scalar {
219 self.volume
220 }
221
222 pub fn set_volume(&mut self, volume: Scalar) {
223 self.volume = volume;
224 self.dirty = self.dirty.max(AudioSourceDirtyMode::Param);
225 }
226
227 pub fn current_time(&self) -> Option<Scalar> {
228 self.current_time
229 }
230
231 pub fn is_playing(&self) -> bool {
232 self.play
233 }
234
235 pub fn play(&mut self) {
236 self.play = true;
237 self.dirty = self.dirty.max(AudioSourceDirtyMode::All);
238 }
239
240 pub fn stop(&mut self) {
241 self.play = false;
242 self.dirty = self.dirty.max(AudioSourceDirtyMode::All);
243 }
244
245 pub fn is_ready(&self) -> bool {
246 self.ready.load(Ordering::Relaxed)
247 }
248}
249
250pub type AudioSourcePrefabProxy = AudioSourceConfig;
251
252impl PrefabProxy<AudioSourcePrefabProxy> for AudioSource {
253 fn from_proxy_with_extras(
254 proxy: AudioSourcePrefabProxy,
255 _: &HashMap<String, Entity>,
256 _: StateToken,
257 ) -> Result<Self, PrefabError> {
258 Ok(proxy.into())
259 }
260}