use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use super::trigger_params::{FREQ_BINS, SoundTriggerParams};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(from = "SavedTrigger")]
pub struct SoundTriggerRef {
pub id: Uuid,
pub params: SoundTriggerParams,
pub f_center: f32,
pub f_radius: f32,
pub(crate) averaging_time: f32,
}
#[derive(Deserialize)]
struct SavedTrigger {
#[serde(default = "Uuid::new_v4")]
id: Uuid,
params: SoundTriggerParams,
f_center: Option<f32>,
f_radius: Option<f32>,
averaging_time: f32,
}
impl From<SavedTrigger> for SoundTriggerRef {
fn from(saved: SavedTrigger) -> Self {
let (f_center, f_radius) = saved.params.filter_tune();
Self {
id: saved.id,
params: saved.params,
f_center: saved.f_center.unwrap_or(f_center),
f_radius: saved.f_radius.unwrap_or(f_radius),
averaging_time: saved.averaging_time,
}
}
}
impl Default for SoundTriggerRef {
fn default() -> Self {
Self {
id: Uuid::new_v4(),
params: SoundTriggerParams::default(),
f_center: 8200.,
f_radius: 990.,
averaging_time: 0.1,
}
}
}
pub trait SoundLevels {
fn level(&self, id: &Uuid) -> f32;
fn spectrum_bytes(&self) -> [u8; FREQ_BINS * 4];
}
pub type SoundTriggerSet = HashMap<Uuid, SoundTriggerParams>;
pub trait CollectSoundTriggers {
fn collect_sound_triggers(&self, triggers: &mut SoundTriggerSet);
}
impl CollectSoundTriggers for SoundTriggerRef {
fn collect_sound_triggers(&self, triggers: &mut SoundTriggerSet) {
triggers.entry(self.id).or_insert(self.params);
}
}
impl<T: CollectSoundTriggers> CollectSoundTriggers for Option<T> {
fn collect_sound_triggers(&self, triggers: &mut SoundTriggerSet) {
if let Some(value) = self {
value.collect_sound_triggers(triggers);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn loads_triggers_saved_without_an_id() {
let json = serde_json::to_string(&SoundTriggerRef::default()).expect("serializes");
let mut value: serde_json::Value = serde_json::from_str(&json).expect("json");
value.as_object_mut().expect("object").remove("id");
let old: SoundTriggerRef = serde_json::from_value(value).expect("loads without id");
assert_eq!(old.f_center, 8200.);
}
#[test]
fn loads_triggers_saved_with_bins() {
let json = serde_json::to_string(&SoundTriggerRef::default()).expect("serializes");
let mut value: serde_json::Value = serde_json::from_str(&json).expect("json");
let object = value.as_object_mut().expect("object");
object.remove("f_center");
object.remove("f_radius");
object.insert("center_bin".to_string(), 134.29.into());
object.insert("window_bins".to_string(), 16.0.into());
let old: SoundTriggerRef = serde_json::from_value(value).expect("loads with bins");
let mut params = SoundTriggerParams::default();
params.set_filter_tune(old.f_center, old.f_radius);
assert_eq!(params, old.params);
}
#[test]
fn copies_share_their_trigger() {
let trigger = SoundTriggerRef::default();
let mut set = SoundTriggerSet::new();
trigger.collect_sound_triggers(&mut set);
trigger.clone().collect_sound_triggers(&mut set);
assert_eq!(set.len(), 1);
}
}