use std::collections::BTreeMap;
use sim_kernel::{Error, Result};
use sim_lib_audio_graph_core::BlockEvent;
#[derive(Clone, Debug, PartialEq)]
pub enum Vst3Event {
NoteOn {
sample_offset: u32,
channel: u8,
pitch: u8,
velocity: f32,
},
NoteOff {
sample_offset: u32,
channel: u8,
pitch: u8,
velocity: f32,
},
Midi {
sample_offset: u32,
bytes: [u8; 3],
len: u8,
},
ParamValue {
sample_offset: u32,
vst3_param_id: u32,
normalized: f64,
},
}
impl Vst3Event {
pub fn to_block_event(&self, params: &Vst3ParamMap) -> BlockEvent<'_> {
match self {
Self::NoteOn {
sample_offset,
channel,
pitch,
velocity,
} => BlockEvent::NoteOn {
offset: *sample_offset,
channel: *channel,
key: *pitch,
velocity: *velocity,
},
Self::NoteOff {
sample_offset,
channel,
pitch,
velocity,
} => BlockEvent::NoteOff {
offset: *sample_offset,
channel: *channel,
key: *pitch,
velocity: *velocity,
},
Self::Midi {
sample_offset,
bytes,
len,
} => BlockEvent::Midi {
offset: *sample_offset,
bytes: *bytes,
len: *len,
},
Self::ParamValue {
sample_offset,
vst3_param_id,
normalized,
} => BlockEvent::ParamSet {
offset: *sample_offset,
param: params.sim_param_for(*vst3_param_id),
value: *normalized,
},
}
}
pub fn try_to_block_event(&self, params: &Vst3ParamMap, 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!(
"VST3 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 Vst3ParamMap {
vst3_to_sim: BTreeMap<u32, u32>,
}
impl Vst3ParamMap {
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, vst3_param_id: u32, sim_param_id: u32) {
self.vst3_to_sim.insert(vst3_param_id, sim_param_id);
}
pub fn sim_param_for(&self, vst3_param_id: u32) -> u32 {
self.vst3_to_sim
.get(&vst3_param_id)
.copied()
.unwrap_or(vst3_param_id)
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Vst3EventBuffer {
events: Vec<Vst3Event>,
}
impl Vst3EventBuffer {
pub fn new(events: Vec<Vst3Event>) -> Self {
Self { events }
}
pub fn events(&self) -> &[Vst3Event] {
&self.events
}
pub fn push(&mut self, event: Vst3Event) {
self.events.push(event);
}
pub fn to_block_events(&self, params: &Vst3ParamMap) -> Vec<BlockEvent<'_>> {
self.events
.iter()
.map(|event| event.to_block_event(params))
.collect()
}
pub fn try_to_block_events(
&self,
params: &Vst3ParamMap,
frames: u32,
) -> Result<Vec<BlockEvent<'_>>> {
self.events
.iter()
.map(|event| event.try_to_block_event(params, frames))
.collect()
}
}