Rework Params trait API with Arc instead of Pin
This is a breaking change requiring a small change to plugin implementations. The reason why `Pin<&dyn Params>` was used was more as a hint to indicate that the object must last for the plugin's lifetime, but `Pin` doesn't enforce that. It also makes the APIs a lot more awkward. Requiring the use of `Arc` fixes the following problems: - When storing the params object in the wrapper, the `ParamPtr`s are guaranteed to be stable. - This makes it possible to access the `Params` object without acquiring a lock on the plugin, this is very important for implementing plugin-side preset management. - It enforces immutability on the `Params` object. - And of course the API is much nicer without a bunch of unsafe code to work around Pin's limitations.
This commit is contained in:
parent
7cc05fce9a
commit
083885a40c
|
@ -218,9 +218,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
unsafe impl #impl_generics Params for #struct_name #ty_generics #where_clause {
|
unsafe impl #impl_generics Params for #struct_name #ty_generics #where_clause {
|
||||||
fn param_map(
|
fn param_map(&self) -> Vec<(String, nih_plug::prelude::ParamPtr, String)> {
|
||||||
self: std::pin::Pin<&Self>,
|
|
||||||
) -> Vec<(String, nih_plug::prelude::ParamPtr, String)> {
|
|
||||||
// This may not be in scope otherwise, used to call .as_ptr()
|
// This may not be in scope otherwise, used to call .as_ptr()
|
||||||
use ::nih_plug::param::Param;
|
use ::nih_plug::param::Param;
|
||||||
|
|
||||||
|
@ -231,8 +229,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
||||||
for (nested_params, group_name) in
|
for (nested_params, group_name) in
|
||||||
nested_params_fields.into_iter().zip(nested_params_groups)
|
nested_params_fields.into_iter().zip(nested_params_groups)
|
||||||
{
|
{
|
||||||
let nested_param_map =
|
let nested_param_map = nested_params.param_map();
|
||||||
unsafe { std::pin::Pin::new_unchecked(*nested_params).param_map() };
|
|
||||||
let prefixed_nested_param_map =
|
let prefixed_nested_param_map =
|
||||||
nested_param_map
|
nested_param_map
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -260,7 +257,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
let nested_params_fields: &[&dyn Params] = &[#(&self.#nested_params_field_idents),*];
|
let nested_params_fields: &[&dyn Params] = &[#(&self.#nested_params_field_idents),*];
|
||||||
for nested_params in nested_params_fields {
|
for nested_params in nested_params_fields {
|
||||||
unsafe { serialized.extend(Pin::new_unchecked(*nested_params).serialize_fields()) };
|
serialized.extend(nested_params.serialize_fields());
|
||||||
}
|
}
|
||||||
|
|
||||||
serialized
|
serialized
|
||||||
|
@ -280,7 +277,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
||||||
// once that gets stabilized.
|
// once that gets stabilized.
|
||||||
let nested_params_fields: &[&dyn Params] = &[#(&self.#nested_params_field_idents),*];
|
let nested_params_fields: &[&dyn Params] = &[#(&self.#nested_params_field_idents),*];
|
||||||
for nested_params in nested_params_fields {
|
for nested_params in nested_params_fields {
|
||||||
unsafe { Pin::new_unchecked(*nested_params).deserialize_fields(serialized) };
|
nested_params.deserialize_fields(serialized);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! A simple generic UI widget that renders all parameters in a [`Params`] object as a scrollable
|
//! A simple generic UI widget that renders all parameters in a [`Params`] object as a scrollable
|
||||||
//! list of sliders and labels.
|
//! list of sliders and labels.
|
||||||
|
|
||||||
use std::pin::Pin;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use egui::{TextStyle, Ui, Vec2};
|
use egui::{TextStyle, Ui, Vec2};
|
||||||
use nih_plug::prelude::{Param, ParamFlags, ParamPtr, ParamSetter, Params};
|
use nih_plug::prelude::{Param, ParamFlags, ParamPtr, ParamSetter, Params};
|
||||||
|
@ -35,7 +35,7 @@ pub struct GenericSlider;
|
||||||
/// space.
|
/// space.
|
||||||
pub fn create(
|
pub fn create(
|
||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
params: Pin<&dyn Params>,
|
params: Arc<impl Params>,
|
||||||
setter: &ParamSetter,
|
setter: &ParamSetter,
|
||||||
widget: impl ParamWidget,
|
widget: impl ParamWidget,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -12,14 +12,14 @@
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! pub(crate) fn create(
|
//! pub(crate) fn create(
|
||||||
//! params: Pin<Arc<FooParams>>,
|
//! params: Arc<FooParams>,
|
||||||
//! editor_state: Arc<IcedState>,
|
//! editor_state: Arc<IcedState>,
|
||||||
//! ) -> Option<Box<dyn Editor>> {
|
//! ) -> Option<Box<dyn Editor>> {
|
||||||
//! create_iced_editor::<Foo>(editor_state, params)
|
//! create_iced_editor::<Foo>(editor_state, params)
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! struct FooEditor {
|
//! struct FooEditor {
|
||||||
//! params: Pin<Arc<FooParams>>,
|
//! params: Arc<FooParams>,
|
||||||
//! context: Arc<dyn GuiContext>,
|
//! context: Arc<dyn GuiContext>,
|
||||||
//!
|
//!
|
||||||
//! foo_slider_state: nih_widgets::param_slider::State,
|
//! foo_slider_state: nih_widgets::param_slider::State,
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
//! impl IcedEditor for FooEditor {
|
//! impl IcedEditor for FooEditor {
|
||||||
//! type Executor = executor::Default;
|
//! type Executor = executor::Default;
|
||||||
//! type Message = Message;
|
//! type Message = Message;
|
||||||
//! type InitializationFlags = Pin<Arc<FooParams>>;
|
//! type InitializationFlags = Arc<FooParams>;
|
||||||
//!
|
//!
|
||||||
//! fn new(
|
//! fn new(
|
||||||
//! params: Self::InitializationFlags,
|
//! params: Self::InitializationFlags,
|
||||||
|
@ -141,7 +141,7 @@ pub fn create_iced_editor<E: IcedEditor>(
|
||||||
|
|
||||||
/// A plugin editor using `iced`. This wraps around [`Application`] with the only change being that
|
/// A plugin editor using `iced`. This wraps around [`Application`] with the only change being that
|
||||||
/// the usual `new()` function now additionally takes a `Arc<dyn GuiContext>` that the editor can
|
/// the usual `new()` function now additionally takes a `Arc<dyn GuiContext>` that the editor can
|
||||||
/// store to interact with the parameters. The editor should have a `Pin<Arc<impl Params>>` as part
|
/// store to interact with the parameters. The editor should have a `Arc<impl Params>` as part
|
||||||
/// of their [`InitializationFlags`][Self::InitializationFlags] so it can read the current parameter
|
/// of their [`InitializationFlags`][Self::InitializationFlags] so it can read the current parameter
|
||||||
/// values. See [`Application`] for more information.
|
/// values. See [`Application`] for more information.
|
||||||
pub trait IcedEditor: 'static + Send + Sync + Sized {
|
pub trait IcedEditor: 'static + Send + Sync + Sized {
|
||||||
|
|
|
@ -5,7 +5,7 @@ use atomic_refcell::AtomicRefCell;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use nih_plug::prelude::{Param, ParamFlags, ParamPtr, Params};
|
use nih_plug::prelude::{Param, ParamFlags, ParamPtr, Params};
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ pub struct GenericSlider;
|
||||||
pub struct GenericUi<'a, W: ParamWidget> {
|
pub struct GenericUi<'a, W: ParamWidget> {
|
||||||
state: &'a mut State<W>,
|
state: &'a mut State<W>,
|
||||||
|
|
||||||
params: Pin<&'a dyn Params>,
|
params: Arc<dyn Params>,
|
||||||
|
|
||||||
width: Length,
|
width: Length,
|
||||||
height: Length,
|
height: Length,
|
||||||
|
@ -85,7 +85,7 @@ where
|
||||||
W: ParamWidget,
|
W: ParamWidget,
|
||||||
{
|
{
|
||||||
/// Creates a new [`GenericUi`] for all provided parameters.
|
/// Creates a new [`GenericUi`] for all provided parameters.
|
||||||
pub fn new(state: &'a mut State<W>, params: Pin<&'a dyn Params>) -> Self {
|
pub fn new(state: &'a mut State<W>, params: Arc<dyn Params>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
state,
|
state,
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Generic UIs for NIH-plug using VIZIA.
|
//! Generic UIs for NIH-plug using VIZIA.
|
||||||
|
|
||||||
use std::{ops::Deref, pin::Pin};
|
use std::sync::Arc;
|
||||||
|
|
||||||
use nih_plug::prelude::{ParamFlags, ParamPtr, Params};
|
use nih_plug::prelude::{ParamFlags, ParamPtr, Params};
|
||||||
use vizia::*;
|
use vizia::*;
|
||||||
|
@ -25,14 +25,12 @@ impl GenericUi {
|
||||||
/// })
|
/// })
|
||||||
/// .width(Percentage(100.0));
|
/// .width(Percentage(100.0));
|
||||||
///```
|
///```
|
||||||
pub fn new<L, PsPtr, Ps>(cx: &mut Context, params: L) -> Handle<'_, GenericUi>
|
pub fn new<L, Ps>(cx: &mut Context, params: L) -> Handle<'_, GenericUi>
|
||||||
where
|
where
|
||||||
L: Lens<Target = Pin<PsPtr>> + Copy,
|
L: Lens<Target = Arc<Ps>> + Copy,
|
||||||
PsPtr: 'static + Deref<Target = Ps>,
|
Ps: Params + 'static,
|
||||||
Ps: Params,
|
|
||||||
{
|
{
|
||||||
// Basic styling is done in the `theme.css` style sheet
|
// Basic styling is done in the `theme.css` style sheet
|
||||||
// TODO: Scrolling
|
|
||||||
Self::new_custom(cx, params, |cx, param_ptr| {
|
Self::new_custom(cx, params, |cx, param_ptr| {
|
||||||
HStack::new(cx, |cx| {
|
HStack::new(cx, |cx| {
|
||||||
// Align this on the right
|
// Align this on the right
|
||||||
|
@ -70,15 +68,14 @@ impl GenericUi {
|
||||||
|
|
||||||
/// Creates a new [`GenericUi`] for all provided parameters using a custom closure that receives
|
/// Creates a new [`GenericUi`] for all provided parameters using a custom closure that receives
|
||||||
/// a function that should draw some widget for each parameter.
|
/// a function that should draw some widget for each parameter.
|
||||||
pub fn new_custom<L, PsPtr, Ps>(
|
pub fn new_custom<L, Ps>(
|
||||||
cx: &mut Context,
|
cx: &mut Context,
|
||||||
params: L,
|
params: L,
|
||||||
mut make_widget: impl FnMut(&mut Context, ParamPtr),
|
mut make_widget: impl FnMut(&mut Context, ParamPtr),
|
||||||
) -> Handle<Self>
|
) -> Handle<Self>
|
||||||
where
|
where
|
||||||
L: Lens<Target = Pin<PsPtr>> + Copy,
|
L: Lens<Target = Arc<Ps>> + Copy,
|
||||||
PsPtr: 'static + Deref<Target = Ps>,
|
Ps: Params + 'static,
|
||||||
Ps: Params,
|
|
||||||
{
|
{
|
||||||
// Basic styling is done in the `theme.css` style sheet
|
// Basic styling is done in the `theme.css` style sheet
|
||||||
Self.build2(cx, |cx| {
|
Self.build2(cx, |cx| {
|
||||||
|
|
|
@ -18,7 +18,6 @@ use nih_plug::prelude::Editor;
|
||||||
use nih_plug_vizia::vizia::*;
|
use nih_plug_vizia::vizia::*;
|
||||||
use nih_plug_vizia::widgets::*;
|
use nih_plug_vizia::widgets::*;
|
||||||
use nih_plug_vizia::{assets, create_vizia_editor, ViziaState};
|
use nih_plug_vizia::{assets, create_vizia_editor, ViziaState};
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::CrispParams;
|
use crate::CrispParams;
|
||||||
|
@ -28,7 +27,7 @@ const POINT_SCALE: f32 = 0.75;
|
||||||
|
|
||||||
#[derive(Lens)]
|
#[derive(Lens)]
|
||||||
struct Data {
|
struct Data {
|
||||||
params: Pin<Arc<CrispParams>>,
|
params: Arc<CrispParams>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Model for Data {}
|
impl Model for Data {}
|
||||||
|
@ -39,7 +38,7 @@ pub(crate) fn default_state() -> Arc<ViziaState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create(
|
pub(crate) fn create(
|
||||||
params: Pin<Arc<CrispParams>>,
|
params: Arc<CrispParams>,
|
||||||
editor_state: Arc<ViziaState>,
|
editor_state: Arc<ViziaState>,
|
||||||
) -> Option<Box<dyn Editor>> {
|
) -> Option<Box<dyn Editor>> {
|
||||||
create_vizia_editor(editor_state, move |cx| {
|
create_vizia_editor(editor_state, move |cx| {
|
||||||
|
|
|
@ -20,7 +20,6 @@ extern crate nih_plug;
|
||||||
use nih_plug::prelude::*;
|
use nih_plug::prelude::*;
|
||||||
use nih_plug_vizia::ViziaState;
|
use nih_plug_vizia::ViziaState;
|
||||||
use pcg::Pcg32iState;
|
use pcg::Pcg32iState;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
mod editor;
|
mod editor;
|
||||||
|
@ -44,7 +43,7 @@ const MAX_FILTER_FREQUENCY: f32 = 22_000.0;
|
||||||
/// white (or filtered) noise. That other copy of the sound may have a low-pass filter applied to it
|
/// white (or filtered) noise. That other copy of the sound may have a low-pass filter applied to it
|
||||||
/// since this effect just turns into literal noise at high frequencies.
|
/// since this effect just turns into literal noise at high frequencies.
|
||||||
struct Crisp {
|
struct Crisp {
|
||||||
params: Pin<Arc<CrispParams>>,
|
params: Arc<CrispParams>,
|
||||||
editor_state: Arc<ViziaState>,
|
editor_state: Arc<ViziaState>,
|
||||||
|
|
||||||
/// Needed for computing the filter coefficients.
|
/// Needed for computing the filter coefficients.
|
||||||
|
@ -126,7 +125,7 @@ enum StereoMode {
|
||||||
impl Default for Crisp {
|
impl Default for Crisp {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
params: Arc::pin(CrispParams::default()),
|
params: Arc::new(CrispParams::default()),
|
||||||
editor_state: editor::default_state(),
|
editor_state: editor::default_state(),
|
||||||
|
|
||||||
sample_rate: 1.0,
|
sample_rate: 1.0,
|
||||||
|
@ -308,8 +307,8 @@ impl Plugin for Crisp {
|
||||||
|
|
||||||
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
||||||
|
|
||||||
fn params(&self) -> Pin<&dyn Params> {
|
fn params(&self) -> Arc<dyn Params> {
|
||||||
self.params.as_ref()
|
self.params.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn editor(&self) -> Option<Box<dyn Editor>> {
|
fn editor(&self) -> Option<Box<dyn Editor>> {
|
||||||
|
|
|
@ -18,7 +18,6 @@ use nih_plug::prelude::Editor;
|
||||||
use nih_plug_vizia::vizia::*;
|
use nih_plug_vizia::vizia::*;
|
||||||
use nih_plug_vizia::widgets::*;
|
use nih_plug_vizia::widgets::*;
|
||||||
use nih_plug_vizia::{assets, create_vizia_editor, ViziaState};
|
use nih_plug_vizia::{assets, create_vizia_editor, ViziaState};
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::DiopserParams;
|
use crate::DiopserParams;
|
||||||
|
@ -28,7 +27,7 @@ const POINT_SCALE: f32 = 0.75;
|
||||||
|
|
||||||
#[derive(Lens)]
|
#[derive(Lens)]
|
||||||
struct Data {
|
struct Data {
|
||||||
params: Pin<Arc<DiopserParams>>,
|
params: Arc<DiopserParams>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Model for Data {}
|
impl Model for Data {}
|
||||||
|
@ -39,7 +38,7 @@ pub(crate) fn default_state() -> Arc<ViziaState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create(
|
pub(crate) fn create(
|
||||||
params: Pin<Arc<DiopserParams>>,
|
params: Arc<DiopserParams>,
|
||||||
editor_state: Arc<ViziaState>,
|
editor_state: Arc<ViziaState>,
|
||||||
) -> Option<Box<dyn Editor>> {
|
) -> Option<Box<dyn Editor>> {
|
||||||
create_vizia_editor(editor_state, move |cx| {
|
create_vizia_editor(editor_state, move |cx| {
|
||||||
|
|
|
@ -24,7 +24,6 @@ extern crate nih_plug;
|
||||||
|
|
||||||
use nih_plug::prelude::*;
|
use nih_plug::prelude::*;
|
||||||
use nih_plug_vizia::ViziaState;
|
use nih_plug_vizia::ViziaState;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::simd::f32x2;
|
use std::simd::f32x2;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -49,7 +48,7 @@ const MAX_AUTOMATION_STEP_SIZE: u32 = 512;
|
||||||
// - Briefly muting the output when changing the number of filters to get rid of the clicks
|
// - Briefly muting the output when changing the number of filters to get rid of the clicks
|
||||||
// - A proper GUI
|
// - A proper GUI
|
||||||
struct Diopser {
|
struct Diopser {
|
||||||
params: Pin<Arc<DiopserParams>>,
|
params: Arc<DiopserParams>,
|
||||||
editor_state: Arc<ViziaState>,
|
editor_state: Arc<ViziaState>,
|
||||||
|
|
||||||
/// Needed for computing the filter coefficients.
|
/// Needed for computing the filter coefficients.
|
||||||
|
@ -125,7 +124,7 @@ impl Default for Diopser {
|
||||||
SpectrumInput::new(Self::DEFAULT_NUM_OUTPUTS as usize);
|
SpectrumInput::new(Self::DEFAULT_NUM_OUTPUTS as usize);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
params: Arc::pin(DiopserParams::new(should_update_filters.clone())),
|
params: Arc::new(DiopserParams::new(should_update_filters.clone())),
|
||||||
editor_state: editor::default_state(),
|
editor_state: editor::default_state(),
|
||||||
|
|
||||||
sample_rate: 1.0,
|
sample_rate: 1.0,
|
||||||
|
@ -240,8 +239,8 @@ impl Plugin for Diopser {
|
||||||
|
|
||||||
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
||||||
|
|
||||||
fn params(&self) -> Pin<&dyn Params> {
|
fn params(&self) -> Arc<dyn Params> {
|
||||||
self.params.as_ref()
|
self.params.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn editor(&self) -> Option<Box<dyn Editor>> {
|
fn editor(&self) -> Option<Box<dyn Editor>> {
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
use atomic_float::AtomicF32;
|
use atomic_float::AtomicF32;
|
||||||
use nih_plug::prelude::*;
|
use nih_plug::prelude::*;
|
||||||
use nih_plug_egui::{create_egui_editor, egui, widgets, EguiState};
|
use nih_plug_egui::{create_egui_editor, egui, widgets, EguiState};
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// This is mostly identical to the gain example, minus some fluff, and with a GUI.
|
/// This is mostly identical to the gain example, minus some fluff, and with a GUI.
|
||||||
struct Gain {
|
struct Gain {
|
||||||
params: Pin<Arc<GainParams>>,
|
params: Arc<GainParams>,
|
||||||
editor_state: Arc<EguiState>,
|
editor_state: Arc<EguiState>,
|
||||||
|
|
||||||
/// Needed to normalize the peak meter's response based on the sample rate.
|
/// Needed to normalize the peak meter's response based on the sample rate.
|
||||||
|
@ -32,7 +31,7 @@ struct GainParams {
|
||||||
impl Default for Gain {
|
impl Default for Gain {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
params: Arc::pin(GainParams::default()),
|
params: Arc::new(GainParams::default()),
|
||||||
editor_state: EguiState::from_size(300, 180),
|
editor_state: EguiState::from_size(300, 180),
|
||||||
|
|
||||||
peak_meter_decay_weight: 1.0,
|
peak_meter_decay_weight: 1.0,
|
||||||
|
@ -74,8 +73,8 @@ impl Plugin for Gain {
|
||||||
const ACCEPTS_MIDI: bool = false;
|
const ACCEPTS_MIDI: bool = false;
|
||||||
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
||||||
|
|
||||||
fn params(&self) -> Pin<&dyn Params> {
|
fn params(&self) -> Arc<dyn Params> {
|
||||||
self.params.as_ref()
|
self.params.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn editor(&self) -> Option<Box<dyn Editor>> {
|
fn editor(&self) -> Option<Box<dyn Editor>> {
|
||||||
|
|
|
@ -2,7 +2,6 @@ use atomic_float::AtomicF32;
|
||||||
use nih_plug::prelude::{util, Editor, GuiContext};
|
use nih_plug::prelude::{util, Editor, GuiContext};
|
||||||
use nih_plug_iced::widgets as nih_widgets;
|
use nih_plug_iced::widgets as nih_widgets;
|
||||||
use nih_plug_iced::*;
|
use nih_plug_iced::*;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
@ -14,7 +13,7 @@ pub(crate) fn default_state() -> Arc<IcedState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create(
|
pub(crate) fn create(
|
||||||
params: Pin<Arc<GainParams>>,
|
params: Arc<GainParams>,
|
||||||
peak_meter: Arc<AtomicF32>,
|
peak_meter: Arc<AtomicF32>,
|
||||||
editor_state: Arc<IcedState>,
|
editor_state: Arc<IcedState>,
|
||||||
) -> Option<Box<dyn Editor>> {
|
) -> Option<Box<dyn Editor>> {
|
||||||
|
@ -22,7 +21,7 @@ pub(crate) fn create(
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GainEditor {
|
struct GainEditor {
|
||||||
params: Pin<Arc<GainParams>>,
|
params: Arc<GainParams>,
|
||||||
context: Arc<dyn GuiContext>,
|
context: Arc<dyn GuiContext>,
|
||||||
|
|
||||||
peak_meter: Arc<AtomicF32>,
|
peak_meter: Arc<AtomicF32>,
|
||||||
|
@ -40,7 +39,7 @@ enum Message {
|
||||||
impl IcedEditor for GainEditor {
|
impl IcedEditor for GainEditor {
|
||||||
type Executor = executor::Default;
|
type Executor = executor::Default;
|
||||||
type Message = Message;
|
type Message = Message;
|
||||||
type InitializationFlags = (Pin<Arc<GainParams>>, Arc<AtomicF32>);
|
type InitializationFlags = (Arc<GainParams>, Arc<AtomicF32>);
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
(params, peak_meter): Self::InitializationFlags,
|
(params, peak_meter): Self::InitializationFlags,
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
use atomic_float::AtomicF32;
|
use atomic_float::AtomicF32;
|
||||||
use nih_plug::prelude::*;
|
use nih_plug::prelude::*;
|
||||||
use nih_plug_iced::IcedState;
|
use nih_plug_iced::IcedState;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
mod editor;
|
mod editor;
|
||||||
|
|
||||||
/// This is mostly identical to the gain example, minus some fluff, and with a GUI.
|
/// This is mostly identical to the gain example, minus some fluff, and with a GUI.
|
||||||
struct Gain {
|
struct Gain {
|
||||||
params: Pin<Arc<GainParams>>,
|
params: Arc<GainParams>,
|
||||||
editor_state: Arc<IcedState>,
|
editor_state: Arc<IcedState>,
|
||||||
|
|
||||||
/// Needed to normalize the peak meter's response based on the sample rate.
|
/// Needed to normalize the peak meter's response based on the sample rate.
|
||||||
|
@ -30,7 +29,7 @@ struct GainParams {
|
||||||
impl Default for Gain {
|
impl Default for Gain {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
params: Arc::pin(GainParams::default()),
|
params: Arc::new(GainParams::default()),
|
||||||
editor_state: editor::default_state(),
|
editor_state: editor::default_state(),
|
||||||
|
|
||||||
peak_meter_decay_weight: 1.0,
|
peak_meter_decay_weight: 1.0,
|
||||||
|
@ -71,8 +70,8 @@ impl Plugin for Gain {
|
||||||
const ACCEPTS_MIDI: bool = false;
|
const ACCEPTS_MIDI: bool = false;
|
||||||
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
||||||
|
|
||||||
fn params(&self) -> Pin<&dyn Params> {
|
fn params(&self) -> Arc<dyn Params> {
|
||||||
self.params.as_ref()
|
self.params.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn editor(&self) -> Option<Box<dyn Editor>> {
|
fn editor(&self) -> Option<Box<dyn Editor>> {
|
||||||
|
|
|
@ -3,7 +3,6 @@ use nih_plug::prelude::{util, Editor};
|
||||||
use nih_plug_vizia::vizia::*;
|
use nih_plug_vizia::vizia::*;
|
||||||
use nih_plug_vizia::widgets::*;
|
use nih_plug_vizia::widgets::*;
|
||||||
use nih_plug_vizia::{assets, create_vizia_editor, ViziaState};
|
use nih_plug_vizia::{assets, create_vizia_editor, ViziaState};
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -17,7 +16,7 @@ const STYLE: &str = r#""#;
|
||||||
|
|
||||||
#[derive(Lens)]
|
#[derive(Lens)]
|
||||||
struct Data {
|
struct Data {
|
||||||
params: Pin<Arc<GainParams>>,
|
params: Arc<GainParams>,
|
||||||
peak_meter: Arc<AtomicF32>,
|
peak_meter: Arc<AtomicF32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ pub(crate) fn default_state() -> Arc<ViziaState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create(
|
pub(crate) fn create(
|
||||||
params: Pin<Arc<GainParams>>,
|
params: Arc<GainParams>,
|
||||||
peak_meter: Arc<AtomicF32>,
|
peak_meter: Arc<AtomicF32>,
|
||||||
editor_state: Arc<ViziaState>,
|
editor_state: Arc<ViziaState>,
|
||||||
) -> Option<Box<dyn Editor>> {
|
) -> Option<Box<dyn Editor>> {
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
use atomic_float::AtomicF32;
|
use atomic_float::AtomicF32;
|
||||||
use nih_plug::prelude::*;
|
use nih_plug::prelude::*;
|
||||||
use nih_plug_vizia::ViziaState;
|
use nih_plug_vizia::ViziaState;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
mod editor;
|
mod editor;
|
||||||
|
|
||||||
/// This is mostly identical to the gain example, minus some fluff, and with a GUI.
|
/// This is mostly identical to the gain example, minus some fluff, and with a GUI.
|
||||||
struct Gain {
|
struct Gain {
|
||||||
params: Pin<Arc<GainParams>>,
|
params: Arc<GainParams>,
|
||||||
editor_state: Arc<ViziaState>,
|
editor_state: Arc<ViziaState>,
|
||||||
|
|
||||||
/// Needed to normalize the peak meter's response based on the sample rate.
|
/// Needed to normalize the peak meter's response based on the sample rate.
|
||||||
|
@ -30,7 +29,7 @@ struct GainParams {
|
||||||
impl Default for Gain {
|
impl Default for Gain {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
params: Arc::pin(GainParams::default()),
|
params: Arc::new(GainParams::default()),
|
||||||
editor_state: editor::default_state(),
|
editor_state: editor::default_state(),
|
||||||
|
|
||||||
peak_meter_decay_weight: 1.0,
|
peak_meter_decay_weight: 1.0,
|
||||||
|
@ -71,8 +70,8 @@ impl Plugin for Gain {
|
||||||
const ACCEPTS_MIDI: bool = false;
|
const ACCEPTS_MIDI: bool = false;
|
||||||
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
||||||
|
|
||||||
fn params(&self) -> Pin<&dyn Params> {
|
fn params(&self) -> Arc<dyn Params> {
|
||||||
self.params.as_ref()
|
self.params.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn editor(&self) -> Option<Box<dyn Editor>> {
|
fn editor(&self) -> Option<Box<dyn Editor>> {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use nih_plug::prelude::*;
|
use nih_plug::prelude::*;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::pin::Pin;
|
use std::sync::Arc;
|
||||||
|
|
||||||
struct Gain {
|
struct Gain {
|
||||||
params: Pin<Box<GainParams>>,
|
params: Arc<GainParams>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The [`Params`] derive macro gathers all of the information needed for the wrapepr to know about
|
/// The [`Params`] derive macro gathers all of the information needed for the wrapepr to know about
|
||||||
|
@ -48,7 +48,7 @@ struct SubSubParams {
|
||||||
impl Default for Gain {
|
impl Default for Gain {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
params: Box::pin(GainParams::default()),
|
params: Arc::new(GainParams::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,8 +111,8 @@ impl Plugin for Gain {
|
||||||
// splits.
|
// splits.
|
||||||
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
||||||
|
|
||||||
fn params(&self) -> Pin<&dyn Params> {
|
fn params(&self) -> Arc<dyn Params> {
|
||||||
self.params.as_ref()
|
self.params.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts_bus_config(&self, config: &BusConfig) -> bool {
|
fn accepts_bus_config(&self, config: &BusConfig) -> bool {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use nih_plug::prelude::*;
|
use nih_plug::prelude::*;
|
||||||
use std::f32::consts;
|
use std::f32::consts;
|
||||||
use std::pin::Pin;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// A test tone generator that can either generate a sine wave based on the plugin's parameters or
|
/// A test tone generator that can either generate a sine wave based on the plugin's parameters or
|
||||||
/// based on the current MIDI input.
|
/// based on the current MIDI input.
|
||||||
struct Sine {
|
struct Sine {
|
||||||
params: Pin<Box<SineParams>>,
|
params: Arc<SineParams>,
|
||||||
sample_rate: f32,
|
sample_rate: f32,
|
||||||
|
|
||||||
/// The current phase of the sine wave, always kept between in `[0, 1]`.
|
/// The current phase of the sine wave, always kept between in `[0, 1]`.
|
||||||
|
@ -35,7 +35,7 @@ struct SineParams {
|
||||||
impl Default for Sine {
|
impl Default for Sine {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
params: Box::pin(SineParams::default()),
|
params: Arc::new(SineParams::default()),
|
||||||
sample_rate: 1.0,
|
sample_rate: 1.0,
|
||||||
|
|
||||||
phase: 0.0,
|
phase: 0.0,
|
||||||
|
@ -106,8 +106,8 @@ impl Plugin for Sine {
|
||||||
const ACCEPTS_MIDI: bool = true;
|
const ACCEPTS_MIDI: bool = true;
|
||||||
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
||||||
|
|
||||||
fn params(&self) -> Pin<&dyn Params> {
|
fn params(&self) -> Arc<dyn Params> {
|
||||||
self.params.as_ref()
|
self.params.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts_bus_config(&self, config: &BusConfig) -> bool {
|
fn accepts_bus_config(&self, config: &BusConfig) -> bool {
|
||||||
|
|
|
@ -2,14 +2,13 @@ use nih_plug::prelude::*;
|
||||||
use realfft::num_complex::Complex32;
|
use realfft::num_complex::Complex32;
|
||||||
use realfft::{ComplexToReal, RealFftPlanner, RealToComplex};
|
use realfft::{ComplexToReal, RealFftPlanner, RealToComplex};
|
||||||
use std::f32;
|
use std::f32;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
const WINDOW_SIZE: usize = 2048;
|
const WINDOW_SIZE: usize = 2048;
|
||||||
const OVERLAP_TIMES: usize = 4;
|
const OVERLAP_TIMES: usize = 4;
|
||||||
|
|
||||||
struct Stft {
|
struct Stft {
|
||||||
params: Pin<Box<StftParams>>,
|
params: Arc<StftParams>,
|
||||||
|
|
||||||
/// An adapter that performs most of the overlap-add algorithm for us.
|
/// An adapter that performs most of the overlap-add algorithm for us.
|
||||||
stft: util::StftHelper,
|
stft: util::StftHelper,
|
||||||
|
@ -56,7 +55,7 @@ impl Default for Stft {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
params: Box::pin(StftParams::default()),
|
params: Arc::new(StftParams::default()),
|
||||||
|
|
||||||
stft: util::StftHelper::new(2, WINDOW_SIZE),
|
stft: util::StftHelper::new(2, WINDOW_SIZE),
|
||||||
window_function: util::window::hann(WINDOW_SIZE),
|
window_function: util::window::hann(WINDOW_SIZE),
|
||||||
|
@ -91,8 +90,8 @@ impl Plugin for Stft {
|
||||||
const ACCEPTS_MIDI: bool = false;
|
const ACCEPTS_MIDI: bool = false;
|
||||||
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
||||||
|
|
||||||
fn params(&self) -> Pin<&dyn Params> {
|
fn params(&self) -> Arc<dyn Params> {
|
||||||
self.params.as_ref()
|
self.params.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts_bus_config(&self, config: &BusConfig) -> bool {
|
fn accepts_bus_config(&self, config: &BusConfig) -> bool {
|
||||||
|
|
|
@ -18,7 +18,6 @@ use nih_plug::prelude::*;
|
||||||
use realfft::num_complex::Complex32;
|
use realfft::num_complex::Complex32;
|
||||||
use realfft::{ComplexToReal, RealFftPlanner, RealToComplex};
|
use realfft::{ComplexToReal, RealFftPlanner, RealToComplex};
|
||||||
use std::f32;
|
use std::f32;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
const MIN_WINDOW_ORDER: usize = 6;
|
const MIN_WINDOW_ORDER: usize = 6;
|
||||||
|
@ -41,7 +40,7 @@ const MAX_OVERLAP_ORDER: usize = 5;
|
||||||
const MAX_OVERLAP_TIMES: usize = 1 << MAX_OVERLAP_ORDER; // 32
|
const MAX_OVERLAP_TIMES: usize = 1 << MAX_OVERLAP_ORDER; // 32
|
||||||
|
|
||||||
struct PubertySimulator {
|
struct PubertySimulator {
|
||||||
params: Pin<Box<PubertySimulatorParams>>,
|
params: Arc<PubertySimulatorParams>,
|
||||||
|
|
||||||
/// An adapter that performs most of the overlap-add algorithm for us.
|
/// An adapter that performs most of the overlap-add algorithm for us.
|
||||||
stft: util::StftHelper,
|
stft: util::StftHelper,
|
||||||
|
@ -82,7 +81,7 @@ struct PubertySimulatorParams {
|
||||||
impl Default for PubertySimulator {
|
impl Default for PubertySimulator {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
params: Box::pin(PubertySimulatorParams::default()),
|
params: Arc::new(PubertySimulatorParams::default()),
|
||||||
|
|
||||||
stft: util::StftHelper::new(2, MAX_WINDOW_SIZE),
|
stft: util::StftHelper::new(2, MAX_WINDOW_SIZE),
|
||||||
window_function: Vec::with_capacity(MAX_WINDOW_SIZE),
|
window_function: Vec::with_capacity(MAX_WINDOW_SIZE),
|
||||||
|
@ -150,8 +149,8 @@ impl Plugin for PubertySimulator {
|
||||||
const DEFAULT_NUM_INPUTS: u32 = 2;
|
const DEFAULT_NUM_INPUTS: u32 = 2;
|
||||||
const DEFAULT_NUM_OUTPUTS: u32 = 2;
|
const DEFAULT_NUM_OUTPUTS: u32 = 2;
|
||||||
|
|
||||||
fn params(&self) -> Pin<&dyn Params> {
|
fn params(&self) -> Arc<dyn Params> {
|
||||||
self.params.as_ref()
|
self.params.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts_bus_config(&self, config: &BusConfig) -> bool {
|
fn accepts_bus_config(&self, config: &BusConfig) -> bool {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! Implementation details for the parameter management.
|
//! Implementation details for the parameter management.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::pin::Pin;
|
|
||||||
|
|
||||||
use super::{Param, ParamFlags};
|
use super::{Param, ParamFlags};
|
||||||
|
|
||||||
|
@ -37,9 +36,9 @@ pub use serde_json::to_string as serialize_field;
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This implementation is safe when using from the wrapper because the plugin object needs to be
|
/// This implementation is safe when using from the wrapper because the plugin's returned `Params`
|
||||||
/// pinned, and it can never outlive the wrapper.
|
/// object lives in an `Arc`, and the wrapper also holds a reference to this `Arc`.
|
||||||
pub unsafe trait Params {
|
pub unsafe trait Params: 'static + Send + Sync {
|
||||||
/// Create a mapping from unique parameter IDs to parameters along with the name of the
|
/// Create a mapping from unique parameter IDs to parameters along with the name of the
|
||||||
/// group/unit/module they are in. The order of the `Vec` determines the display order in the
|
/// group/unit/module they are in. The order of the `Vec` determines the display order in the
|
||||||
/// (host's) generic UI. The group name is either an empty string for top level parameters, or a
|
/// (host's) generic UI. The group name is either an empty string for top level parameters, or a
|
||||||
|
@ -48,13 +47,13 @@ pub unsafe trait Params {
|
||||||
/// for every parameter field marked with `#[id = "stable"]`, and it also inlines all fields
|
/// for every parameter field marked with `#[id = "stable"]`, and it also inlines all fields
|
||||||
/// from child `Params` structs marked with `#[nested = "Group Name"]`, prefixing that group
|
/// from child `Params` structs marked with `#[nested = "Group Name"]`, prefixing that group
|
||||||
/// name before the parameter's originanl group name. Dereferencing the pointers stored in the
|
/// name before the parameter's originanl group name. Dereferencing the pointers stored in the
|
||||||
/// values is only valid as long as this pinned object is valid.
|
/// values is only valid as long as this object is valid.
|
||||||
///
|
///
|
||||||
/// # Note
|
/// # Note
|
||||||
///
|
///
|
||||||
/// This uses `String` even though for the `Params` derive macro `&'static str` would have been
|
/// This uses `String` even though for the `Params` derive macro `&'static str` would have been
|
||||||
/// fine to be able to support custom reusable Params implemnetations.
|
/// fine to be able to support custom reusable Params implemnetations.
|
||||||
fn param_map(self: Pin<&Self>) -> Vec<(String, ParamPtr, String)>;
|
fn param_map(&self) -> Vec<(String, ParamPtr, String)>;
|
||||||
|
|
||||||
/// Serialize all fields marked with `#[persist = "stable_name"]` into a hash map containing
|
/// Serialize all fields marked with `#[persist = "stable_name"]` into a hash map containing
|
||||||
/// JSON-representations of those fields so they can be written to the plugin's state and
|
/// JSON-representations of those fields so they can be written to the plugin's state and
|
||||||
|
@ -84,8 +83,9 @@ pub enum ParamPtr {
|
||||||
EnumParam(*mut super::enums::EnumParamInner),
|
EnumParam(*mut super::enums::EnumParamInner),
|
||||||
}
|
}
|
||||||
|
|
||||||
// These pointers only point to fields on pinned structs, and the caller always needs to make sure
|
// These pointers only point to fields on structs kept in an `Arc<dyn Params>`, and the caller
|
||||||
// that dereferencing them is safe
|
// always needs to make sure that dereferencing them is safe. To do that the plugin wrappers will
|
||||||
|
// keep references to that `Arc` around for the entire lifetime of the plugin.
|
||||||
unsafe impl Send for ParamPtr {}
|
unsafe impl Send for ParamPtr {}
|
||||||
unsafe impl Sync for ParamPtr {}
|
unsafe impl Sync for ParamPtr {}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
|
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::buffer::Buffer;
|
use crate::buffer::Buffer;
|
||||||
|
@ -55,7 +54,7 @@ pub trait Plugin: Default + Send + Sync + 'static {
|
||||||
/// The plugin's parameters. The host will update the parameter values before calling
|
/// The plugin's parameters. The host will update the parameter values before calling
|
||||||
/// `process()`. These parameters are identified by strings that should never change when the
|
/// `process()`. These parameters are identified by strings that should never change when the
|
||||||
/// plugin receives an update.
|
/// plugin receives an update.
|
||||||
fn params(&self) -> Pin<&dyn Params>;
|
fn params(&self) -> Arc<dyn Params>;
|
||||||
|
|
||||||
/// The plugin's editor, if it has one. The actual editor instance is created in
|
/// The plugin's editor, if it has one. The actual editor instance is created in
|
||||||
/// [`Editor::spawn()`]. A plugin editor likely wants to interact with the plugin's parameters
|
/// [`Editor::spawn()`]. A plugin editor likely wants to interact with the plugin's parameters
|
||||||
|
|
|
@ -67,7 +67,7 @@ use super::util::ClapPtr;
|
||||||
use crate::buffer::Buffer;
|
use crate::buffer::Buffer;
|
||||||
use crate::context::Transport;
|
use crate::context::Transport;
|
||||||
use crate::event_loop::{EventLoop, MainThreadExecutor, TASK_QUEUE_CAPACITY};
|
use crate::event_loop::{EventLoop, MainThreadExecutor, TASK_QUEUE_CAPACITY};
|
||||||
use crate::param::internals::ParamPtr;
|
use crate::param::internals::{ParamPtr, Params};
|
||||||
use crate::param::ParamFlags;
|
use crate::param::ParamFlags;
|
||||||
use crate::plugin::{
|
use crate::plugin::{
|
||||||
BufferConfig, BusConfig, ClapPlugin, Editor, NoteEvent, ParentWindowHandle, ProcessStatus,
|
BufferConfig, BusConfig, ClapPlugin, Editor, NoteEvent, ParentWindowHandle, ProcessStatus,
|
||||||
|
@ -90,6 +90,10 @@ pub struct Wrapper<P: ClapPlugin> {
|
||||||
|
|
||||||
/// The wrapped plugin instance.
|
/// The wrapped plugin instance.
|
||||||
plugin: RwLock<P>,
|
plugin: RwLock<P>,
|
||||||
|
/// The plugin's parameters. These are fetched once during initialization. That way the
|
||||||
|
/// `ParamPtr`s are guaranteed to live at least as long as this object and we can interact with
|
||||||
|
/// the `Params` object without having to acquire a lock on `plugin`.
|
||||||
|
params: Arc<dyn Params>,
|
||||||
/// The plugin's editor, if it has one. This object does not do anything on its own, but we need
|
/// The plugin's editor, if it has one. This object does not do anything on its own, but we need
|
||||||
/// to instantiate this in advance so we don't need to lock the entire [`Plugin`] object when
|
/// to instantiate this in advance so we don't need to lock the entire [`Plugin`] object when
|
||||||
/// creating an editor.
|
/// creating an editor.
|
||||||
|
@ -162,8 +166,8 @@ pub struct Wrapper<P: ClapPlugin> {
|
||||||
/// The keys from `param_map` in a stable order.
|
/// The keys from `param_map` in a stable order.
|
||||||
param_hashes: Vec<u32>,
|
param_hashes: Vec<u32>,
|
||||||
/// A mapping from parameter ID hashes (obtained from the string parameter IDs) to pointers to
|
/// A mapping from parameter ID hashes (obtained from the string parameter IDs) to pointers to
|
||||||
/// parameters belonging to the plugin. As long as `plugin` does not get recreated, these
|
/// parameters belonging to the plugin. These addresses will remain stable as long as the
|
||||||
/// addresses will remain stable, as they are obtained from a pinned object.
|
/// `params` object does not get deallocated.
|
||||||
param_by_hash: HashMap<u32, ParamPtr>,
|
param_by_hash: HashMap<u32, ParamPtr>,
|
||||||
/// The group name of a parameter, indexed by the parameter's hash. Nested groups are delimited
|
/// The group name of a parameter, indexed by the parameter's hash. Nested groups are delimited
|
||||||
/// by slashes, and they're only used to allow the DAW to display parameters in a tree
|
/// by slashes, and they're only used to allow the DAW to display parameters in a tree
|
||||||
|
@ -318,9 +322,8 @@ impl<P: ClapPlugin> Wrapper<P> {
|
||||||
// `wrapper.plugin` is alive. The plugin API identifiers these parameters by hashes, which
|
// `wrapper.plugin` is alive. The plugin API identifiers these parameters by hashes, which
|
||||||
// we'll calculate from the string ID specified by the plugin. These parameters should also
|
// we'll calculate from the string ID specified by the plugin. These parameters should also
|
||||||
// remain in the same order as the one returned by the plugin.
|
// remain in the same order as the one returned by the plugin.
|
||||||
let param_id_hashes_ptrs_groups: Vec<_> = plugin
|
let params = plugin.read().params();
|
||||||
.read()
|
let param_id_hashes_ptrs_groups: Vec<_> = params
|
||||||
.params()
|
|
||||||
.param_map()
|
.param_map()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(id, ptr, group)| {
|
.map(|(id, ptr, group)| {
|
||||||
|
@ -329,7 +332,7 @@ impl<P: ClapPlugin> Wrapper<P> {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
let param_map = plugin.read().params().param_map();
|
let param_map = params.param_map();
|
||||||
let param_ids: HashSet<_> = param_id_hashes_ptrs_groups
|
let param_ids: HashSet<_> = param_id_hashes_ptrs_groups
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(id, _, _, _)| id.clone())
|
.map(|(id, _, _, _)| id.clone())
|
||||||
|
@ -430,6 +433,7 @@ impl<P: ClapPlugin> Wrapper<P> {
|
||||||
this: AtomicRefCell::new(Weak::new()),
|
this: AtomicRefCell::new(Weak::new()),
|
||||||
|
|
||||||
plugin,
|
plugin,
|
||||||
|
params,
|
||||||
editor,
|
editor,
|
||||||
editor_handle: RwLock::new(None),
|
editor_handle: RwLock::new(None),
|
||||||
editor_scaling_factor: AtomicF32::new(1.0),
|
editor_scaling_factor: AtomicF32::new(1.0),
|
||||||
|
@ -1916,7 +1920,7 @@ impl<P: ClapPlugin> Wrapper<P> {
|
||||||
let wrapper = &*(plugin as *const Self);
|
let wrapper = &*(plugin as *const Self);
|
||||||
|
|
||||||
let serialized = state::serialize(
|
let serialized = state::serialize(
|
||||||
wrapper.plugin.read().params(),
|
wrapper.params.clone(),
|
||||||
&wrapper.param_by_hash,
|
&wrapper.param_by_hash,
|
||||||
&wrapper.param_id_to_hash,
|
&wrapper.param_id_to_hash,
|
||||||
);
|
);
|
||||||
|
@ -1976,7 +1980,7 @@ impl<P: ClapPlugin> Wrapper<P> {
|
||||||
|
|
||||||
let success = state::deserialize(
|
let success = state::deserialize(
|
||||||
&read_buffer,
|
&read_buffer,
|
||||||
wrapper.plugin.read().params(),
|
wrapper.params.clone(),
|
||||||
&wrapper.param_by_hash,
|
&wrapper.param_by_hash,
|
||||||
&wrapper.param_id_to_hash,
|
&wrapper.param_id_to_hash,
|
||||||
wrapper.current_buffer_config.load().as_ref(),
|
wrapper.current_buffer_config.load().as_ref(),
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::pin::Pin;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::param::internals::{ParamPtr, Params};
|
use crate::param::internals::{ParamPtr, Params};
|
||||||
use crate::param::Param;
|
use crate::param::Param;
|
||||||
|
@ -41,7 +41,7 @@ pub struct State {
|
||||||
/// Serialize a plugin's state to a vector containing JSON data. This can (and should) be shared
|
/// Serialize a plugin's state to a vector containing JSON data. This can (and should) be shared
|
||||||
/// across plugin formats.
|
/// across plugin formats.
|
||||||
pub(crate) unsafe fn serialize(
|
pub(crate) unsafe fn serialize(
|
||||||
plugin_params: Pin<&dyn Params>,
|
plugin_params: Arc<dyn Params>,
|
||||||
param_by_hash: &HashMap<u32, ParamPtr>,
|
param_by_hash: &HashMap<u32, ParamPtr>,
|
||||||
param_id_to_hash: &HashMap<String, u32>,
|
param_id_to_hash: &HashMap<String, u32>,
|
||||||
) -> serde_json::Result<Vec<u8>> {
|
) -> serde_json::Result<Vec<u8>> {
|
||||||
|
@ -89,7 +89,7 @@ pub(crate) unsafe fn serialize(
|
||||||
/// parameter values. The smoothers have already been reset by this function.
|
/// parameter values. The smoothers have already been reset by this function.
|
||||||
pub(crate) unsafe fn deserialize(
|
pub(crate) unsafe fn deserialize(
|
||||||
state: &[u8],
|
state: &[u8],
|
||||||
plugin_params: Pin<&dyn Params>,
|
plugin_params: Arc<dyn Params>,
|
||||||
param_by_hash: &HashMap<u32, ParamPtr>,
|
param_by_hash: &HashMap<u32, ParamPtr>,
|
||||||
param_id_to_hash: &HashMap<String, u32>,
|
param_id_to_hash: &HashMap<String, u32>,
|
||||||
current_buffer_config: Option<&BufferConfig>,
|
current_buffer_config: Option<&BufferConfig>,
|
||||||
|
|
|
@ -16,7 +16,7 @@ use super::view::WrapperView;
|
||||||
use crate::buffer::Buffer;
|
use crate::buffer::Buffer;
|
||||||
use crate::context::Transport;
|
use crate::context::Transport;
|
||||||
use crate::event_loop::{EventLoop, MainThreadExecutor, OsEventLoop};
|
use crate::event_loop::{EventLoop, MainThreadExecutor, OsEventLoop};
|
||||||
use crate::param::internals::ParamPtr;
|
use crate::param::internals::{ParamPtr, Params};
|
||||||
use crate::param::ParamFlags;
|
use crate::param::ParamFlags;
|
||||||
use crate::plugin::{BufferConfig, BusConfig, Editor, NoteEvent, ProcessStatus, Vst3Plugin};
|
use crate::plugin::{BufferConfig, BusConfig, Editor, NoteEvent, ProcessStatus, Vst3Plugin};
|
||||||
use crate::wrapper::util::hash_param_id;
|
use crate::wrapper::util::hash_param_id;
|
||||||
|
@ -27,6 +27,10 @@ use crate::wrapper::util::hash_param_id;
|
||||||
pub(crate) struct WrapperInner<P: Vst3Plugin> {
|
pub(crate) struct WrapperInner<P: Vst3Plugin> {
|
||||||
/// The wrapped plugin instance.
|
/// The wrapped plugin instance.
|
||||||
pub plugin: RwLock<P>,
|
pub plugin: RwLock<P>,
|
||||||
|
/// The plugin's parameters. These are fetched once during initialization. That way the
|
||||||
|
/// `ParamPtr`s are guaranteed to live at least as long as this object and we can interact with
|
||||||
|
/// the `Params` object without having to acquire a lock on `plugin`.
|
||||||
|
pub params: Arc<dyn Params>,
|
||||||
/// The plugin's editor, if it has one. This object does not do anything on its own, but we need
|
/// The plugin's editor, if it has one. This object does not do anything on its own, but we need
|
||||||
/// to instantiate this in advance so we don't need to lock the entire [`Plugin`] object when
|
/// to instantiate this in advance so we don't need to lock the entire [`Plugin`] object when
|
||||||
/// creating an editor.
|
/// creating an editor.
|
||||||
|
@ -80,8 +84,8 @@ pub(crate) struct WrapperInner<P: Vst3Plugin> {
|
||||||
/// The keys from `param_map` in a stable order.
|
/// The keys from `param_map` in a stable order.
|
||||||
pub param_hashes: Vec<u32>,
|
pub param_hashes: Vec<u32>,
|
||||||
/// A mapping from parameter ID hashes (obtained from the string parameter IDs) to pointers to
|
/// A mapping from parameter ID hashes (obtained from the string parameter IDs) to pointers to
|
||||||
/// parameters belonging to the plugin. As long as `plugin` does not get recreated, these
|
/// parameters belonging to the plugin. These addresses will remain stable as long as the
|
||||||
/// addresses will remain stable, as they are obtained from a pinned object.
|
/// `params` object does not get deallocated.
|
||||||
pub param_by_hash: HashMap<u32, ParamPtr>,
|
pub param_by_hash: HashMap<u32, ParamPtr>,
|
||||||
pub param_units: ParamUnits,
|
pub param_units: ParamUnits,
|
||||||
/// Mappings from string parameter indentifiers to parameter hashes. Useful for debug logging
|
/// Mappings from string parameter indentifiers to parameter hashes. Useful for debug logging
|
||||||
|
@ -135,9 +139,8 @@ impl<P: Vst3Plugin> WrapperInner<P> {
|
||||||
// `wrapper.plugin` is alive. The plugin API identifiers these parameters by hashes, which
|
// `wrapper.plugin` is alive. The plugin API identifiers these parameters by hashes, which
|
||||||
// we'll calculate from the string ID specified by the plugin. These parameters should also
|
// we'll calculate from the string ID specified by the plugin. These parameters should also
|
||||||
// remain in the same order as the one returned by the plugin.
|
// remain in the same order as the one returned by the plugin.
|
||||||
let param_id_hashes_ptrs_groups: Vec<_> = plugin
|
let params = plugin.read().params();
|
||||||
.read()
|
let param_id_hashes_ptrs_groups: Vec<_> = params
|
||||||
.params()
|
|
||||||
.param_map()
|
.param_map()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(id, ptr, group)| {
|
.map(|(id, ptr, group)| {
|
||||||
|
@ -146,7 +149,7 @@ impl<P: Vst3Plugin> WrapperInner<P> {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
let param_map = plugin.read().params().param_map();
|
let param_map = params.param_map();
|
||||||
let param_ids: HashSet<_> = param_id_hashes_ptrs_groups
|
let param_ids: HashSet<_> = param_id_hashes_ptrs_groups
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(id, _, _, _)| id.clone())
|
.map(|(id, _, _, _)| id.clone())
|
||||||
|
@ -199,6 +202,7 @@ impl<P: Vst3Plugin> WrapperInner<P> {
|
||||||
|
|
||||||
let wrapper = Self {
|
let wrapper = Self {
|
||||||
plugin,
|
plugin,
|
||||||
|
params,
|
||||||
editor,
|
editor,
|
||||||
|
|
||||||
component_handler: AtomicRefCell::new(None),
|
component_handler: AtomicRefCell::new(None),
|
||||||
|
|
|
@ -222,7 +222,7 @@ impl<P: Vst3Plugin> IComponent for Wrapper<P> {
|
||||||
|
|
||||||
let success = state::deserialize(
|
let success = state::deserialize(
|
||||||
&read_buffer,
|
&read_buffer,
|
||||||
self.inner.plugin.read().params(),
|
self.inner.params.clone(),
|
||||||
&self.inner.param_by_hash,
|
&self.inner.param_by_hash,
|
||||||
&self.inner.param_id_to_hash,
|
&self.inner.param_id_to_hash,
|
||||||
self.inner.current_buffer_config.load().as_ref(),
|
self.inner.current_buffer_config.load().as_ref(),
|
||||||
|
@ -256,7 +256,7 @@ impl<P: Vst3Plugin> IComponent for Wrapper<P> {
|
||||||
let state = state.upgrade().unwrap();
|
let state = state.upgrade().unwrap();
|
||||||
|
|
||||||
let serialized = state::serialize(
|
let serialized = state::serialize(
|
||||||
self.inner.plugin.read().params(),
|
self.inner.params.clone(),
|
||||||
&self.inner.param_by_hash,
|
&self.inner.param_by_hash,
|
||||||
&self.inner.param_id_to_hash,
|
&self.inner.param_id_to_hash,
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue