1use crate::clap::{
2 CLAP_EXT_AUDIO_PORTS, CLAP_EXT_PARAMS, CLAP_EXT_TIMER_SUPPORT, ClapAudioBuffer,
3 ClapEventHeader, ClapEventParamGesture, ClapEventParamMod, ClapEventParamValue,
4 ClapPluginParams, ClapProcess, EventBuffer, EventCapture, PluginInstance, ThreadType,
5 host_timers, set_thread_type,
6};
7#[cfg(unix)]
8use crate::clap::{CLAP_EXT_POSIX_FD_SUPPORT, host_fds};
9use crate::events::EventPair;
10#[cfg(windows)]
11use crate::gui_win32::win32::{ContainerWindow, create_container_window};
12use crate::protocol::*;
13use crate::ringbuf::RingBuffer;
14use crate::shm::ShmMapping;
15use std::ptr;
16use std::sync::atomic::{AtomicBool, Ordering};
17use std::time::{Duration, Instant};
18#[cfg(windows)]
19use windows_sys::Win32::UI::WindowsAndMessaging::{
20 SW_HIDE, SW_SHOW, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOZORDER, SetWindowPos, ShowWindow,
21};
22
23static PARAMS_FLUSH_REQUESTED: AtomicBool = AtomicBool::new(false);
24
25pub fn request_params_flush() {
26 PARAMS_FLUSH_REQUESTED.store(true, Ordering::Release);
27}
28
29static AUDIO_PORTS_RESCAN_REQUESTED: AtomicBool = AtomicBool::new(false);
30
31pub fn request_audio_ports_rescan() {
32 AUDIO_PORTS_RESCAN_REQUESTED.store(true, Ordering::Release);
33}
34
35struct PortBuffers {
36 inputs: Vec<ClapAudioBuffer>,
37 outputs: Vec<ClapAudioBuffer>,
38 _input_ptrs: Vec<Vec<*mut f32>>,
39 _output_ptrs: Vec<Vec<*mut f32>>,
40}
41
42impl PortBuffers {
43 fn from_plugin(
44 plugin: *const crate::clap::ClapPlugin,
45 ptr: *mut u8,
46 num_in: usize,
47 num_out: usize,
48 ) -> Option<Self> {
49 let ext = unsafe {
50 (*plugin)
51 .get_extension
52 .map(|f| f(plugin, CLAP_EXT_AUDIO_PORTS.as_ptr()))
53 }?;
54 if ext.is_null() {
55 return None;
56 }
57 let ap = unsafe { &*(ext as *const crate::clap::ClapPluginAudioPorts) };
58 let in_count = ap.count.map(|f| unsafe { f(plugin, true) }).unwrap_or(0) as usize;
59 let out_count = ap.count.map(|f| unsafe { f(plugin, false) }).unwrap_or(0) as usize;
60
61 let mut inputs = Vec::with_capacity(in_count);
62 let mut input_ptrs = Vec::with_capacity(in_count);
63 let mut global_ch: usize = 0;
64 for i in 0..in_count {
65 let mut info = crate::clap::ClapAudioPortInfo {
66 id: 0,
67 name: [0; 256],
68 flags: 0,
69 channel_count: 1,
70 port_type: ptr::null(),
71 in_place_pair: 0,
72 };
73 let ch_count = if ap
74 .get
75 .map(|f| unsafe { f(plugin, i as u32, true, &mut info) })
76 .unwrap_or(false)
77 {
78 info.channel_count.max(1) as usize
79 } else {
80 1
81 };
82 let mut port_channels = Vec::with_capacity(ch_count);
83 for _ in 0..ch_count {
84 let shm_ptr = if global_ch < num_in {
85 unsafe { audio_channel_ptr(ptr, global_ch, 0) }
86 } else {
87 ptr::null_mut()
88 };
89 port_channels.push(shm_ptr);
90 global_ch += 1;
91 }
92 inputs.push(ClapAudioBuffer {
93 data32: port_channels.as_mut_ptr(),
94 data64: ptr::null_mut(),
95 channel_count: port_channels.len() as u32,
96 latency: 0,
97 constant_mask: 0,
98 });
99 input_ptrs.push(port_channels);
100 }
101
102 let mut outputs = Vec::with_capacity(out_count);
103 let mut output_ptrs = Vec::with_capacity(out_count);
104 global_ch = 0;
105 for i in 0..out_count {
106 let mut info = crate::clap::ClapAudioPortInfo {
107 id: 0,
108 name: [0; 256],
109 flags: 0,
110 channel_count: 1,
111 port_type: ptr::null(),
112 in_place_pair: 0,
113 };
114 let ch_count = if ap
115 .get
116 .map(|f| unsafe { f(plugin, i as u32, false, &mut info) })
117 .unwrap_or(false)
118 {
119 info.channel_count.max(1) as usize
120 } else {
121 1
122 };
123 let mut port_channels = Vec::with_capacity(ch_count);
124 for _ in 0..ch_count {
125 let shm_ptr = if global_ch < num_out {
126 unsafe { audio_channel_ptr(ptr, global_ch, 1) }
127 } else {
128 ptr::null_mut()
129 };
130 port_channels.push(shm_ptr);
131 global_ch += 1;
132 }
133 outputs.push(ClapAudioBuffer {
134 data32: port_channels.as_mut_ptr(),
135 data64: ptr::null_mut(),
136 channel_count: port_channels.len() as u32,
137 latency: 0,
138 constant_mask: 0,
139 });
140 output_ptrs.push(port_channels);
141 }
142
143 Some(Self {
144 inputs,
145 outputs,
146 _input_ptrs: input_ptrs,
147 _output_ptrs: output_ptrs,
148 })
149 }
150}
151
152pub struct HostRuntime {
153 pub mapping: ShmMapping,
154 pub events: EventPair,
155 pub format: String,
156 pub plugin_path: String,
157 pub instance_id: String,
158}
159
160impl HostRuntime {
161 pub fn attach(
162 shm_name: &str,
163 events: EventPair,
164 format: String,
165 plugin_path: String,
166 instance_id: String,
167 ) -> Result<Self, String> {
168 let mapping = ShmMapping::open_existing(shm_name, SHM_SIZE)?;
169 Ok(Self {
170 mapping,
171 events,
172 format,
173 plugin_path,
174 instance_id,
175 })
176 }
177
178 fn plugin_id(&self) -> &str {
179 if let Some(pos) = self.plugin_path.rfind("::") {
180 &self.plugin_path[pos + 2..]
181 } else if let Some(pos) = self.plugin_path.rfind('#') {
182 &self.plugin_path[pos + 1..]
183 } else {
184 ""
185 }
186 }
187
188 fn real_plugin_path(&self) -> &str {
189 if let Some(pos) = self.plugin_path.rfind("::") {
190 &self.plugin_path[..pos]
191 } else if let Some(pos) = self.plugin_path.rfind('#') {
192 &self.plugin_path[..pos]
193 } else {
194 &self.plugin_path
195 }
196 }
197
198 pub fn signal_ready(&self) {
199 let header = unsafe { header_mut(self.mapping.as_ptr()) };
200 header.ready.store(1, Ordering::Release);
201 }
202
203 pub fn write_test_magic(&self) {
204 let scratch = unsafe { scratch_ptr(self.mapping.as_ptr()) };
205 let magic: u32 = 0xDEADBEEF;
206 unsafe {
207 std::ptr::write_unaligned(scratch as *mut u32, magic);
208 }
209 }
210
211 pub fn run_until_shutdown(&self) {
212 let header = unsafe { header_ref(self.mapping.as_ptr()) };
213 let start = Instant::now();
214 loop {
215 if header.shutdown_request.load(Ordering::Acquire) != 0 {
216 break;
217 }
218 if start.elapsed() >= Duration::from_millis(100) {
219 header.heartbeat.fetch_add(1, Ordering::Relaxed);
220 }
221 match self.events.wait_daw(Duration::from_millis(100)) {
222 Ok(()) => continue,
223 Err(e) if e.kind() == std::io::ErrorKind::TimedOut => continue,
224 Err(_e) => {
225 break;
226 }
227 }
228 }
229 }
230
231 pub fn run_null_plugin(&self) {
232 let header = unsafe { header_ref(self.mapping.as_ptr()) };
233 let ptr = self.mapping.as_ptr();
234
235 loop {
236 if header.shutdown_request.load(Ordering::Acquire) != 0 {
237 break;
238 }
239
240 match self.events.wait_daw(Duration::from_millis(100)) {
241 Ok(()) => {}
242 Err(e) if e.kind() == std::io::ErrorKind::TimedOut => continue,
243 Err(_e) => {
244 break;
245 }
246 }
247
248 let block_size = header.block_size.load(Ordering::Acquire) as usize;
249 let num_in = header.num_input_channels.load(Ordering::Acquire) as usize;
250 let num_out = header.num_output_channels.load(Ordering::Acquire) as usize;
251
252 if block_size == 0 || block_size > MAX_BLOCK_SIZE {
253 let _ = self.events.signal_daw();
254 continue;
255 }
256
257 let max_ch = num_in.min(num_out).min(MAX_CHANNELS);
258 for ch in 0..max_ch {
259 let in_ptr = unsafe { audio_channel_ptr(ptr, ch, 0) };
260 let out_ptr = unsafe { audio_channel_ptr(ptr, ch, 1) };
261 unsafe {
262 std::ptr::copy_nonoverlapping(in_ptr, out_ptr, block_size);
263 }
264 }
265
266 if let Err(_e) = self.events.signal_daw() {
267 break;
268 }
269 }
270 }
271
272 pub fn run_clap_plugin(&self) {
273 let mut plugin = match PluginInstance::new(self.real_plugin_path(), self.plugin_id()) {
274 Ok(p) => p,
275 Err(_e) => {
276 return;
277 }
278 };
279
280 let ptr = self.mapping.as_ptr();
281 let header = unsafe { header_ref(self.mapping.as_ptr()) };
282
283 unsafe {
284 maolan_plugin_protocol::protocol::write_plugin_name_to_scratch(ptr, &plugin.name());
285 }
286
287 let sample_rate = unsafe {
288 let ts = transport_ref(ptr);
289 if ts.sample_rate_hz > 0.0 {
290 ts.sample_rate_hz
291 } else {
292 48000.0
293 }
294 };
295
296 if let Err(_e) = plugin.activate(sample_rate, 1, MAX_BLOCK_SIZE as u32) {
297 return;
298 }
299
300 let mut port_buffers = PortBuffers::from_plugin(plugin.plugin_ptr(), ptr, 0, 0);
301
302 let has_note_ports = unsafe {
303 (*plugin.plugin_ptr())
304 .get_extension
305 .map(|f| {
306 f(
307 plugin.plugin_ptr(),
308 crate::clap::CLAP_EXT_NOTE_PORTS.as_ptr(),
309 )
310 })
311 .filter(|p| !p.is_null())
312 .is_some()
313 };
314
315 let audio_in_channels = port_buffers
316 .as_ref()
317 .map(|pb| pb.inputs.iter().map(|p| p.channel_count).sum::<u32>())
318 .unwrap_or(0);
319 let audio_out_channels = port_buffers
320 .as_ref()
321 .map(|pb| pb.outputs.iter().map(|p| p.channel_count).sum::<u32>())
322 .unwrap_or(0);
323 let (midi_in_ports, midi_out_ports) = unsafe {
324 let ext = (*plugin.plugin_ptr()).get_extension.map(|f| {
325 f(
326 plugin.plugin_ptr(),
327 crate::clap::CLAP_EXT_NOTE_PORTS.as_ptr(),
328 )
329 });
330 if let Some(ptr) = ext
331 && !ptr.is_null()
332 {
333 let np = &*(ptr as *const crate::clap::ClapPluginNotePorts);
334 let in_count = np.count.map(|f| f(plugin.plugin_ptr(), true)).unwrap_or(0);
335 let out_count = np.count.map(|f| f(plugin.plugin_ptr(), false)).unwrap_or(0);
336 (in_count, out_count)
337 } else {
338 (0, 0)
339 }
340 };
341 unsafe {
342 maolan_plugin_protocol::protocol::write_port_counts_to_scratch(
343 ptr,
344 audio_in_channels,
345 audio_out_channels,
346 midi_in_ports,
347 midi_out_ports,
348 );
349 }
350
351 self.signal_ready();
352
353 let param_ring = unsafe {
354 let buf = param_ring_ptr(ptr);
355 let (w, r) = param_indices(ptr);
356 RingBuffer::new(buf, w, r, RING_CAPACITY)
357 };
358
359 let echo_ring = unsafe {
360 let buf = echo_ring_ptr(ptr);
361 let (w, r) = echo_indices(ptr);
362 RingBuffer::new(buf, w, r, RING_CAPACITY)
363 };
364
365 let midi_ring = unsafe {
366 let buf = midi_ring_ptr(ptr);
367 let (w, r) = midi_indices(ptr);
368 RingBuffer::new(buf, w, r, RING_CAPACITY)
369 };
370
371 let params_ext = unsafe {
372 (*plugin.plugin_ptr())
373 .get_extension
374 .map(|f| f(plugin.plugin_ptr(), CLAP_EXT_PARAMS.as_ptr()))
375 .filter(|p| !p.is_null())
376 .map(|p| p as *const ClapPluginParams)
377 };
378
379 let timer_ext = unsafe {
380 (*plugin.plugin_ptr())
381 .get_extension
382 .map(|f| f(plugin.plugin_ptr(), CLAP_EXT_TIMER_SUPPORT.as_ptr()))
383 .filter(|p| !p.is_null())
384 .map(|p| p as *const crate::clap::ClapPluginTimerSupport)
385 };
386
387 #[cfg(unix)]
388 let fd_ext = unsafe {
389 (*plugin.plugin_ptr())
390 .get_extension
391 .map(|f| f(plugin.plugin_ptr(), CLAP_EXT_POSIX_FD_SUPPORT.as_ptr()))
392 .filter(|p| !p.is_null())
393 .map(|p| p as *const crate::clap::ClapPluginPosixFdSupport)
394 };
395 let mut steady_time: i64 = 0;
396 #[cfg(unix)]
397 let daw_read_fd = self.events.host_read_fd();
398 let mut started_processing = false;
399 #[cfg(windows)]
400 let mut clap_gui_window: Option<ContainerWindow> = None;
401 #[cfg(all(unix, not(target_os = "macos")))]
402 let mut clap_gui_window_x11: Option<crate::gui_x11::x11::ContainerWindow> = None;
403
404 loop {
405 if header.shutdown_request.load(Ordering::Acquire) != 0 {
406 break;
407 }
408
409 let req = header.request_type.load(Ordering::Acquire);
410 if req != 0 {
411 let scratch = unsafe { scratch_ptr(ptr) };
412 let result = match req {
413 1 => match plugin.save_state() {
414 Ok(bytes) if bytes.len() <= SCRATCH_SIZE => {
415 unsafe {
416 std::ptr::copy_nonoverlapping(bytes.as_ptr(), scratch, bytes.len());
417 }
418 header
419 .scratch_size
420 .store(bytes.len() as u32, Ordering::Release);
421 Ok(())
422 }
423 Ok(bytes) => Err(format!(
424 "CLAP state is too large for scratch buffer: {} bytes",
425 bytes.len()
426 )),
427 Err(e) => Err(e),
428 },
429 2 => {
430 let size = header.scratch_size.load(Ordering::Acquire) as usize;
431 if size > SCRATCH_SIZE {
432 Err(format!("Invalid CLAP state size: {size} bytes"))
433 } else {
434 let bytes = unsafe { std::slice::from_raw_parts(scratch, size) };
435 plugin.load_state(bytes)
436 }
437 }
438 3 => {
439 let gui_supported = plugin.gui_is_supported();
440 if !gui_supported {
441 Err("Plugin does not support GUI".to_string())
442 } else {
443 #[cfg(windows)]
444 {
445 if plugin.gui_created() {
446 plugin.gui_destroy();
447 }
448 clap_gui_window = None;
449
450 let title = std::path::Path::new(self.real_plugin_path())
451 .file_stem()
452 .and_then(|s| s.to_str())
453 .unwrap_or("Plugin");
454 match create_container_window(std::ptr::null_mut(), title, 800, 600)
455 {
456 Ok(window) => {
457 let hwnd = window.hwnd;
458 let result = plugin
459 .gui_create("win32", false)
460 .inspect(|_| ())
461 .inspect_err(|e| ())
462 .and_then(|_| {
463 plugin
464 .gui_get_size()
465 .inspect(|(w, h)| ())
466 .inspect_err(|e| ())
467 })
468 .and_then(|(w, h)| {
469 if w > 0 && h > 0 {
470 unsafe {
471 SetWindowPos(
472 hwnd,
473 std::ptr::null_mut(),
474 0,
475 0,
476 w as i32,
477 h as i32,
478 SWP_NOMOVE
479 | SWP_NOZORDER
480 | SWP_NOACTIVATE,
481 );
482 }
483 } else {
484 }
485 plugin
486 .gui_set_parent(hwnd as u64)
487 .inspect(|_| ())
488 .inspect_err(|e| ())
489 })
490 .and_then(|_| {
491 unsafe {
492 ShowWindow(hwnd, SW_SHOW);
493 }
494 plugin
495 .gui_show()
496 .inspect(|_| ())
497 .inspect_err(|e| ())
498 });
499 if result.is_ok() {
500 clap_gui_window = Some(window);
501 }
502 result
503 }
504 Err(e) => Err(e),
505 }
506 }
507 #[cfg(all(unix, not(target_os = "macos")))]
508 {
509 if plugin.gui_created() {
510 plugin.gui_destroy();
511 }
512 clap_gui_window_x11 = None;
513
514 let title = std::path::Path::new(self.real_plugin_path())
515 .file_stem()
516 .and_then(|s| s.to_str())
517 .unwrap_or("Plugin");
518 match crate::gui_x11::x11::create_container_window(
519 None, None, title, 800, 600,
520 ) {
521 Ok(window) => {
522 let window_id = window.window();
523 window.map();
524 let result = plugin
525 .gui_create("x11", false)
526 .inspect(|_| ())
527 .inspect_err(|_e| ())
528 .and_then(|_| {
529 plugin
530 .gui_get_size()
531 .inspect(|(_w, _h)| ())
532 .inspect_err(|_e| ())
533 })
534 .and_then(|(w, h)| {
535 if w > 0 && h > 0 {
536 window.resize(w, h);
537 }
538 plugin
539 .gui_set_parent(window_id)
540 .inspect(|_| ())
541 .inspect_err(|_e| ())
542 })
543 .and_then(|_| {
544 plugin
545 .gui_show()
546 .inspect(|_| ())
547 .inspect_err(|_e| ())
548 });
549 if result.is_ok() {
550 clap_gui_window_x11 = Some(window);
551 }
552 result
553 }
554 Err(e) => Err(e),
555 }
556 }
557 #[cfg(target_os = "macos")]
558 {
559 let window_id = header.parent_window_usize() as u64;
560 let is_floating = window_id == 0;
561
562 if plugin.gui_created() {
563 plugin.gui_destroy();
564 }
565 let create_result = plugin.gui_create("cocoa", is_floating);
566 create_result
567 .and_then(|_| {
568 if window_id != 0 {
569 plugin.gui_set_parent(window_id)
570 } else {
571 Ok(())
572 }
573 })
574 .and_then(|_| plugin.gui_show())
575 }
576 }
577 }
578 4 => {
579 #[cfg(windows)]
580 if let Some(ref window) = clap_gui_window {
581 unsafe {
582 ShowWindow(window.hwnd, SW_HIDE);
583 }
584 }
585 #[cfg(all(unix, not(target_os = "macos")))]
586 if let Some(ref window) = clap_gui_window_x11 {
587 window.unmap();
588 }
589 plugin.gui_hide()
590 }
591 _ => Err(format!("Unknown request type: {req}")),
592 };
593 header
594 .request_status
595 .store(if result.is_ok() { 1 } else { 2 }, Ordering::Release);
596 if req == 1 || req == 2 {
597 let _ = self.events.signal_daw();
598 }
599 header.request_type.store(0, Ordering::Release);
600 continue;
601 }
602
603 set_thread_type(ThreadType::MainThread);
604
605 self.handle_idle_work(&plugin, params_ext, timer_ext);
606
607 let timeout_ms = self.next_timer_ms().min(100);
608
609 #[cfg(unix)]
610 {
611 let (daw_ready, ready_fds) = match timeout_ms {
612 0 => (true, Vec::new()),
613 ms => self.poll_daw_and_fds(daw_read_fd, Duration::from_millis(ms)),
614 };
615
616 if let Some(ext) = fd_ext {
617 for (fd, flags) in ready_fds {
618 unsafe {
619 if let Some(cb) = (*ext).on_fd {
620 cb(plugin.plugin_ptr(), fd, flags);
621 }
622 }
623 }
624 }
625
626 if !daw_ready {
627 continue;
628 }
629 }
630
631 #[cfg(windows)]
632 {
633 match self
634 .events
635 .wait_daw_with_message_pump(Duration::from_millis(timeout_ms.max(1)))
636 {
637 Ok(()) => {}
638 Err(e) if e.kind() == std::io::ErrorKind::TimedOut => continue,
639 Err(e) => {
640 break;
641 }
642 }
643 }
644
645 let block_size = header.block_size.load(Ordering::Acquire) as usize;
646 let num_in = header.num_input_channels.load(Ordering::Acquire) as usize;
647 let num_out = header.num_output_channels.load(Ordering::Acquire) as usize;
648
649 if block_size == 0 || block_size > MAX_BLOCK_SIZE {
650 let _ = self.events.signal_daw();
651 continue;
652 }
653
654 if AUDIO_PORTS_RESCAN_REQUESTED.swap(false, Ordering::Acquire) {
655 port_buffers = PortBuffers::from_plugin(plugin.plugin_ptr(), ptr, num_in, num_out);
656 }
657
658 if let Some(ref mut pb) = port_buffers {
659 let mut global_ch: usize = 0;
660 for port in &mut pb._input_ptrs {
661 for ch in port.iter_mut() {
662 *ch = if global_ch < num_in {
663 unsafe { audio_channel_ptr(ptr, global_ch, 0) }
664 } else {
665 ptr::null_mut()
666 };
667 global_ch += 1;
668 }
669 }
670 global_ch = 0;
671 for port in &mut pb._output_ptrs {
672 for ch in port.iter_mut() {
673 *ch = if global_ch < num_out {
674 unsafe { audio_channel_ptr(ptr, global_ch, 1) }
675 } else {
676 ptr::null_mut()
677 };
678 global_ch += 1;
679 }
680 }
681 } else {
682 let mut in_ptrs: [*mut f32; MAX_CHANNELS] = [ptr::null_mut(); MAX_CHANNELS];
683 let mut out_ptrs: [*mut f32; MAX_CHANNELS] = [ptr::null_mut(); MAX_CHANNELS];
684 for (ch, in_ptr) in in_ptrs
685 .iter_mut()
686 .enumerate()
687 .take(num_in.min(MAX_CHANNELS))
688 {
689 *in_ptr = unsafe { audio_channel_ptr(ptr, ch, 0) };
690 }
691 for (ch, out_ptr) in out_ptrs
692 .iter_mut()
693 .enumerate()
694 .take(num_out.min(MAX_CHANNELS))
695 {
696 *out_ptr = unsafe { audio_channel_ptr(ptr, ch, 1) };
697 }
698 }
699
700 let mut event_buf = EventBuffer::new();
701 while let Some(ev) = param_ring.pop() {
702 match ev.event_kind {
703 PARAM_EVENT_MOD => {
704 event_buf.push_param_mod(ev.param_index, ev.value as f64, ev.sample_offset);
705 }
706 PARAM_EVENT_GESTURE_BEGIN => {
707 event_buf.push_param_gesture_begin(ev.param_index, ev.sample_offset);
708 }
709 PARAM_EVENT_GESTURE_END => {
710 event_buf.push_param_gesture_end(ev.param_index, ev.sample_offset);
711 }
712 _ => {
713 event_buf.push_param_value(
714 ev.param_index,
715 ev.value as f64,
716 ev.sample_offset,
717 );
718 }
719 }
720 }
721 while let Some(ev) = midi_ring.pop() {
722 if has_note_ports {
723 self.push_midi_as_clap_events(
724 &mut event_buf,
725 ev.data,
726 ev.channel as u16,
727 ev.sample_offset,
728 );
729 } else {
730 event_buf.push_midi(ev.data, ev.channel as u16, ev.sample_offset);
731 }
732 }
733
734 let in_events = event_buf.as_input_events();
735
736 let mut event_capture = EventCapture::new();
737 let out_events = event_capture.as_output_events();
738
739 if PARAMS_FLUSH_REQUESTED.swap(false, Ordering::Acquire)
740 && let Some(params_ptr) = params_ext
741 {
742 unsafe {
743 let flush = (*params_ptr).flush;
744 if let Some(f) = flush {
745 let empty_in = crate::clap::empty_input_events();
746 let mut flush_capture = EventCapture::new();
747 let flush_out = flush_capture.as_output_events();
748 f(plugin.plugin_ptr(), &empty_in, &flush_out);
749
750 for bytes in flush_capture.drain() {
751 if bytes.len() >= std::mem::size_of::<ClapEventHeader>() {
752 let h = &*(bytes.as_ptr() as *const ClapEventHeader);
753 self.echo_event_to_daw(h, &bytes, &echo_ring);
754 }
755 }
756 }
757 }
758 }
759
760 let transport =
761 unsafe { transport_ref(ptr) as *const TransportState as *const std::ffi::c_void };
762
763 if !started_processing {
764 set_thread_type(ThreadType::AudioThread);
765 if let Err(_e) = plugin.start_processing() {
766 break;
767 }
768 started_processing = true;
769 }
770
771 set_thread_type(ThreadType::AudioThread);
772
773 let process_result = if let Some(ref mut pb) = port_buffers {
774 let process = ClapProcess {
775 steady_time,
776 frames_count: block_size as u32,
777 transport,
778 audio_inputs: pb.inputs.as_ptr(),
779 audio_outputs: pb.outputs.as_mut_ptr(),
780 audio_inputs_count: pb.inputs.len() as u32,
781 audio_outputs_count: pb.outputs.len() as u32,
782 in_events: &in_events,
783 out_events: &out_events,
784 };
785 plugin.process(&process)
786 } else {
787 let mut fallback_in_ptrs: Vec<*mut f32> = Vec::new();
788 let mut fallback_out_ptrs: Vec<*mut f32> = Vec::new();
789 fallback_in_ptrs.resize(num_in.min(MAX_CHANNELS), ptr::null_mut());
790 fallback_out_ptrs.resize(num_out.min(MAX_CHANNELS), ptr::null_mut());
791 for (ch, in_ptr) in fallback_in_ptrs.iter_mut().enumerate() {
792 *in_ptr = unsafe { audio_channel_ptr(ptr, ch, 0) };
793 }
794 for (ch, out_ptr) in fallback_out_ptrs.iter_mut().enumerate() {
795 *out_ptr = unsafe { audio_channel_ptr(ptr, ch, 1) };
796 }
797 let fallback_audio_in = ClapAudioBuffer {
798 data32: fallback_in_ptrs.as_mut_ptr(),
799 data64: ptr::null_mut(),
800 channel_count: num_in as u32,
801 latency: 0,
802 constant_mask: 0,
803 };
804 let mut fallback_audio_out = ClapAudioBuffer {
805 data32: fallback_out_ptrs.as_mut_ptr(),
806 data64: ptr::null_mut(),
807 channel_count: num_out as u32,
808 latency: 0,
809 constant_mask: 0,
810 };
811 let process = ClapProcess {
812 steady_time,
813 frames_count: block_size as u32,
814 transport,
815 audio_inputs: &fallback_audio_in,
816 audio_outputs: &mut fallback_audio_out,
817 audio_inputs_count: 1,
818 audio_outputs_count: 1,
819 in_events: &in_events,
820 out_events: &out_events,
821 };
822 plugin.process(&process)
823 };
824
825 set_thread_type(ThreadType::MainThread);
826
827 if let Err(_e) = process_result {
828 break;
829 }
830
831 steady_time += block_size as i64;
832
833 for bytes in event_capture.drain() {
834 if bytes.len() >= std::mem::size_of::<ClapEventHeader>() {
835 let h = unsafe { &*(bytes.as_ptr() as *const ClapEventHeader) };
836 self.echo_event_to_daw(h, &bytes, &echo_ring);
837 }
838 }
839
840 if let Err(_e) = self.events.signal_daw() {
841 break;
842 }
843 }
844
845 if started_processing {
846 set_thread_type(ThreadType::AudioThread);
847 plugin.stop_processing();
848 set_thread_type(ThreadType::MainThread);
849 }
850 plugin.deactivate();
851 }
852
853 pub fn shutdown(self) {}
854
855 fn push_midi_as_clap_events(
856 &self,
857 event_buf: &mut EventBuffer,
858 data: [u8; 3],
859 port_index: u16,
860 sample_offset: u32,
861 ) {
862 let status = data[0] & 0xF0;
863 let channel = (data[0] & 0x0F) as i16;
864 let note_id = -1i32;
865 match status {
866 0x90 => {
867 let velocity = data[2] as f64 / 127.0;
868 if velocity > 0.0 {
869 event_buf.push_note_on(
870 note_id,
871 port_index as i16,
872 channel,
873 data[1] as i16,
874 velocity,
875 sample_offset,
876 );
877 } else {
878 event_buf.push_note_off(
879 note_id,
880 port_index as i16,
881 channel,
882 data[1] as i16,
883 0.0,
884 sample_offset,
885 );
886 }
887 }
888 0x80 => {
889 let velocity = data[2] as f64 / 127.0;
890 event_buf.push_note_off(
891 note_id,
892 port_index as i16,
893 channel,
894 data[1] as i16,
895 velocity,
896 sample_offset,
897 );
898 }
899 _ => {}
900 }
901
902 event_buf.push_midi(data, port_index, sample_offset);
903 }
904
905 fn echo_event_to_daw(
906 &self,
907 header: &ClapEventHeader,
908 bytes: &[u8],
909 echo_ring: &RingBuffer<ParameterEvent>,
910 ) {
911 match header.type_ {
912 crate::clap::CLAP_EVENT_PARAM_VALUE
913 if bytes.len() >= std::mem::size_of::<ClapEventParamValue>() =>
914 {
915 let ev = unsafe { &*(bytes.as_ptr() as *const ClapEventParamValue) };
916 let echo = ParameterEvent {
917 param_index: ev.param_id,
918 value: ev.value as f32,
919 sample_offset: ev.header.time,
920 event_kind: PARAM_EVENT_VALUE,
921 };
922 if !echo_ring.push(echo) {}
923 }
924 crate::clap::CLAP_EVENT_PARAM_MOD
925 if bytes.len() >= std::mem::size_of::<ClapEventParamMod>() =>
926 {
927 let ev = unsafe { &*(bytes.as_ptr() as *const ClapEventParamMod) };
928 let echo = ParameterEvent {
929 param_index: ev.param_id,
930 value: ev.amount as f32,
931 sample_offset: ev.header.time,
932 event_kind: PARAM_EVENT_MOD,
933 };
934 if !echo_ring.push(echo) {}
935 }
936 crate::clap::CLAP_EVENT_PARAM_GESTURE_BEGIN
937 if bytes.len() >= std::mem::size_of::<ClapEventParamGesture>() =>
938 {
939 let ev = unsafe { &*(bytes.as_ptr() as *const ClapEventParamGesture) };
940 let echo = ParameterEvent {
941 param_index: ev.param_id,
942 value: 0.0,
943 sample_offset: ev.header.time,
944 event_kind: PARAM_EVENT_GESTURE_BEGIN,
945 };
946 if !echo_ring.push(echo) {}
947 }
948 crate::clap::CLAP_EVENT_PARAM_GESTURE_END
949 if bytes.len() >= std::mem::size_of::<ClapEventParamGesture>() =>
950 {
951 let ev = unsafe { &*(bytes.as_ptr() as *const ClapEventParamGesture) };
952 let echo = ParameterEvent {
953 param_index: ev.param_id,
954 value: 0.0,
955 sample_offset: ev.header.time,
956 event_kind: PARAM_EVENT_GESTURE_END,
957 };
958 if !echo_ring.push(echo) {}
959 }
960 _ => {}
961 }
962 }
963
964 #[cfg(unix)]
965 fn poll_daw_and_fds(&self, daw_fd: i32, timeout: Duration) -> (bool, Vec<(i32, u32)>) {
966 let fds = host_fds().lock().unwrap();
967 if fds.is_empty() {
968 return (self.events.wait_daw(timeout).is_ok(), Vec::new());
969 }
970 let mut poll_fds: Vec<libc::pollfd> = Vec::with_capacity(fds.len() + 1);
971 poll_fds.push(libc::pollfd {
972 fd: daw_fd,
973 events: libc::POLLIN,
974 revents: 0,
975 });
976 for f in fds.iter() {
977 let mut events = 0;
978 if f.flags & 1 != 0 {
979 events |= libc::POLLIN;
980 }
981 if f.flags & 2 != 0 {
982 events |= libc::POLLOUT;
983 }
984 if f.flags & 4 != 0 {
985 events |= libc::POLLERR;
986 }
987 poll_fds.push(libc::pollfd {
988 fd: f.fd,
989 events,
990 revents: 0,
991 });
992 }
993 let ms = timeout.as_millis().clamp(0, i32::MAX as u128) as i32;
994 let rc = unsafe { libc::poll(poll_fds.as_mut_ptr(), poll_fds.len() as libc::nfds_t, ms) };
995 if rc < 0 {
996 return (false, Vec::new());
997 }
998 let mut ready_fds = Vec::new();
999 for (i, f) in fds.iter().enumerate() {
1000 let pfd = &poll_fds[i + 1];
1001 if pfd.revents != 0 {
1002 let mut flags = 0;
1003 if pfd.revents & libc::POLLIN != 0 {
1004 flags |= 1;
1005 }
1006 if pfd.revents & libc::POLLOUT != 0 {
1007 flags |= 2;
1008 }
1009 if pfd.revents & libc::POLLERR != 0 {
1010 flags |= 4;
1011 }
1012 ready_fds.push((f.fd, flags));
1013 }
1014 }
1015 (poll_fds[0].revents & libc::POLLIN != 0, ready_fds)
1016 }
1017
1018 fn next_timer_ms(&self) -> u64 {
1019 let timers = host_timers().lock().unwrap();
1020 let now = Instant::now();
1021 timers
1022 .iter()
1023 .map(|t| {
1024 if t.deadline <= now {
1025 0
1026 } else {
1027 (t.deadline - now).as_millis() as u64
1028 }
1029 })
1030 .min()
1031 .unwrap_or(100)
1032 }
1033
1034 fn handle_idle_work(
1035 &self,
1036 plugin: &PluginInstance,
1037 _params_ext: Option<*const ClapPluginParams>,
1038 timer_ext: Option<*const crate::clap::ClapPluginTimerSupport>,
1039 ) {
1040 let now = Instant::now();
1041 let mut fired_timers = Vec::new();
1042 {
1043 let mut timers = host_timers().lock().unwrap();
1044 for t in timers.iter_mut() {
1045 if t.deadline <= now {
1046 fired_timers.push(t.id);
1047 t.deadline = now + Duration::from_millis(t.period_ms as u64);
1048 }
1049 }
1050 }
1051 if let Some(ext) = timer_ext {
1052 for id in fired_timers {
1053 unsafe {
1054 if let Some(f) = (*ext).on_timer {
1055 f(plugin.plugin_ptr(), id);
1056 }
1057 }
1058 }
1059 }
1060 }
1061}