#[macro_export]
macro_rules! plugin {
(
logic: $logic:ty,
params: $params:ty $(,)?
) => {
$crate::__plugin_impl!($logic, $params);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __plugin_impl {
($logic:ty, $params:ty) => {
$crate::__reexport::__truce_lv2_emit_root!($params);
$crate::__reexport::export_plugin!($logic, $params);
#[allow(unexpected_cfgs)]
mod __truce_runtime {
use super::*;
#[cfg(any(not(feature = "shell"), test))]
$crate::__reexport::export_static! {
params: $params,
info: $crate::prelude::plugin_info!(),
logic: $logic,
}
#[cfg(all(feature = "shell", not(test)))]
$crate::__plugin_hot_reload!($logic, $params);
}
#[doc(hidden)]
pub use __truce_runtime::__HotShellWrapper;
pub type Plugin = __HotShellWrapper;
#[doc(hidden)]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn __truce_screenshot(
state_ptr: *const u8,
state_len: usize,
out_path_ptr: *const u8,
out_path_len: usize,
scale: f64,
) -> u32 {
let state: Option<&[u8]> = if state_len == 0 {
None
} else {
Some(::std::slice::from_raw_parts(state_ptr, state_len))
};
let path_bytes = ::std::slice::from_raw_parts(out_path_ptr, out_path_len);
let path_str = match ::std::str::from_utf8(path_bytes) {
Ok(s) => s,
Err(e) => {
::std::eprintln!("[truce] __truce_screenshot: invalid UTF-8 in out_path: {e}");
return 1;
}
};
let path = ::std::path::Path::new(path_str);
if let Some(parent) = path.parent() {
let _ = ::std::fs::create_dir_all(parent);
}
let resolved_scale = if scale.is_finite() && scale > 0.0 {
scale
} else {
$crate::core::screenshot::DEFAULT_SCREENSHOT_SCALE
};
let (pixels, w, h) = $crate::core::screenshot::render_with_state_at_scale::<Plugin>(
state,
resolved_scale,
);
$crate::core::screenshot::save_png(path, &pixels, w, h);
0
}
#[allow(unexpected_cfgs)]
mod __truce_format_exports {
use super::__HotShellWrapper;
#[cfg(feature = "clap")]
::truce_clap::export_clap!(__HotShellWrapper);
#[cfg(feature = "vst3")]
::truce_vst3::export_vst3!(__HotShellWrapper);
#[cfg(feature = "vst2")]
::truce_vst2::export_vst2!(__HotShellWrapper);
#[cfg(feature = "lv2")]
::truce_lv2::export_lv2!(__HotShellWrapper);
#[cfg(feature = "aax")]
::truce_aax::export_aax!(__HotShellWrapper);
#[cfg(feature = "au")]
::truce_au::export_au!(__HotShellWrapper);
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __plugin_hot_reload {
($logic:ty, $params:ty) => {
pub struct __HotShellWrapper {
inner: $crate::__reexport::HotShell<$params, Sample>,
}
impl __HotShellWrapper {
fn dylib_path() -> std::path::PathBuf {
if let Ok(p) = std::env::var("TRUCE_LOGIC_PATH") {
return std::path::PathBuf::from(p);
}
let crate_name = env!("CARGO_PKG_NAME");
if let Some(sidecar) = $crate::__reexport::shell_sidecar_path(crate_name) {
if let Ok(contents) = std::fs::read_to_string(&sidecar) {
let trimmed = contents.trim();
if !trimmed.is_empty() {
let p = std::path::PathBuf::from(trimmed);
if p.is_file() {
return p;
}
eprintln!(
"[truce] sidecar {} points at missing dylib {}; \
falling back to manifest-relative search",
sidecar.display(),
p.display(),
);
}
}
}
panic!(
"truce hot-reload: no logic dylib path resolved. \
The shell sidecar at $HOME/.truce/shell/{}.path is \
missing or empty and TRUCE_LOGIC_PATH is unset. \
Run `cargo truce install --shell` to write the \
sidecar, or set TRUCE_LOGIC_PATH explicitly.",
crate_name,
);
}
}
impl $crate::core::plugin::Plugin for __HotShellWrapper {
type Sample = Sample;
fn supports_in_place() -> bool
where
Self: Sized,
{
<$logic as $crate::gui::PluginLogicCore<Sample>>::supports_in_place()
}
fn info() -> $crate::core::info::PluginInfo
where
Self: Sized,
{
$crate::prelude::plugin_info!()
}
fn bus_layouts() -> Vec<$crate::core::bus::BusLayout>
where
Self: Sized,
{
<$logic as $crate::gui::PluginLogicCore<Sample>>::bus_layouts()
}
fn init(&mut self) {
self.inner.init();
}
fn reset(&mut self, sample_rate: f64, max_block_size: usize) {
self.inner.reset(sample_rate, max_block_size);
}
fn process(
&mut self,
buffer: &mut $crate::core::buffer::AudioBuffer<Sample>,
events: &$crate::core::events::EventList,
context: &mut $crate::core::process::ProcessContext,
) -> $crate::core::process::ProcessStatus {
self.inner.process(buffer, events, context)
}
fn save_state(&self) -> Vec<u8> {
self.inner.save_state()
}
fn load_state(
&mut self,
data: &[u8],
) -> Result<(), $crate::core::state::StateLoadError> {
self.inner.load_state(data)
}
fn editor(&mut self) -> Option<Box<dyn $crate::core::editor::Editor>> {
self.inner.editor()
}
fn latency(&self) -> u32 {
self.inner.latency()
}
fn tail(&self) -> u32 {
self.inner.tail()
}
fn get_meter(&self, meter_id: u32) -> f32 {
self.inner.get_meter(meter_id)
}
}
impl $crate::core::export::PluginExport for __HotShellWrapper {
type Params = $params;
fn create() -> Self {
let params = <$params>::new();
let path = Self::dylib_path();
Self {
inner: $crate::__reexport::HotShell::new(params, path),
}
}
fn params(&self) -> &$params {
&self.inner.params
}
fn params_arc(&self) -> std::sync::Arc<$params> {
std::sync::Arc::clone(&self.inner.params)
}
}
};
}