Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 4 additions & 9 deletions examples/gain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ impl Plugin for Gain {
],
params: GainParams::params(),
has_view: true,
size: Size {
width: 256.0,
height: 256.0
}
}
}

Expand Down Expand Up @@ -336,15 +340,6 @@ impl GainView {
}

impl View for GainView {
fn size(&self) -> Size {
let size = self.task.with(|state, _| state.window.as_ref().unwrap().size());

Size {
width: size.width,
height: size.height,
}
}

fn param_changed(&mut self, id: ParamId, value: ParamValue) {
self.task.with(|state, _| {
state.params.set_param(id, value);
Expand Down
148 changes: 128 additions & 20 deletions src/format/clap/gui.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::ffi::{c_char, CStr};
use std::future::Future;
use std::os::raw::c_int;
use std::rc::Rc;
use std::sync::Arc;

use clap_sys::ext::{gui::*, params::*};
use clap_sys::{host::*, plugin::*};

use super::instance::Instance;
use super::instance::{Instance, MainThreadState};
use crate::params::{ParamId, ParamValue};
use crate::plugin::Plugin;
use crate::sync::param_gestures::ParamGestures;
use crate::view::{ParentWindow, RawParent, View, ViewHost, ViewHostInner};
use clap_sys::ext::posix_fd_support::{
clap_plugin_posix_fd_support, clap_posix_fd_flags, CLAP_POSIX_FD_READ,
};
use clap_sys::ext::timer_support::clap_plugin_timer_support;
use clap_sys::ext::{gui::*, params::*};
use clap_sys::id::{clap_id, CLAP_INVALID_ID};
use clap_sys::{host::*, plugin::*};

struct ClapViewHost {
pub struct ClapViewHost {
host: *const clap_host,
host_params: Option<*const clap_host_params>,
param_map: Arc<HashMap<ParamId, usize>>,
param_gestures: Arc<ParamGestures>,
#[cfg_attr(not(target_os = "linux"), allow(unused))]
timer_id: Option<clap_id>,
}

impl ViewHostInner for ClapViewHost {
Expand Down Expand Up @@ -73,6 +82,17 @@ impl<P: Plugin> Instance<P> {
#[cfg(target_os = "linux")]
const API: &'static CStr = CLAP_WINDOW_API_X11;

#[cfg(target_os = "linux")]
pub(crate) const TIMER_SUPPORT: clap_plugin_timer_support = clap_plugin_timer_support {
on_timer: Some(Self::timer_support_on_timer),
};

#[cfg(target_os = "linux")]
pub(crate) const POSIX_FD_SUPPORT: clap_plugin_posix_fd_support =
clap_plugin_posix_fd_support {
on_fd: Some(Self::posix_fd_support_on_fd),
};

unsafe extern "C" fn gui_is_api_supported(
_plugin: *const clap_plugin,
api: *const c_char,
Expand Down Expand Up @@ -113,6 +133,18 @@ impl<P: Plugin> Instance<P> {
let instance = &*(plugin as *const Self);
let main_thread_state = &mut *instance.main_thread_state.get();

if let Some(posix_fd_support) = (*instance.host_extensions.get()).posix_fd_support {
if let Some(fd) = main_thread_state.view.as_ref().unwrap().file_descriptor() {
(*posix_fd_support).unregister_fd.unwrap_unchecked()(instance.host, fd);
}
}

if let Some(timer_support) = (*instance.host_extensions.get()).timer_support {
(*timer_support).unregister_timer.unwrap_unchecked()(
instance.host, main_thread_state.view_host.as_ref().unwrap().timer_id.unwrap()
);
}

main_thread_state.view = None;
}

Expand All @@ -125,19 +157,11 @@ impl<P: Plugin> Instance<P> {
width: *mut u32,
height: *mut u32,
) -> bool {
let instance = &*(plugin as *const Self);
let main_thread_state = &mut *instance.main_thread_state.get();

if let Some(view) = &main_thread_state.view {
let size = view.size();

*width = size.width.round() as u32;
*height = size.height.round() as u32;

return true;
}
let size = P::info().size;
*width = size.width as u32;
*height = size.height as u32;

false
true
}

unsafe extern "C" fn gui_can_resize(_plugin: *const clap_plugin) -> bool {
Expand Down Expand Up @@ -189,14 +213,63 @@ impl<P: Plugin> Instance<P> {
let instance = &*(plugin as *const Self);
let main_thread_state = &mut *instance.main_thread_state.get();

let host = ViewHost::from_inner(Rc::new(ClapViewHost {
let mut timer_id: Option<clap_id> = None;
#[cfg(target_os = "linux")]
{
let host_extensions = instance.host_extensions.get();
if (*host_extensions).timer_support.is_none()
{
dbg!("missing timer support");
return false;
}
let timer_support = (*host_extensions).timer_support.unwrap();
const TIMER_PERIOD_MS: u32 = 16;
let mut maybe_timer_id = CLAP_INVALID_ID;
if !(*timer_support).register_timer.unwrap_unchecked()(
instance.host,
TIMER_PERIOD_MS,
&mut maybe_timer_id,
) {
dbg!("Failed to register timer");
return false;
}
timer_id = Some(maybe_timer_id);
}

let view_host = Rc::new(ClapViewHost {
host: instance.host,
host_params: main_thread_state.host_params,
param_map: Arc::clone(&instance.param_map),
param_gestures: Arc::clone(&instance.param_gestures),
}));
timer_id,
});
main_thread_state.view_host = Some(view_host);
let view_host = ViewHost::from_inner(main_thread_state.view_host.as_ref().unwrap().clone());
let parent = ParentWindow::from_raw(raw_parent);
let view = main_thread_state.plugin.view(host, &parent);
let view = main_thread_state.plugin.view(view_host, &parent);

#[cfg(target_os = "linux")]
{
let host_extensions = instance.host_extensions.get();
if (*host_extensions).posix_fd_support.is_none()
{
dbg!("missing fd support");
return false;
}
let posix_fd_support = (*host_extensions).posix_fd_support.unwrap();

if let Some(fd) = view.file_descriptor() {
if !(*posix_fd_support).register_fd.unwrap_unchecked()(
instance.host,
fd,
CLAP_POSIX_FD_READ,
) {
dbg!("Failed to register fd");
return false;
}
}
}

main_thread_state.view = Some(view);

true
Expand All @@ -218,4 +291,39 @@ impl<P: Plugin> Instance<P> {
unsafe extern "C" fn gui_hide(_plugin: *const clap_plugin) -> bool {
false
}

#[cfg(target_os = "linux")]
unsafe extern "C" fn timer_support_on_timer(plugin: *const clap_plugin, timer_id: clap_id) {
let instance = &*(plugin as *const Self);
let main_thread_state = unsafe { &mut *instance.main_thread_state.get() };

main_thread_state.view_host.as_ref().unwrap().timer_id;

if let Some(view_host) = &mut main_thread_state.view_host {
if let Some(id) = view_host.timer_id {
if id == timer_id {
if let Some(view) = &mut main_thread_state.view {
view.poll();
}
}
}
}
}

#[cfg(target_os = "linux")]
pub unsafe extern "C" fn posix_fd_support_on_fd(
plugin: *const clap_plugin,
fd: i32,
_flags: clap_posix_fd_flags,
) {
let instance = &*(plugin as *const Self);
let main_thread_state = unsafe { &mut *instance.main_thread_state.get() };
if let Some(view) = &mut main_thread_state.view {
if let Some(fd) = view.file_descriptor() {
if fd == fd {
view.poll();
}
}
}
}
}
53 changes: 50 additions & 3 deletions src/format/clap/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ use std::iter::zip;
use std::ptr::NonNull;
use std::sync::Arc;
use std::{io, mem, ptr, slice};

use clap_sys::ext::{audio_ports::*, audio_ports_config::*, gui::*, params::*, state::*};
use std::rc::Rc;
use clap_sys::ext::{audio_ports::*, audio_ports_config::*, gui::*, params::*, posix_fd_support, state::*};
use clap_sys::{events::*, host::*, id::*, plugin::*, process::*, stream::*};

use clap_sys::ext::posix_fd_support::{clap_host_posix_fd_support, clap_plugin_posix_fd_support, CLAP_EXT_POSIX_FD_SUPPORT};
use clap_sys::ext::timer_support::{clap_host_timer_support, clap_plugin_timer_support, CLAP_EXT_TIMER_SUPPORT};
use super::host::ClapHost;
use crate::buffers::{BufferData, BufferType, Buffers};
use crate::bus::{BusDir, Format};
use crate::engine::{Config, Engine};
use crate::events::{Data, Event, Events};
use crate::format::clap::gui::ClapViewHost;
use crate::host::Host;
use crate::params::{ParamId, ParamInfo, ParamValue};
use crate::plugin::{Plugin, PluginInfo};
Expand Down Expand Up @@ -50,6 +52,7 @@ pub struct MainThreadState<P: Plugin> {
pub layout_index: usize,
pub plugin: P,
pub view: Option<P::View>,
pub view_host: Option<Rc<ClapViewHost>>,
}

pub struct ProcessState<P: Plugin> {
Expand All @@ -60,11 +63,19 @@ pub struct ProcessState<P: Plugin> {
engine: Option<P::Engine>,
}

pub struct HostExtensions {
pub timer_support: Option<*const clap_host_timer_support>,
pub posix_fd_support: Option<*const clap_host_posix_fd_support>,
}

#[repr(C)]
pub struct Instance<P: Plugin> {
#[allow(unused)]
pub clap_plugin: clap_plugin,
pub host: *const clap_host,
// todo: is below comment still correct?
// Safety: We only form an &mut in init(), which must be called before any other methods
pub host_extensions: UnsafeCell<HostExtensions>,
pub info: Arc<PluginInfo>,
pub input_bus_map: Vec<usize>,
pub output_bus_map: Vec<usize>,
Expand Down Expand Up @@ -120,6 +131,10 @@ impl<P: Plugin> Instance<P> {
on_main_thread: Some(Self::on_main_thread),
},
host,
host_extensions: UnsafeCell::new(HostExtensions {
timer_support: None,
posix_fd_support: None,
}),
info: info.clone(),
input_bus_map,
output_bus_map,
Expand All @@ -132,6 +147,7 @@ impl<P: Plugin> Instance<P> {
layout_index: 0,
plugin: P::new(Host::from_inner(Arc::new(ClapHost {}))),
view: None,
view_host: None,
}),
process_state: UnsafeCell::new(ProcessState {
gesture_states: GestureStates::with_count(info.params.len()),
Expand Down Expand Up @@ -311,6 +327,25 @@ impl<P: Plugin> Instance<P> {
if !host_params.is_null() {
main_thread_state.host_params = Some(host_params as *const clap_host_params);
}
let host_extensions = instance.host_extensions.get();

let timer_support = (*instance.host).get_extension.unwrap_unchecked()(
instance.host,
CLAP_EXT_TIMER_SUPPORT.as_ptr(),
);
if !timer_support.is_null() {
// todo: dereferencing seems odd - is this okay?
(*host_extensions).timer_support = Some(timer_support as *const clap_host_timer_support);
}

let posix_fd_support = (*instance.host).get_extension.unwrap_unchecked()(
instance.host,
CLAP_EXT_POSIX_FD_SUPPORT.as_ptr(),
);
if !posix_fd_support.is_null() {
// todo: dereferencing seems odd - is this okay?
(*host_extensions).posix_fd_support = Some(posix_fd_support as *const clap_host_posix_fd_support);
}

true
}
Expand Down Expand Up @@ -524,6 +559,18 @@ impl<P: Plugin> Instance<P> {
}
}

// todo: adding this required making below constants public - is there
// a better way?
#[cfg(target_os = "linux")]
if id == CLAP_EXT_TIMER_SUPPORT {
return &Self::TIMER_SUPPORT as *const _ as *const c_void;
}

#[cfg(target_os = "linux")]
if id == CLAP_EXT_POSIX_FD_SUPPORT {
return &Self::POSIX_FD_SUPPORT as *const _ as *const c_void;
}

ptr::null()
}

Expand Down
4 changes: 4 additions & 0 deletions src/format/clap/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ impl Plugin for TestPlugin {
layouts: vec![],
params: Vec::new(),
has_view: false,
size: Size {
height: 0.,
width: 0.,
}
}
}
fn new(_host: Host) -> Self {
Expand Down
20 changes: 7 additions & 13 deletions src/format/vst3/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,21 +228,15 @@ impl<P: Plugin> IPlugViewTrait for PlugView<P> {
return kResultFalse;
}

let main_thread_state = &*self.main_thread_state.get();
let plugin_size = P::info().size;

if let Some(view) = &main_thread_state.view {
let view_size = view.size();
let rect = &mut *size;
rect.left = 0;
rect.top = 0;
rect.right = plugin_size.width.round() as int32;
rect.bottom = plugin_size.height.round() as int32;

let rect = &mut *size;
rect.left = 0;
rect.top = 0;
rect.right = view_size.width.round() as int32;
rect.bottom = view_size.height.round() as int32;

return kResultOk;
}

kResultFalse
kResultOk
}

unsafe fn onSize(&self, _newSize: *mut ViewRect) -> tresult {
Expand Down
Loading