use truce_core::buffer::AudioBuffer;
use truce_core::bus::BusLayout;
use truce_core::config::AudioConfig;
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::{ForeignState, MigratedState, StateLoadError};
use truce_gui_types::interaction::WidgetRegion;
use truce_gui_types::widgets::WidgetType;
use truce_params::sample::Sample;
pub trait PluginLogicCore<S: Sample = f32>: 'static {
type Params: truce_params::Params;
type DspState: Send + 'static;
const PRESERVE_DSP_STATE: bool = true;
#[must_use]
fn supports_in_place() -> bool {
false
}
#[must_use]
fn bus_layouts() -> Vec<BusLayout> {
vec![BusLayout::stereo()]
}
fn init(params: &Self::Params, cx: &InitContext) -> Self::DspState;
fn reset(state: &mut Self::DspState, params: &Self::Params, config: &AudioConfig);
fn process(
state: &mut Self::DspState,
params: &Self::Params,
buffer: &mut AudioBuffer<S>,
events: &EventList,
context: &mut ProcessContext,
) -> ProcessStatus;
fn save_state(state: &Self::DspState) -> Vec<u8> {
let _ = state;
Vec::new()
}
fn snapshot_into(state: &Self::DspState, buf: &mut Vec<u8>) -> bool {
let _ = (state, buf);
false
}
fn load_state(state: &mut Self::DspState, data: &[u8]) -> Result<(), StateLoadError> {
let _ = (state, data);
Ok(())
}
#[must_use]
fn migrate_state(foreign: &ForeignState) -> Option<MigratedState> {
let _ = foreign;
None
}
fn state_changed(state: &mut Self::DspState, params: &Self::Params) {
let _ = (state, params);
}
fn latency(state: &Self::DspState) -> u32 {
let _ = state;
0
}
fn tail(state: &Self::DspState) -> u32 {
let _ = state;
0
}
}
pub trait PluginEditor<S: Sample> {
type Params: truce_params::Params;
fn editor(params: std::sync::Arc<Self::Params>) -> 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: 'static {
type Params: $crate::__plugin_logic_deps::Params;
type DspState: ::core::default::Default + Send + 'static;
const PRESERVE_DSP_STATE: bool = true;
#[must_use]
fn supports_in_place() -> bool {
false
}
#[must_use]
fn bus_layouts() -> Vec<$crate::__plugin_logic_deps::BusLayout> {
vec![$crate::__plugin_logic_deps::BusLayout::stereo()]
}
fn init(
params: &Self::Params,
cx: &$crate::__plugin_logic_deps::InitContext,
) -> Self::DspState {
let _ = (params, cx);
::core::default::Default::default()
}
fn reset(
state: &mut Self::DspState,
params: &Self::Params,
config: &$crate::__plugin_logic_deps::AudioConfig,
) {
let _ = (state, params, config);
}
fn process(
state: &mut Self::DspState,
params: &Self::Params,
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(state: &Self::DspState) -> Vec<u8> {
let mut buf = Vec::new();
let _ = Self::snapshot_into(state, &mut buf);
buf
}
fn snapshot_into(state: &Self::DspState, buf: &mut Vec<u8>) -> bool {
let _ = (state, buf);
false
}
fn load_state(
state: &mut Self::DspState,
data: &[u8],
) -> Result<(), $crate::__plugin_logic_deps::StateLoadError> {
let _ = (state, data);
Ok(())
}
fn state_changed(state: &mut Self::DspState, params: &Self::Params) {
let _ = (state, params);
}
#[must_use]
fn migrate_state(
foreign: &$crate::__plugin_logic_deps::ForeignState,
) -> Option<$crate::__plugin_logic_deps::MigratedState> {
let _ = foreign;
None
}
fn latency(state: &Self::DspState) -> u32 {
let _ = state;
0
}
fn tail(state: &Self::DspState) -> u32 {
let _ = state;
0
}
fn editor(
params: ::std::sync::Arc<Self::Params>,
) -> 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::config::AudioConfig;
pub use truce_core::dsp_state::{NO_PRESERVE, layout_fingerprint};
pub use truce_core::editor::Editor;
pub use truce_core::events::EventList;
pub use truce_core::process::{ProcessContext, ProcessStatus};
pub use truce_core::state::{ForeignState, MigratedState, StateLoadError};
pub use truce_core::tasks::{InitContext, TaskSpawner};
pub use truce_params::Params;
}
plugin_logic_leaf_trait! {
pub trait PluginLogic<sample = f32>
}
plugin_logic_leaf_trait! {
pub trait PluginLogic64<sample = f64>
}
macro_rules! pure_plugin_leaf_trait {
($(#[$attr:meta])* $vis:vis trait $name:ident: $leaf:ident<sample = $sample:ty>) => {
$(#[$attr])*
$vis trait $name: 'static {
type Params: crate::__plugin_logic_deps::Params;
#[must_use]
fn supports_in_place() -> bool {
false
}
#[must_use]
fn bus_layouts() -> Vec<crate::__plugin_logic_deps::BusLayout> {
vec![crate::__plugin_logic_deps::BusLayout::stereo()]
}
fn process(
params: &Self::Params,
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;
#[must_use]
fn migrate_state(
foreign: &crate::__plugin_logic_deps::ForeignState,
) -> Option<crate::__plugin_logic_deps::MigratedState> {
let _ = foreign;
None
}
fn editor(
params: ::std::sync::Arc<Self::Params>,
) -> Box<dyn crate::__plugin_logic_deps::Editor>;
}
impl<T: $name> $leaf for T {
type Params = <T as $name>::Params;
type DspState = ();
fn supports_in_place() -> bool {
<T as $name>::supports_in_place()
}
fn bus_layouts() -> Vec<crate::__plugin_logic_deps::BusLayout> {
<T as $name>::bus_layouts()
}
fn process(
_state: &mut (),
params: &Self::Params,
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 {
<T as $name>::process(params, buffer, events, context)
}
fn migrate_state(
foreign: &crate::__plugin_logic_deps::ForeignState,
) -> Option<crate::__plugin_logic_deps::MigratedState> {
<T as $name>::migrate_state(foreign)
}
fn editor(
params: ::std::sync::Arc<Self::Params>,
) -> Box<dyn crate::__plugin_logic_deps::Editor> {
<T as $name>::editor(params)
}
}
};
}
pure_plugin_leaf_trait! {
pub trait PurePluginLogic: PluginLogic<sample = f32>
}
pure_plugin_leaf_trait! {
pub trait PurePluginLogic64: PluginLogic64<sample = f64>
}
pub use crate::__plugin_logic_deps::{InitContext, TaskSpawner};
pub trait BackgroundTasks {
type Params: crate::__plugin_logic_deps::Params;
type Task: Send + 'static;
fn run_task(task: Self::Task, params: &Self::Params);
}
macro_rules! plugin_logic_bridge {
($leaf:ident, $sample:ty) => {
impl<T: $leaf> PluginLogicCore<$sample> for T {
type Params = <T as $leaf>::Params;
type DspState = <T as $leaf>::DspState;
const PRESERVE_DSP_STATE: bool = <T as $leaf>::PRESERVE_DSP_STATE;
fn supports_in_place() -> bool {
<Self as $leaf>::supports_in_place()
}
fn bus_layouts() -> Vec<BusLayout> {
<Self as $leaf>::bus_layouts()
}
fn init(
params: &Self::Params,
cx: &crate::__plugin_logic_deps::InitContext,
) -> Self::DspState {
<Self as $leaf>::init(params, cx)
}
fn reset(state: &mut Self::DspState, params: &Self::Params, config: &AudioConfig) {
<Self as $leaf>::reset(state, params, config);
}
fn process(
state: &mut Self::DspState,
params: &Self::Params,
buffer: &mut AudioBuffer<$sample>,
events: &EventList,
context: &mut ProcessContext,
) -> ProcessStatus {
let _denormal_guard = DenormalGuard::new();
<Self as $leaf>::process(state, params, buffer, events, context)
}
fn save_state(state: &Self::DspState) -> Vec<u8> {
<Self as $leaf>::save_state(state)
}
fn snapshot_into(state: &Self::DspState, buf: &mut Vec<u8>) -> bool {
<Self as $leaf>::snapshot_into(state, buf)
}
fn load_state(state: &mut Self::DspState, data: &[u8]) -> Result<(), StateLoadError> {
<Self as $leaf>::load_state(state, data)
}
fn state_changed(state: &mut Self::DspState, params: &Self::Params) {
<Self as $leaf>::state_changed(state, params);
}
fn migrate_state(foreign: &ForeignState) -> Option<MigratedState> {
<Self as $leaf>::migrate_state(foreign)
}
fn latency(state: &Self::DspState) -> u32 {
<Self as $leaf>::latency(state)
}
fn tail(state: &Self::DspState) -> u32 {
<Self as $leaf>::tail(state)
}
}
impl<T: $leaf> PluginEditor<$sample> for T {
type Params = <T as $leaf>::Params;
fn editor(params: std::sync::Arc<Self::Params>) -> Box<dyn Editor> {
<Self as $leaf>::editor(params)
}
}
};
}
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
}