Skip to main content

voirs_spatial/visual_audio/
mapping.rs

1//! Audio-to-visual mapping configuration
2
3use super::types::{ColorRGBA, DirectionZone, ShapeType, VisualEffect, VisualElementType};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::time::Duration;
7
8/// Audio-to-visual mapping configuration
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct AudioVisualMapping {
11    /// Low frequency visual mapping
12    pub low_freq_mapping: FrequencyVisualMapping,
13
14    /// Mid frequency visual mapping
15    pub mid_freq_mapping: FrequencyVisualMapping,
16
17    /// High frequency visual mapping
18    pub high_freq_mapping: FrequencyVisualMapping,
19
20    /// Amplitude-based visual scaling
21    pub amplitude_scaling: AmplitudeVisualMapping,
22
23    /// Directional visual cues
24    pub directional_cues: DirectionalCueMapping,
25
26    /// Event-based visual triggers
27    pub event_triggers: EventTriggerMapping,
28}
29
30/// Frequency band to visual mapping
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct FrequencyVisualMapping {
33    /// Frequency range (Hz)
34    pub frequency_range: (f32, f32),
35
36    /// Visual element type for this frequency
37    pub element_type: VisualElementType,
38
39    /// Base color for this frequency band
40    pub base_color: ColorRGBA,
41
42    /// Intensity scaling factor
43    pub intensity_scale: f32,
44
45    /// Size scaling factor
46    pub size_scale: f32,
47
48    /// Animation responsiveness
49    pub animation_responsiveness: f32,
50}
51
52/// Amplitude-based visual scaling
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct AmplitudeVisualMapping {
55    /// Minimum amplitude for visual activation
56    pub threshold: f32,
57
58    /// Amplitude to intensity scaling
59    pub intensity_curve: ScalingCurve,
60
61    /// Amplitude to size scaling
62    pub size_curve: ScalingCurve,
63
64    /// Dynamic range compression
65    pub compression_ratio: f32,
66}
67
68/// Scaling curve types
69#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
70pub enum ScalingCurve {
71    /// Linear scaling
72    Linear,
73
74    /// Logarithmic scaling
75    Logarithmic,
76
77    /// Exponential scaling
78    Exponential,
79
80    /// Power law scaling
81    Power(f32),
82
83    /// Custom curve
84    Custom,
85}
86
87/// Directional visual cue mapping
88#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct DirectionalCueMapping {
90    /// Enable directional indicators
91    pub enabled: bool,
92
93    /// Arrow/pointer visual element
94    pub directional_element: VisualElementType,
95
96    /// Color coding for direction zones
97    pub direction_colors: HashMap<DirectionZone, ColorRGBA>,
98
99    /// Distance-based directional scaling
100    pub distance_scaling: bool,
101
102    /// Peripheral vision enhancement
103    pub peripheral_enhancement: bool,
104}
105
106/// Event-based visual trigger mapping
107#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct EventTriggerMapping {
109    /// Audio onset triggers
110    pub onset_triggers: Vec<OnsetTrigger>,
111
112    /// Beat/rhythm triggers
113    pub rhythm_triggers: Vec<RhythmTrigger>,
114
115    /// Spectral event triggers
116    pub spectral_triggers: Vec<SpectralTrigger>,
117
118    /// Silence/quiet triggers
119    pub silence_triggers: Vec<SilenceTrigger>,
120}
121
122/// Audio onset trigger configuration
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct OnsetTrigger {
125    /// Trigger sensitivity
126    pub sensitivity: f32,
127
128    /// Visual effect to trigger
129    pub effect: VisualEffect,
130
131    /// Minimum time between triggers
132    pub cooldown: Duration,
133}
134
135/// Rhythm-based trigger configuration
136#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct RhythmTrigger {
138    /// Target tempo range (BPM)
139    pub tempo_range: (f32, f32),
140
141    /// Beat emphasis visual effect
142    pub beat_effect: VisualEffect,
143
144    /// Downbeat special effect
145    pub downbeat_effect: Option<VisualEffect>,
146
147    /// Rhythm confidence threshold
148    pub confidence_threshold: f32,
149}
150
151/// Spectral event trigger configuration
152#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct SpectralTrigger {
154    /// Frequency range to monitor
155    pub frequency_range: (f32, f32),
156
157    /// Energy change threshold
158    pub energy_threshold: f32,
159
160    /// Visual effect for spectral events
161    pub effect: VisualEffect,
162
163    /// Trigger duration
164    pub duration: Duration,
165}
166
167/// Silence detection trigger configuration
168#[derive(Debug, Clone, Serialize, Deserialize)]
169pub struct SilenceTrigger {
170    /// Silence threshold (dB)
171    pub threshold_db: f32,
172
173    /// Minimum silence duration
174    pub min_duration: Duration,
175
176    /// Visual effect during silence
177    pub silence_effect: VisualEffect,
178
179    /// Visual effect for silence end
180    pub end_effect: Option<VisualEffect>,
181}
182
183/// Visual distance attenuation configuration
184#[derive(Debug, Clone, Serialize, Deserialize)]
185pub struct VisualDistanceAttenuation {
186    /// Minimum distance for full intensity
187    pub min_distance: f32,
188
189    /// Maximum distance for zero intensity
190    pub max_distance: f32,
191
192    /// Attenuation curve type
193    pub curve_type: ScalingCurve,
194
195    /// Size scaling with distance
196    pub size_scaling: bool,
197
198    /// Perspective correction
199    pub perspective_correction: bool,
200}
201
202// Default implementations
203
204impl Default for AudioVisualMapping {
205    fn default() -> Self {
206        Self {
207            low_freq_mapping: FrequencyVisualMapping {
208                frequency_range: (20.0, 250.0),
209                element_type: VisualElementType::PointLight,
210                base_color: ColorRGBA {
211                    r: 1.0,
212                    g: 0.2,
213                    b: 0.2,
214                    a: 0.8,
215                },
216                intensity_scale: 1.5,
217                size_scale: 1.2,
218                animation_responsiveness: 0.8,
219            },
220            mid_freq_mapping: FrequencyVisualMapping {
221                frequency_range: (250.0, 4000.0),
222                element_type: VisualElementType::Shape(ShapeType::Sphere),
223                base_color: ColorRGBA {
224                    r: 0.2,
225                    g: 1.0,
226                    b: 0.2,
227                    a: 0.8,
228                },
229                intensity_scale: 1.0,
230                size_scale: 1.0,
231                animation_responsiveness: 1.0,
232            },
233            high_freq_mapping: FrequencyVisualMapping {
234                frequency_range: (4000.0, 20000.0),
235                element_type: VisualElementType::ParticleEffect,
236                base_color: ColorRGBA {
237                    r: 0.2,
238                    g: 0.2,
239                    b: 1.0,
240                    a: 0.8,
241                },
242                intensity_scale: 0.8,
243                size_scale: 0.6,
244                animation_responsiveness: 1.5,
245            },
246            amplitude_scaling: AmplitudeVisualMapping {
247                threshold: 0.1,
248                intensity_curve: ScalingCurve::Logarithmic,
249                size_curve: ScalingCurve::Linear,
250                compression_ratio: 3.0,
251            },
252            directional_cues: DirectionalCueMapping::default(),
253            event_triggers: EventTriggerMapping::default(),
254        }
255    }
256}
257
258impl Default for DirectionalCueMapping {
259    fn default() -> Self {
260        let mut direction_colors = HashMap::new();
261        direction_colors.insert(
262            DirectionZone::Front,
263            ColorRGBA {
264                r: 0.0,
265                g: 1.0,
266                b: 0.0,
267                a: 1.0,
268            },
269        );
270        direction_colors.insert(
271            DirectionZone::Left,
272            ColorRGBA {
273                r: 1.0,
274                g: 1.0,
275                b: 0.0,
276                a: 1.0,
277            },
278        );
279        direction_colors.insert(
280            DirectionZone::Back,
281            ColorRGBA {
282                r: 1.0,
283                g: 0.0,
284                b: 0.0,
285                a: 1.0,
286            },
287        );
288        direction_colors.insert(
289            DirectionZone::Right,
290            ColorRGBA {
291                r: 0.0,
292                g: 0.0,
293                b: 1.0,
294                a: 1.0,
295            },
296        );
297        direction_colors.insert(
298            DirectionZone::Above,
299            ColorRGBA {
300                r: 1.0,
301                g: 0.0,
302                b: 1.0,
303                a: 1.0,
304            },
305        );
306        direction_colors.insert(
307            DirectionZone::Below,
308            ColorRGBA {
309                r: 0.0,
310                g: 1.0,
311                b: 1.0,
312                a: 1.0,
313            },
314        );
315
316        Self {
317            enabled: true,
318            directional_element: VisualElementType::Shape(ShapeType::Arrow),
319            direction_colors,
320            distance_scaling: true,
321            peripheral_enhancement: true,
322        }
323    }
324}
325
326impl Default for EventTriggerMapping {
327    fn default() -> Self {
328        Self {
329            onset_triggers: vec![],
330            rhythm_triggers: vec![],
331            spectral_triggers: vec![],
332            silence_triggers: vec![],
333        }
334    }
335}
336
337impl Default for VisualDistanceAttenuation {
338    fn default() -> Self {
339        Self {
340            min_distance: 0.5,
341            max_distance: 20.0,
342            curve_type: ScalingCurve::Linear,
343            size_scaling: true,
344            perspective_correction: true,
345        }
346    }
347}