use truce_core::buffer::AudioBuffer;
use truce_core::bus::BusLayout;
use truce_core::denormal::DenormalGuard;
use truce_core::editor::Editor;
use truce_core::events::EventList;
use truce_core::process::{ProcessContext, ProcessStatus};
use truce_core::state::StateLoadError;
use truce_gui_types::interaction::WidgetRegion;
use truce_gui_types::widgets::WidgetType;
use truce_params::sample::Sample;
pub trait PluginLogicCore<S: Sample = f32>: Send + 'static {
#[must_use]
fn supports_in_place() -> bool
where
Self: Sized;
#[must_use]
fn bus_layouts() -> Vec<BusLayout>
where
Self: Sized;
fn reset(&mut self, sample_rate: f64, max_block_size: usize);
fn process(
&mut self,
buffer: &mut AudioBuffer<S>,
events: &EventList,
context: &mut ProcessContext,
) -> ProcessStatus;
fn save_state(&self) -> Vec<u8>;
fn load_state(&mut self, data: &[u8]) -> Result<(), StateLoadError>;
fn state_changed(&mut self);
fn latency(&self) -> u32;
fn tail(&self) -> u32;
fn editor(&self) -> Box<dyn Editor>;
}
#[doc(hidden)]
#[macro_export]
macro_rules! plugin_logic_leaf_trait {
($(#[$attr:meta])* $vis:vis trait $name:ident<sample = $sample:ty>) => {
$(#[$attr])*
$vis trait $name: Send + 'static {
#[must_use]
fn supports_in_place() -> bool
where
Self: Sized,
{
false
}
#[must_use]
fn bus_layouts() -> Vec<$crate::__plugin_logic_deps::BusLayout>
where
Self: Sized,
{
vec![$crate::__plugin_logic_deps::BusLayout::stereo()]
}
fn reset(&mut self, sample_rate: f64, max_block_size: usize);
fn process(
&mut self,
buffer: &mut $crate::__plugin_logic_deps::AudioBuffer<$sample>,
events: &$crate::__plugin_logic_deps::EventList,
context: &mut $crate::__plugin_logic_deps::ProcessContext,
) -> $crate::__plugin_logic_deps::ProcessStatus;
fn save_state(&self) -> Vec<u8> {
Vec::new()
}
fn load_state(
&mut self,
_data: &[u8],
) -> Result<(), $crate::__plugin_logic_deps::StateLoadError> {
Ok(())
}
fn state_changed(&mut self) {}
fn latency(&self) -> u32 {
0
}
fn tail(&self) -> u32 {
0
}
fn editor(&self) -> Box<dyn $crate::__plugin_logic_deps::Editor>;
}
};
}
#[doc(hidden)]
pub mod __plugin_logic_deps {
pub use truce_core::buffer::AudioBuffer;
pub use truce_core::bus::BusLayout;
pub use truce_core::editor::Editor;
pub use truce_core::events::EventList;
pub use truce_core::process::{ProcessContext, ProcessStatus};
pub use truce_core::state::StateLoadError;
}
plugin_logic_leaf_trait! {
pub trait PluginLogic<sample = f32>
}
plugin_logic_leaf_trait! {
pub trait PluginLogic64<sample = f64>
}
macro_rules! plugin_logic_bridge {
($leaf:ident, $sample:ty) => {
impl<T: $leaf> PluginLogicCore<$sample> for T {
fn supports_in_place() -> bool
where
Self: Sized,
{
<Self as $leaf>::supports_in_place()
}
fn bus_layouts() -> Vec<BusLayout>
where
Self: Sized,
{
<Self as $leaf>::bus_layouts()
}
fn reset(&mut self, sample_rate: f64, max_block_size: usize) {
<Self as $leaf>::reset(self, sample_rate, max_block_size);
}
fn process(
&mut self,
buffer: &mut AudioBuffer<$sample>,
events: &EventList,
context: &mut ProcessContext,
) -> ProcessStatus {
let _denormal_guard = DenormalGuard::new();
<Self as $leaf>::process(self, buffer, events, context)
}
fn save_state(&self) -> Vec<u8> {
<Self as $leaf>::save_state(self)
}
fn load_state(&mut self, data: &[u8]) -> Result<(), StateLoadError> {
<Self as $leaf>::load_state(self, data)
}
fn state_changed(&mut self) {
<Self as $leaf>::state_changed(self);
}
fn latency(&self) -> u32 {
<Self as $leaf>::latency(self)
}
fn tail(&self) -> u32 {
<Self as $leaf>::tail(self)
}
fn editor(&self) -> Box<dyn Editor> {
<Self as $leaf>::editor(self)
}
}
};
}
plugin_logic_bridge!(PluginLogic, f32);
plugin_logic_bridge!(PluginLogic64, f64);
#[must_use]
pub fn default_hit_test(widgets: &[WidgetRegion], x: f32, y: f32) -> Option<usize> {
for (i, w) in widgets.iter().enumerate() {
if w.widget_type == WidgetType::Meter {
continue;
}
if w.widget_type == WidgetType::Knob {
let dx = x - w.cx;
let dy = y - w.cy;
if dx * dx + dy * dy <= w.radius * w.radius {
return Some(i);
}
} else if x >= w.x && x <= w.x + w.w && y >= w.y && y <= w.y + w.h {
return Some(i);
}
}
None
}