use crate::fixed::fixed::Q15;
use alloc::vec::Vec;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AutomationTarget {
GlobalVolume,
Bpm,
Speed,
ChannelVolume(u8),
ChannelPanning(u8),
TrackVolume(u32),
TrackPanning(u32),
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum AutomationValue {
Normalized(Q15),
Bpm(u16),
Speed(u8),
}
impl AutomationValue {
pub fn is_compatible_with(&self, target: AutomationTarget) -> bool {
matches!(
(self, target),
(
AutomationValue::Normalized(_),
AutomationTarget::GlobalVolume
) | (
AutomationValue::Normalized(_),
AutomationTarget::ChannelVolume(_)
) | (
AutomationValue::Normalized(_),
AutomationTarget::ChannelPanning(_)
) | (
AutomationValue::Normalized(_),
AutomationTarget::TrackVolume(_)
) | (
AutomationValue::Normalized(_),
AutomationTarget::TrackPanning(_)
) | (AutomationValue::Bpm(_), AutomationTarget::Bpm)
| (AutomationValue::Speed(_), AutomationTarget::Speed)
)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct AutomationPoint {
pub tick: u32,
pub value: AutomationValue,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AutomationLane {
pub target: AutomationTarget,
pub points: Vec<AutomationPoint>,
pub enabled: bool,
}
impl AutomationLane {
pub fn new(target: AutomationTarget) -> Self {
Self {
target,
points: Vec::new(),
enabled: true,
}
}
pub fn insert_point(&mut self, point: AutomationPoint) {
match self.points.binary_search_by_key(&point.tick, |p| p.tick) {
Ok(idx) => self.points[idx] = point,
Err(idx) => self.points.insert(idx, point),
}
}
}