use std::collections::BTreeMap;
use sim_kernel::{Error, Result};
use sim_lib_audio_graph_core::BlockEvent;
#[derive(Clone, Debug, PartialEq)]
pub enum ClapEvent {
MidiShort {
time: u32,
bytes: [u8; 3],
len: u8,
},
NoteOn {
time: u32,
channel: u8,
key: u8,
velocity: f32,
},
NoteOff {
time: u32,
channel: u8,
key: u8,
velocity: f32,
},
ParamValue {
time: u32,
clap_param_id: u32,
value: f64,
},
}
impl ClapEvent {
pub fn to_block_event(&self, params: &ClapParamMap) -> BlockEvent<'_> {
match self {
Self::MidiShort { time, bytes, len } => BlockEvent::Midi {
offset: *time,
bytes: *bytes,
len: *len,
},
Self::NoteOn {
time,
channel,
key,
velocity,
} => BlockEvent::NoteOn {
offset: *time,
channel: *channel,
key: *key,
velocity: *velocity,
},
Self::NoteOff {
time,
channel,
key,
velocity,
} => BlockEvent::NoteOff {
offset: *time,
channel: *channel,
key: *key,
velocity: *velocity,
},
Self::ParamValue {
time,
clap_param_id,
value,
} => BlockEvent::ParamSet {
offset: *time,
param: params.sim_param_for(*clap_param_id),
value: *value,
},
}
}
pub fn try_to_block_event(&self, params: &ClapParamMap, frames: u32) -> Result<BlockEvent<'_>> {
let event = self.to_block_event(params);
let offset = block_event_offset(&event);
if offset >= frames {
return Err(Error::Eval(format!(
"CLAP event offset {offset} is outside block frames 0..{frames}"
)));
}
Ok(event)
}
}
fn block_event_offset(event: &BlockEvent<'_>) -> u32 {
match *event {
BlockEvent::Midi { offset, .. }
| BlockEvent::MidiLong { offset, .. }
| BlockEvent::ParamSet { offset, .. }
| BlockEvent::NoteOn { offset, .. }
| BlockEvent::NoteOff { offset, .. } => offset,
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct ClapParamMap {
clap_to_sim: BTreeMap<u32, u32>,
}
impl ClapParamMap {
pub fn new() -> Self {
Self::default()
}
pub fn identity(ids: impl IntoIterator<Item = u32>) -> Self {
let mut map = Self::new();
for id in ids {
map.insert(id, id);
}
map
}
pub fn insert(&mut self, clap_param_id: u32, sim_param_id: u32) {
self.clap_to_sim.insert(clap_param_id, sim_param_id);
}
pub fn sim_param_for(&self, clap_param_id: u32) -> u32 {
self.clap_to_sim
.get(&clap_param_id)
.copied()
.unwrap_or(clap_param_id)
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ClapEventBuffer {
events: Vec<ClapEvent>,
}
impl ClapEventBuffer {
pub fn new(events: Vec<ClapEvent>) -> Self {
Self { events }
}
pub fn events(&self) -> &[ClapEvent] {
&self.events
}
pub fn push(&mut self, event: ClapEvent) {
self.events.push(event);
}
pub fn to_block_events(&self, params: &ClapParamMap) -> Vec<BlockEvent<'_>> {
self.events
.iter()
.map(|event| event.to_block_event(params))
.collect()
}
pub fn try_to_block_events(
&self,
params: &ClapParamMap,
frames: u32,
) -> Result<Vec<BlockEvent<'_>>> {
self.events
.iter()
.map(|event| event.try_to_block_event(params, frames))
.collect()
}
}