reaper_low/
reaper_plugin_context.rs

1use super::raw::{reaper_plugin_info_t, REAPER_PLUGIN_VERSION};
2use std::os::raw::{c_int, c_void};
3use std::ptr::null_mut;
4use vst::api::HostCallbackProc;
5use vst::plugin::HostCallback;
6
7type FunctionProvider = Box<dyn Fn(&std::ffi::CStr) -> isize>;
8
9/// This represents the context which is needed to access REAPER functions from plug-ins.
10///
11/// Once obtained, it is supposed to be passed to [`Reaper::load()`].
12///
13/// [`Reaper::load()`]: struct.Reaper.html#method.load
14pub struct ReaperPluginContext {
15    /// Function which obtains a function pointer for a given REAPER function name.
16    pub(crate) function_provider: FunctionProvider,
17}
18
19impl ReaperPluginContext {
20    /// Creates a plug-in context from an extension entry point plug-in info.
21    ///
22    /// It requires the [`reaper_plugin_info_t`] struct that REAPER provides when calling the
23    /// `ReaperPluginEntry` function (the main entry point for any extension plug-in).
24    ///
25    /// It's recommended to use the `reaper_extension_plugin` macro in the
26    /// [reaper-macros](https://crates.io/crates/reaper-macros) crate instead of calling
27    /// this function directly.
28    ///
29    /// [`reaper_plugin_info_t`]: raw/struct.reaper_plugin_info_t.html
30    pub fn from_extension_plugin(
31        rec: *mut reaper_plugin_info_t,
32    ) -> Result<ReaperPluginContext, &'static str> {
33        let function_provider = create_extension_plugin_function_provider(rec)?;
34        Ok(ReaperPluginContext { function_provider })
35    }
36
37    /// Creates a plug-in context from a VST host callback.
38    ///
39    /// It requires the host callback which [vst-rs](https://crates.io/crates/vst) passes to the
40    /// plugin's [`new()`] function.
41    ///
42    /// [`new()`]: /vst/plugin/trait.Plugin.html#method.new
43    pub fn from_vst_plugin(host: HostCallback) -> Result<ReaperPluginContext, &'static str> {
44        let host_callback = host.raw_callback().ok_or("Host callback not available")?;
45        let function_provider = create_vst_plugin_function_provider(host_callback);
46        Ok(ReaperPluginContext { function_provider })
47    }
48}
49
50fn create_extension_plugin_function_provider(
51    rec: *mut reaper_plugin_info_t,
52) -> Result<FunctionProvider, &'static str> {
53    if rec.is_null() {
54        return Err("rec not available");
55    }
56    let rec = unsafe { *rec };
57    if rec.caller_version != REAPER_PLUGIN_VERSION as c_int {
58        return Err("Caller version doesn't match");
59    }
60    let get_func = rec.GetFunc.ok_or("GetFunc function pointer not set")?;
61    Ok(Box::new(move |name| unsafe {
62        get_func(name.as_ptr()) as isize
63    }))
64}
65
66fn create_vst_plugin_function_provider(host_callback: HostCallbackProc) -> FunctionProvider {
67    Box::new(move |name| {
68        #[allow(overflowing_literals)]
69        host_callback(
70            null_mut(),
71            0xdeadbeef,
72            0xdeadf00d,
73            0,
74            name.as_ptr() as *mut c_void,
75            0.0,
76        )
77    })
78}