audio_processor_standalone_midi/
vst.rs1use std::cmp::{max, min};
24
25use vst::api::{Event, Events, MidiEvent};
26
27use crate::constants::MIDI_BUFFER_CAPACITY;
28use crate::host::MidiMessageEntry;
29
30pub struct MidiVSTConverter {
44 events: Box<Events>,
45 #[allow(dead_code, clippy::vec_box)]
47 events_lst: Vec<Box<Event>>,
48 capacity: usize,
49}
50
51impl Default for MidiVSTConverter {
52 fn default() -> Self {
53 Self::new(MIDI_BUFFER_CAPACITY)
54 }
55}
56
57impl MidiVSTConverter {
58 pub fn new(capacity: usize) -> Self {
62 unsafe {
63 let events_ptr = MidiVSTConverter::allocate_events(capacity);
64 let event_ptrs = std::slice::from_raw_parts_mut(
65 &mut (*events_ptr).events[0] as *mut *mut _ as *mut *mut _,
66 capacity,
67 );
68 let mut events_lst = Vec::with_capacity(capacity);
69 for event_ptr_cell in event_ptrs.iter_mut().take(capacity) {
70 let event_ptr = MidiVSTConverter::allocate_event();
71 *event_ptr_cell = event_ptr;
72 events_lst.push(Box::from_raw(*event_ptr_cell));
73 }
74
75 Self {
76 events: Box::from_raw(events_ptr),
77 events_lst,
78 capacity,
79 }
80 }
81 }
82
83 pub fn accept(&mut self, midi_message_buffer: &[MidiMessageEntry]) -> &Events {
89 self.events.num_events = min(self.capacity as i32, midi_message_buffer.len() as i32);
90
91 for (i, message) in midi_message_buffer.iter().enumerate() {
92 if i >= self.capacity {
93 log::trace!("MIDI Message was dropped");
94 break;
95 }
96
97 unsafe {
98 log::trace!("Forwarding message {:?}", message.message_data);
99 let event = MidiEvent {
100 event_type: vst::api::EventType::Midi,
101 byte_size: std::mem::size_of::<MidiEvent>() as i32,
102 delta_frames: 0,
103 flags: 0,
104 note_length: 0,
105 note_offset: 0,
106 midi_data: message.message_data,
107 _midi_reserved: 0,
108 detune: 0,
109 note_off_velocity: 0,
110 _reserved1: 0,
111 _reserved2: 0,
112 };
113
114 let ptr = std::slice::from_raw_parts_mut(
115 &mut self.events.events[0] as *mut *mut Event,
116 self.events.num_events as usize,
117 );
118 let ptr_event_ref: *mut Event = ptr[i];
119 let midi_event: *mut MidiEvent = std::mem::transmute(ptr_event_ref);
120 *midi_event = event;
121 }
122 }
123
124 &self.events
125 }
126
127 pub fn events(&self) -> &Events {
129 &self.events
130 }
131
132 unsafe fn allocate_event() -> *mut Event {
135 let (event_size, event_align) = (
136 max(
137 std::mem::size_of::<vst::api::SysExEvent>(),
138 max(
139 std::mem::size_of::<Event>(),
140 std::mem::size_of::<MidiEvent>(),
141 ),
142 ),
143 std::mem::align_of::<Event>(),
144 );
145 let event_layout = std::alloc::Layout::from_size_align_unchecked(event_size, event_align);
146
147 std::alloc::alloc(event_layout) as *mut Event
148 }
149
150 unsafe fn allocate_events(capacity: usize) -> *mut Events {
154 let event_ptr_size = std::mem::size_of::<*mut Event>();
155 let events_layout = std::alloc::Layout::from_size_align_unchecked(
156 std::mem::size_of::<Events>() + event_ptr_size * capacity,
157 std::mem::align_of::<Events>(),
158 );
159
160 std::alloc::alloc(events_layout) as *mut Events
161 }
162}
163
164#[cfg(test)]
165mod test {
166 use basedrop::Owned;
167
168 use audio_processor_traits::MidiMessageLike;
169
170 use crate::host::MidiMessageWrapper;
171 use assert_no_alloc::assert_no_alloc;
172
173 use super::*;
174
175 #[test]
176 fn test_create_converter() {
177 let _midi_vst_converter = MidiVSTConverter::new(10);
178 }
179
180 #[test]
181 fn test_allocate_event() {
182 let _event_ptr = unsafe { MidiVSTConverter::allocate_event() };
184 }
185
186 #[test]
187 fn test_accept_events() {
188 let mut converter = MidiVSTConverter::new(10);
189 let buffer = [
190 MidiMessageEntry(Owned::new(
191 audio_garbage_collector::handle(),
192 MidiMessageWrapper {
193 timestamp: 0,
194 message_data: [10, 20, 30],
195 },
196 )),
197 MidiMessageEntry(Owned::new(
198 audio_garbage_collector::handle(),
199 MidiMessageWrapper {
200 timestamp: 10,
201 message_data: [30, 40, 50],
202 },
203 )),
204 ];
205
206 let events = assert_no_alloc(|| converter.accept(&buffer));
207 assert_eq!(events.num_events, 2);
208
209 let event = events.events[0];
210 assert_eq!(event.is_midi(), true);
211 let msg = [10_u8, 20, 30];
212 assert_eq!(event.bytes(), Some(&msg as &[u8]));
213 let event = events.events[1];
214 assert_eq!(event.is_midi(), true);
215 let msg = [30_u8, 40, 50];
216 assert_eq!(event.bytes(), Some(&msg as &[u8]));
217 }
218}