Skip to main content

sim_lib_plugin_vst3/
event.rs

1use std::collections::BTreeMap;
2
3use sim_lib_audio_graph_core::BlockEvent;
4
5/// A VST3 input event for one processing block.
6///
7/// Mirrors the VST3 event surface; [`to_block_event`](Vst3Event::to_block_event)
8/// translates each variant into a graph `BlockEvent`, remapping parameter ids
9/// through a [`Vst3ParamMap`].
10#[derive(Clone, Debug, PartialEq)]
11pub enum Vst3Event {
12    /// A note-on event.
13    NoteOn {
14        /// The sample offset of the event within the block.
15        sample_offset: u32,
16        /// The MIDI channel.
17        channel: u8,
18        /// The note pitch (MIDI key number).
19        pitch: u8,
20        /// The note-on velocity.
21        velocity: f32,
22    },
23    /// A note-off event.
24    NoteOff {
25        /// The sample offset of the event within the block.
26        sample_offset: u32,
27        /// The MIDI channel.
28        channel: u8,
29        /// The note pitch (MIDI key number).
30        pitch: u8,
31        /// The note-off (release) velocity.
32        velocity: f32,
33    },
34    /// A raw MIDI event of up to three bytes.
35    Midi {
36        /// The sample offset of the event within the block.
37        sample_offset: u32,
38        /// The MIDI message bytes.
39        bytes: [u8; 3],
40        /// The number of valid bytes in `bytes`.
41        len: u8,
42    },
43    /// A normalized parameter value change.
44    ParamValue {
45        /// The sample offset of the event within the block.
46        sample_offset: u32,
47        /// The VST3 parameter id, remapped to a SIM id on conversion.
48        vst3_param_id: u32,
49        /// The normalized parameter value.
50        normalized: f64,
51    },
52}
53
54impl Vst3Event {
55    /// Translates this event into a graph `BlockEvent`, remapping any parameter
56    /// id through `params`.
57    pub fn to_block_event(&self, params: &Vst3ParamMap) -> BlockEvent<'_> {
58        match self {
59            Self::NoteOn {
60                sample_offset,
61                channel,
62                pitch,
63                velocity,
64            } => BlockEvent::NoteOn {
65                offset: *sample_offset,
66                channel: *channel,
67                key: *pitch,
68                velocity: *velocity,
69            },
70            Self::NoteOff {
71                sample_offset,
72                channel,
73                pitch,
74                velocity,
75            } => BlockEvent::NoteOff {
76                offset: *sample_offset,
77                channel: *channel,
78                key: *pitch,
79                velocity: *velocity,
80            },
81            Self::Midi {
82                sample_offset,
83                bytes,
84                len,
85            } => BlockEvent::Midi {
86                offset: *sample_offset,
87                bytes: *bytes,
88                len: *len,
89            },
90            Self::ParamValue {
91                sample_offset,
92                vst3_param_id,
93                normalized,
94            } => BlockEvent::ParamSet {
95                offset: *sample_offset,
96                param: params.sim_param_for(*vst3_param_id),
97                value: *normalized,
98            },
99        }
100    }
101}
102
103/// A mapping from host-facing VST3 parameter ids to SIM parameter ids.
104///
105/// Unmapped ids pass through unchanged, so an empty map behaves as the identity.
106#[derive(Clone, Debug, Default, PartialEq, Eq)]
107pub struct Vst3ParamMap {
108    vst3_to_sim: BTreeMap<u32, u32>,
109}
110
111impl Vst3ParamMap {
112    /// Creates an empty map (every id passes through unchanged).
113    pub fn new() -> Self {
114        Self::default()
115    }
116
117    /// Creates a map where each id in `ids` maps to itself.
118    pub fn identity(ids: impl IntoIterator<Item = u32>) -> Self {
119        let mut map = Self::new();
120        for id in ids {
121            map.insert(id, id);
122        }
123        map
124    }
125
126    /// Records that `vst3_param_id` maps to `sim_param_id`.
127    pub fn insert(&mut self, vst3_param_id: u32, sim_param_id: u32) {
128        self.vst3_to_sim.insert(vst3_param_id, sim_param_id);
129    }
130
131    /// Returns the SIM parameter id for `vst3_param_id`, or the input id itself
132    /// when it is unmapped.
133    pub fn sim_param_for(&self, vst3_param_id: u32) -> u32 {
134        self.vst3_to_sim
135            .get(&vst3_param_id)
136            .copied()
137            .unwrap_or(vst3_param_id)
138    }
139}
140
141/// An ordered buffer of VST3 events for one processing block.
142#[derive(Clone, Debug, Default, PartialEq)]
143pub struct Vst3EventBuffer {
144    events: Vec<Vst3Event>,
145}
146
147impl Vst3EventBuffer {
148    /// Creates a buffer from an existing `events` vector.
149    pub fn new(events: Vec<Vst3Event>) -> Self {
150        Self { events }
151    }
152
153    /// Returns the buffered events in order.
154    pub fn events(&self) -> &[Vst3Event] {
155        &self.events
156    }
157
158    /// Appends `event` to the buffer.
159    pub fn push(&mut self, event: Vst3Event) {
160        self.events.push(event);
161    }
162
163    /// Translates every buffered event into a graph `BlockEvent`, remapping
164    /// parameter ids through `params`.
165    pub fn to_block_events(&self, params: &Vst3ParamMap) -> Vec<BlockEvent<'_>> {
166        self.events
167            .iter()
168            .map(|event| event.to_block_event(params))
169            .collect()
170    }
171}