cvkg_core/
audio_haptic.rs1use std::sync::Arc;
11use std::sync::Mutex;
12
13pub trait AudioEngine: Send + Sync {
19 fn play_sound(&self, name: &str, volume: f32);
21
22 fn play_spatial(&self, name: &str, position: [f32; 3], volume: f32);
24
25 fn set_listener_position(&self, _position: [f32; 3]) {}
27
28 fn stop_all(&self) {}
30
31 fn play_buffer(&self, _data: &[u8], _volume: f32) {}
37}
38
39pub struct NullAudioEngine;
41
42impl AudioEngine for NullAudioEngine {
43 fn play_sound(&self, _name: &str, _volume: f32) {}
44 fn play_spatial(&self, _name: &str, _position: [f32; 3], _volume: f32) {}
45 fn set_listener_position(&self, _position: [f32; 3]) {}
46 fn stop_all(&self) {}
47}
48
49pub trait HapticEngine: Send + Sync {
57 fn impact(&self, _intensity: HapticIntensity) {}
59
60 fn selection(&self) {}
62
63 fn success(&self) {}
65
66 fn warning(&self) {}
68
69 fn error(&self) {}
71
72 fn visual_tick(&self, _intensity: f32) {}
79}
80
81#[derive(Clone, Copy, Debug, PartialEq, Eq)]
83pub enum HapticIntensity {
84 Light,
85 Medium,
86 Heavy,
87}
88
89pub struct NullHapticEngine;
91
92impl HapticEngine for NullHapticEngine {
93 fn impact(&self, _intensity: HapticIntensity) {}
94 fn selection(&self) {}
95 fn success(&self) {}
96 fn warning(&self) {}
97 fn error(&self) {}
98 fn visual_tick(&self, _intensity: f32) {}
99}
100
101pub mod sounds {
105 pub const CLICK: &str = "click";
106 pub const TOGGLE_ON: &str = "toggle_on";
107 pub const TOGGLE_OFF: &str = "toggle_off";
108 pub const SUCCESS: &str = "success";
109 pub const ERROR: &str = "error";
110 pub const WARNING: &str = "warning";
111 pub const SCRUB: &str = "scrub";
112 pub const SELECTION: &str = "selection";
113
114 pub const NAVIGATION_TICK: &[u8] = include_bytes!("../assets/sounds/nav_tick.wav");
118
119 pub const SUCCESS_CHIME: &[u8] = include_bytes!("../assets/sounds/success_chime.wav");
121
122 pub const WARNING_TONE: &[u8] = include_bytes!("../assets/sounds/warning_tone.wav");
124}
125
126static AUDIO_ENGINE: once_cell::sync::Lazy<Mutex<Arc<dyn AudioEngine>>> =
128 once_cell::sync::Lazy::new(|| Mutex::new(Arc::new(NullAudioEngine)));
129
130static HAPTIC_ENGINE: once_cell::sync::Lazy<Mutex<Arc<dyn HapticEngine>>> =
132 once_cell::sync::Lazy::new(|| Mutex::new(Arc::new(NullHapticEngine)));
133
134pub fn set_audio_engine(engine: Arc<dyn AudioEngine>) {
136 if let Ok(mut guard) = AUDIO_ENGINE.lock() {
137 *guard = engine;
138 }
139}
140
141pub fn set_haptic_engine(engine: Arc<dyn HapticEngine>) {
143 if let Ok(mut guard) = HAPTIC_ENGINE.lock() {
144 *guard = engine;
145 }
146}
147
148pub fn play_sound(name: &str, volume: f32) {
150 if let Ok(guard) = AUDIO_ENGINE.lock() {
151 guard.play_sound(name, volume);
152 }
153}
154
155pub fn haptic_impact(intensity: HapticIntensity) {
157 if let Ok(guard) = HAPTIC_ENGINE.lock() {
158 guard.impact(intensity);
159 }
160}
161
162pub fn haptic_selection() {
164 if let Ok(guard) = HAPTIC_ENGINE.lock() {
165 guard.selection();
166 }
167}
168
169pub fn haptic_success() {
171 if let Ok(guard) = HAPTIC_ENGINE.lock() {
172 guard.success();
173 }
174}
175
176pub fn haptic_error() {
178 if let Ok(guard) = HAPTIC_ENGINE.lock() {
179 guard.error();
180 }
181}