summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio.rs45
-rw-r--r--src/gui.rs40
-rw-r--r--src/lib.rs23
-rw-r--r--src/params.rs298
-rw-r--r--src/window_size.rs2
-rw-r--r--src/window_type.rs26
6 files changed, 175 insertions, 259 deletions
diff --git a/src/audio.rs b/src/audio.rs
index 64338a1..6ad1a86 100644
--- a/src/audio.rs
+++ b/src/audio.rs
@@ -1,8 +1,7 @@
-//! Contains all types and implementations related to audio processing and the audio thread.
-
use crate::{
- RetainPluginMainThread, RetainPluginShared, params::RetainParamsLocal,
- retain::retain_top_n_magnitudes, windowed_fft::WindowedRealFft,
+ RetainPluginMainThread, RetainPluginShared, params::RetainParams,
+ retain::retain_top_n_magnitudes, window_size::WindowSize, window_type::WindowType,
+ windowed_fft::WindowedRealFft,
};
use clack_extensions::{
audio_ports::{
@@ -12,6 +11,7 @@ use clack_extensions::{
params::PluginAudioProcessorParams,
};
use clack_plugin::prelude::*;
+use std::sync::Arc;
/// Our plugin's audio processor. It lives in the audio thread.
///
@@ -19,7 +19,7 @@ use clack_plugin::prelude::*;
/// buffer.
pub struct RetainPluginAudioProcessor<'a> {
/// The local state of the parameters
- params: RetainParamsLocal,
+ params: Arc<RetainParams>,
/// A reference to the plugin's shared data.
shared: &'a RetainPluginShared<'a>,
/// Our handle to the host
@@ -28,6 +28,10 @@ pub struct RetainPluginAudioProcessor<'a> {
fft_left: WindowedRealFft,
/// Fft for the right channel
fft_right: WindowedRealFft,
+ /// Previous window type
+ prev_window_type: Option<WindowType>,
+ /// Previous window size
+ prev_window_size: Option<WindowSize>,
}
impl<'a> PluginAudioProcessor<'a, RetainPluginShared<'a>, RetainPluginMainThread<'a>>
@@ -39,7 +43,7 @@ impl<'a> PluginAudioProcessor<'a, RetainPluginShared<'a>, RetainPluginMainThread
shared: &'a RetainPluginShared<'a>,
_audio_config: PluginAudioConfiguration,
) -> Result<Self, PluginError> {
- let params = RetainParamsLocal::new(&shared.params);
+ let params = Arc::clone(&shared.params);
let fft_left = WindowedRealFft::new(params.get_window_size().into());
let fft_right = WindowedRealFft::new(params.get_window_size().into());
@@ -51,6 +55,8 @@ impl<'a> PluginAudioProcessor<'a, RetainPluginShared<'a>, RetainPluginMainThread
host,
fft_left,
fft_right,
+ prev_window_size: None,
+ prev_window_type: None,
})
}
@@ -87,18 +93,12 @@ impl<'a> PluginAudioProcessor<'a, RetainPluginShared<'a>, RetainPluginMainThread
}
}
- let prev_window_size = self.params.get_window_size();
- let prev_window_type = self.params.get_window_type().as_byte();
-
- // Receive any param updates from the main thread and/or the GUI.
- self.params.fetch_updates(&self.shared.params);
-
// update window size and latency if it has changed
// updates fft window sizes only if necessary
let window_size = self.params.get_window_size();
- if prev_window_size != window_size {
- self.fft_left.window_size(window_size.into());
- self.fft_right.window_size(window_size.into());
+ if self.prev_window_size != Some(window_size.clone()) {
+ self.fft_left.window_size(window_size.clone());
+ self.fft_right.window_size(window_size.clone());
if let Some(latency) = self.shared.host.get_extension::<HostLatency>() {
// should be safe
@@ -111,9 +111,9 @@ impl<'a> PluginAudioProcessor<'a, RetainPluginShared<'a>, RetainPluginMainThread
// update change in window type if needed
let window_type = self.params.get_window_type();
- if prev_window_type != window_type.as_byte() {
- self.fft_left.window_function(window_type);
- self.fft_right.window_function(window_type);
+ if self.prev_window_type != Some(window_type.clone()) {
+ self.fft_left.window_function(&window_type);
+ self.fft_right.window_function(&window_type);
}
// Now let's process the audio, while splitting the processing in batches between each
@@ -158,11 +158,12 @@ impl<'a> PluginAudioProcessor<'a, RetainPluginShared<'a>, RetainPluginMainThread
}
}
+ self.prev_window_size = Some(window_size);
+ self.prev_window_type = Some(window_type);
+
// Publish any parameter changes we may have received back to the GUI.
- if self.params.push_updates(&self.shared.params) {
- // Request the on-main-thread callback, which we use to refresh the UI if it is open
- self.host.request_callback();
- }
+ // Request the on-main-thread callback, which we use to refresh the UI if it is open
+ self.host.request_callback();
Ok(ProcessStatus::ContinueIfNotQuiet)
}
diff --git a/src/gui.rs b/src/gui.rs
index 1662b79..5780f50 100644
--- a/src/gui.rs
+++ b/src/gui.rs
@@ -1,9 +1,7 @@
//! Contains all types and implementations related to the plugin's GUI
use crate::{
- RetainPluginMainThread, RetainPluginShared,
- params::{RetainParamsLocal, RetainParamsShared},
- window_size::WindowSize,
+ RetainPluginMainThread, RetainPluginShared, params::RetainParams, window_size::WindowSize,
window_type::WindowType,
};
use baseview::{Size, WindowHandle, WindowOpenOptions, WindowScalePolicy, gl::GlConfig};
@@ -18,17 +16,14 @@ use std::sync::Arc;
/// The EGUI application state
struct AppState {
/// A handle to the shared params state
- shared_params: Arc<RetainParamsShared>,
- /// The local state of the parameters
- local_params: RetainParamsLocal,
+ params: Arc<RetainParams>,
}
impl AppState {
/// Initializes a new [`AppState`] from the given shared params state handle
- pub fn new(shared_params: &Arc<RetainParamsShared>) -> Self {
+ pub fn new(params: &Arc<RetainParams>) -> Self {
Self {
- local_params: RetainParamsLocal::new(shared_params),
- shared_params: Arc::clone(shared_params),
+ params: Arc::clone(params),
}
}
}
@@ -62,8 +57,6 @@ impl RetainPluginGui {
tx.send(egui_ctx.clone()).unwrap();
},
|egui_ctx: &Context, _queue: &mut Queue, state: &mut AppState| {
- state.local_params.fetch_updates(&state.shared_params);
-
egui::CentralPanel::default().show(egui_ctx, |ui| {
ui.with_layout(Layout::top_down(Align::Center), |ui| {
ui.heading("Retain");
@@ -71,8 +64,8 @@ impl RetainPluginGui {
ui.horizontal(|ui| {
ui.with_layout(Layout::top_down(Align::LEFT), |ui| {
- let mut order = state.local_params.get_order();
- let window_size = state.local_params.get_window_size();
+ let mut order = state.params.get_order();
+ let window_size = state.params.get_window_size().inner();
let slider = ui.add(
Slider::new(&mut order, 0..=window_size)
@@ -81,12 +74,10 @@ impl RetainPluginGui {
);
if slider.changed() {
- state.local_params.set_order(order);
- state.local_params.push_updates(&state.shared_params);
+ state.params.set_order(order);
}
- let mut window_size =
- WindowSize::from(state.local_params.get_window_size());
+ let mut window_size = state.params.get_window_size();
ComboBox::from_label("Window Size")
.selected_text(window_size.as_str())
@@ -99,22 +90,20 @@ impl RetainPluginGui {
.selectable_value(&mut window_size, size, display)
.changed()
{
- state.local_params.set_window_size(inner);
- state.local_params.push_updates(&state.shared_params);
+ state.params.set_window_size(inner.into());
}
}
});
});
ui.with_layout(Layout::top_down(Align::RIGHT), |ui| {
- let mut complement = state.local_params.get_complement();
+ let mut complement = state.params.get_complement();
if ui.checkbox(&mut complement, "Complement").changed() {
- state.local_params.set_complement(complement);
- state.local_params.push_updates(&state.shared_params);
+ state.params.set_complement(complement);
}
- let window_type = state.local_params.get_window_type();
+ let window_type = state.params.get_window_type();
let selected = window_type.as_str();
let mut window_type = window_type.as_byte();
@@ -123,7 +112,7 @@ impl RetainPluginGui {
.show_ui(ui, |ui| {
for function in WindowType::iter() {
let display = function.as_str();
- let bits = function.as_byte();
+ let byte = function.as_byte();
if ui
.selectable_value(
@@ -133,8 +122,7 @@ impl RetainPluginGui {
)
.changed()
{
- state.local_params.set_window_type_from_byte(bits);
- state.local_params.push_updates(&state.shared_params);
+ state.params.set_window_type(byte.into());
}
}
});
diff --git a/src/lib.rs b/src/lib.rs
index e26211f..2878e4f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,8 +1,4 @@
-use crate::{
- audio::RetainPluginAudioProcessor,
- gui::RetainPluginGui,
- params::{RetainParamsLocal, RetainParamsShared},
-};
+use crate::{audio::RetainPluginAudioProcessor, gui::RetainPluginGui, params::RetainParams};
use clack_extensions::{
audio_ports::PluginAudioPorts,
gui::PluginGui,
@@ -52,6 +48,8 @@ impl DefaultPluginFactory for RetainPlugin {
fn get_descriptor() -> PluginDescriptor {
PluginDescriptor::new("com.haemolacriaa.retain", "Retain")
.with_description("Retains only the nth largest magnitude frequencies in the signal")
+ .with_version("0.1.0")
+ .with_vendor("haemolacriaa")
.with_features([AUDIO_EFFECT, STEREO])
}
@@ -63,25 +61,21 @@ impl DefaultPluginFactory for RetainPlugin {
_host: HostMainThreadHandle<'a>,
shared: &'a Self::Shared<'a>,
) -> Result<Self::MainThread<'a>, PluginError> {
- Ok(Self::MainThread {
- shared,
- params: RetainParamsLocal::new(&shared.params),
- gui: None,
- })
+ Ok(Self::MainThread { shared, gui: None })
}
}
/// The plugin data that gets shared between the Main Thread and the Audio Thread.
pub struct RetainPluginShared<'a> {
/// The plugin's parameter values.
- params: Arc<RetainParamsShared>,
+ params: Arc<RetainParams>,
host: HostSharedHandle<'a>,
}
impl<'a> RetainPluginShared<'a> {
fn new(host: HostSharedHandle<'a>) -> Self {
RetainPluginShared {
- params: Arc::new(RetainParamsShared::new()),
+ params: Arc::new(RetainParams::new()),
host,
}
}
@@ -91,8 +85,6 @@ impl<'a> PluginShared<'a> for RetainPluginShared<'a> {}
/// The data that belongs to the main thread of our plugin.
pub struct RetainPluginMainThread<'a> {
- /// The local state of the parameters
- params: RetainParamsLocal,
/// A reference to the plugin's shared data.
shared: &'a RetainPluginShared<'a>,
/// The plugin's GUI state and context
@@ -109,8 +101,7 @@ impl<'a> PluginMainThread<'a, RetainPluginShared<'a>> for RetainPluginMainThread
impl PluginLatencyImpl for RetainPluginMainThread<'_> {
fn get(&mut self) -> u32 {
- self.params.fetch_updates(&self.shared.params);
- self.params.get_window_size() as u32
+ self.shared.params.get_window_size().inner() as u32
}
}
diff --git a/src/params.rs b/src/params.rs
index 605e305..4b57dd6 100644
--- a/src/params.rs
+++ b/src/params.rs
@@ -1,5 +1,3 @@
-//! Contains all types and implementations related to parameter management.
-
use crate::{RetainPluginMainThread, window_size::WindowSize, window_type::WindowType};
use clack_extensions::{
params::{
@@ -21,18 +19,14 @@ use std::{
sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering},
};
-/// The default value of the order parameter.
+/// The default values of the parameters.
const DEFAULT_ORDER: usize = 1;
pub const DEFAULT_WINDOW_SIZE: WindowSize = WindowSize::Size4096;
pub const DEFAULT_WINDOW_TYPE: WindowType = WindowType::Hann;
const DEFAULT_COMPLEMENT: bool = false;
-/// A struct that manages the parameters for our plugin.
-///
-/// This struct will be used both by the [`RetainPluginMainThread`] (which the host will use
-/// to query the value of our parameters), and by the [`RetainPluginAudioProcessor`], which will
-/// actually modulate the audio samples.
-pub struct RetainParamsShared {
+/// A struct that manages the parameters for the plugin.
+pub struct RetainParams {
/// The current value of the order parameter.
order: AtomicUsize,
/// Window size of FFT
@@ -43,12 +37,12 @@ pub struct RetainParamsShared {
complement: AtomicBool,
}
-impl RetainParamsShared {
+impl RetainParams {
/// The unique identifier for the order parameter.
pub const PARAM_ORDER_ID: ClapId = ClapId::new(1);
pub const PARAM_WINDOW_SIZE_ID: ClapId = ClapId::new(2);
pub const PARAM_WINDOW_TYPE_ID: ClapId = ClapId::new(3);
- pub const PARAM_COMPLEMENT_ID: ClapId = ClapId::new(3);
+ pub const PARAM_COMPLEMENT_ID: ClapId = ClapId::new(4);
/// Initializes the shared parameter value.
pub fn new() -> Self {
@@ -59,157 +53,85 @@ impl RetainParamsShared {
complement: AtomicBool::new(DEFAULT_COMPLEMENT),
}
}
-}
-
-/// The local-side of parameter state.
-///
-/// This state is local to the current thread (whether it is the main-thread, the UI or the audio
-/// thread), it is not shared directly with the others.
-///
-/// This allows us to both check for differences, and to only update parameter state when we want
-/// to.
-pub struct RetainParamsLocal {
- /// The local value of the order parameter.
- order: usize,
- /// The local value of the window size paramter.
- window_size: usize,
- /// The local value of the type of window function parameter.
- window_type: WindowType,
- /// The local value of the complement parameter.
- complement: bool,
-}
-
-impl RetainParamsLocal {
- /// Initializes a new local state from the current shared state.
- pub fn new(shared: &RetainParamsShared) -> Self {
- Self {
- order: shared.order.load(Ordering::Relaxed),
- window_size: shared.window_size.load(Ordering::Relaxed),
- window_type: WindowType::from_byte(shared.window_type.load(Ordering::Relaxed)),
- complement: shared.complement.load(Ordering::Relaxed),
- }
- }
- /// Returns the current local order value.
+ /// Returns the current order value.
#[inline]
pub fn get_order(&self) -> usize {
- self.order
+ self.order.load(Ordering::SeqCst)
}
- /// Sets the current local order to `value`.
+ /// Sets the current order to `value`.
///
- /// It is clamped to the range `0..=100_000`.
+ /// It is clamped to the range `0..=32_768`.
#[inline]
- pub fn set_order(&mut self, value: usize) {
- self.order = value;
+ pub fn set_order(&self, value: usize) {
+ self.order.store(value.clamp(0, 32768), Ordering::SeqCst);
}
/// Returns the current window size value.
#[inline]
- pub fn get_window_size(&self) -> usize {
- self.window_size
+ pub fn get_window_size(&self) -> WindowSize {
+ self.window_size.load(Ordering::SeqCst).into()
}
/// Sets the current local window size to `value`.
#[inline]
- pub fn set_window_size(&mut self, value: usize) {
- self.window_size = value;
+ pub fn set_window_size(&self, value: WindowSize) {
+ self.window_size.store(value.inner(), Ordering::SeqCst);
}
/// Returns the current local window type.
#[inline]
- pub fn get_window_type(&self) -> &WindowType {
- &self.window_type
+ pub fn get_window_type(&self) -> WindowType {
+ self.window_type.load(Ordering::SeqCst).into()
}
/// Sets the current local window type from `bits`.
#[inline]
- pub fn set_window_type_from_byte(&mut self, bits: u8) {
- self.window_type = WindowType::from_byte(bits);
+ pub fn set_window_type(&self, window_type: WindowType) {
+ self.window_type
+ .store(window_type.as_byte(), Ordering::SeqCst);
}
/// Returns the current local complement.
#[inline]
pub fn get_complement(&self) -> bool {
- self.complement
+ self.complement.load(Ordering::SeqCst)
}
/// Sets the current local complement to `value`.
#[inline]
- pub fn set_complement(&mut self, value: bool) {
- self.complement = value;
- }
-
- /// Fetch updates from the `shared` state.
- ///
- /// If any of the parameters have been updated, this returns `true`.
- #[inline]
- pub fn fetch_updates(&mut self, shared: &RetainParamsShared) -> bool {
- let latest_order = shared.order.load(Ordering::Relaxed);
- let latest_window_size = shared.window_size.load(Ordering::Relaxed);
- let latest_window_type = WindowType::from_byte(shared.window_type.load(Ordering::Relaxed));
- let latest_complement = shared.complement.load(Ordering::Relaxed);
-
- if latest_order != self.order
- || latest_window_size != self.order
- || latest_window_type != self.window_type
- || latest_complement != self.complement
- {
- self.order = latest_order;
- self.window_size = latest_window_size;
- self.window_type = latest_window_type;
- self.complement = latest_complement;
-
- true
- } else {
- false
- }
- }
-
- /// Pushes the local parameter values to the `shared` state.
- ///
- /// If the values were different and an actual update occurred, this returns `true`.
- #[inline]
- pub fn push_updates(&self, shared: &RetainParamsShared) -> bool {
- let previous_order = shared.order.swap(self.order, Ordering::Relaxed);
- let previous_window_size = shared.window_size.swap(self.window_size, Ordering::Relaxed);
- let previous_window_type = shared
- .window_type
- .swap(self.window_type.as_byte(), Ordering::Relaxed);
- let previous_complement = shared.complement.swap(self.complement, Ordering::Relaxed);
-
- previous_order != self.order
- || previous_window_size != self.window_size
- || previous_window_type != self.window_type.as_byte()
- || previous_complement != self.complement
+ pub fn set_complement(&self, value: bool) {
+ self.complement.store(value, Ordering::SeqCst);
}
/// Handles incoming events.
///
/// If the given event is a matching parameter change event, the order parameter will be
/// updated accordingly.
- pub fn handle_event(&mut self, event: &UnknownEvent) {
+ pub fn handle_event(&self, event: &UnknownEvent) {
if let Some(CoreEventSpace::ParamValue(event)) = event.as_core_event() {
- if event.param_id() == RetainParamsShared::PARAM_ORDER_ID {
+ if event.param_id() == RetainParams::PARAM_ORDER_ID {
self.set_order(event.value() as usize);
}
- if event.param_id() == RetainParamsShared::PARAM_WINDOW_SIZE_ID {
- self.set_window_size(event.value() as usize);
+ if event.param_id() == RetainParams::PARAM_WINDOW_SIZE_ID {
+ self.set_window_size((event.value() as usize).into());
}
- if event.param_id() == RetainParamsShared::PARAM_WINDOW_TYPE_ID {
- self.set_window_type_from_byte(event.value() as u8);
+ if event.param_id() == RetainParams::PARAM_WINDOW_TYPE_ID {
+ self.set_window_type((event.value() as u8).into());
}
- if event.param_id() == RetainParamsShared::PARAM_COMPLEMENT_ID {
+ if event.param_id() == RetainParams::PARAM_COMPLEMENT_ID {
self.set_complement(event.value() != 0.0);
}
}
}
}
-/// To save the plugin state (parameter values) using protocol buffers
+/// Wrapper that helps save plugin parameters using protocol buffers
+/// Updating this will change the schema and break old
#[derive(Message)]
struct PluginState {
#[prost(uint64, tag = "1")]
@@ -223,10 +145,10 @@ struct PluginState {
}
impl PluginState {
- fn copied(local_params: &RetainParamsLocal) -> Self {
+ fn copied(local_params: &RetainParams) -> Self {
Self {
order: local_params.get_order() as u64,
- window_size: local_params.get_window_size() as u32,
+ window_size: local_params.get_window_size().inner() as u32,
window_type: local_params.get_window_type().as_byte() as u32,
complement: local_params.get_complement(),
}
@@ -249,14 +171,12 @@ impl PluginState {
}
}
-/// Implementation of the State extension.
+/// To save and load the plugin parameters
impl PluginStateImpl for RetainPluginMainThread<'_> {
fn save(&mut self, output: &mut OutputStream) -> Result<(), PluginError> {
- self.params.fetch_updates(&self.shared.params);
-
let mut data = vec![];
- let state = PluginState::copied(&self.params);
+ let state = PluginState::copied(&self.shared.params);
state.encode(&mut data)?;
@@ -271,13 +191,14 @@ impl PluginStateImpl for RetainPluginMainThread<'_> {
let data = PluginState::decode(&data[..])?;
- self.params.set_order(data.get_order() as usize);
- self.params.set_window_size(data.get_window_size() as usize);
- self.params
- .set_window_type_from_byte(data.get_window_type_bits());
- self.params.set_complement(data.get_complement());
-
- self.params.push_updates(&self.shared.params);
+ self.shared.params.set_order(data.get_order() as usize);
+ self.shared
+ .params
+ .set_window_size((data.get_window_size() as usize).into());
+ self.shared
+ .params
+ .set_window_type(data.get_window_type_bits().into());
+ self.shared.params.set_complement(data.get_complement());
Ok(())
}
@@ -288,92 +209,105 @@ impl PluginMainThreadParams for RetainPluginMainThread<'_> {
4
}
+ /// `param_index`: The index of the parameter to query.
+ /// Must be less than the value returned by `count()`.
fn get_info(&mut self, param_index: u32, info: &mut ParamInfoWriter) {
- if param_index != 0 {
+ if param_index >= 4 {
return;
}
- info.set(&ParamInfo {
- id: RetainParamsShared::PARAM_ORDER_ID,
- flags: ParamInfoFlags::IS_AUTOMATABLE | ParamInfoFlags::IS_STEPPED,
- cookie: Cookie::default(),
- name: b"Order",
- module: b"",
- min_value: 0.0,
- max_value: f64::MAX,
- default_value: DEFAULT_ORDER as f64,
- });
-
- info.set(&ParamInfo {
- id: RetainParamsShared::PARAM_WINDOW_SIZE_ID,
- flags: ParamInfoFlags::IS_READONLY,
- cookie: Cookie::default(),
- name: b"Window Size",
- module: b"",
- min_value: 128.0,
- max_value: usize::MAX as f64,
- default_value: DEFAULT_WINDOW_SIZE.inner() as f64,
- });
-
- info.set(&ParamInfo {
- id: RetainParamsShared::PARAM_WINDOW_TYPE_ID,
- flags: ParamInfoFlags::IS_READONLY,
- cookie: Cookie::default(),
- name: b"Window Function",
- module: b"",
- min_value: 0.0,
- max_value: 4.0,
- default_value: DEFAULT_WINDOW_TYPE.as_byte() as f64,
- });
-
- info.set(&ParamInfo {
- id: RetainParamsShared::PARAM_COMPLEMENT_ID,
- flags: ParamInfoFlags::IS_READONLY,
- cookie: Cookie::default(),
- name: b"Complement",
- module: b"",
- min_value: 0.0,
- max_value: 1.0,
- default_value: DEFAULT_COMPLEMENT as u8 as f64,
- });
+ // cleaner than match is
+ if param_index == 0 {
+ info.set(&ParamInfo {
+ id: RetainParams::PARAM_ORDER_ID,
+ flags: ParamInfoFlags::IS_AUTOMATABLE | ParamInfoFlags::IS_STEPPED,
+ cookie: Cookie::default(),
+ name: b"Order",
+ module: b"",
+ min_value: 0.0,
+ max_value: 32768.0,
+ default_value: DEFAULT_ORDER as f64,
+ });
+ }
+
+ if param_index == 1 {
+ info.set(&ParamInfo {
+ id: RetainParams::PARAM_WINDOW_SIZE_ID,
+ flags: ParamInfoFlags::IS_READONLY,
+ cookie: Cookie::default(),
+ name: b"Window Size",
+ module: b"",
+ min_value: 256.0,
+ max_value: 32768.0,
+ default_value: DEFAULT_WINDOW_SIZE.inner() as f64,
+ });
+ }
+
+ if param_index == 2 {
+ info.set(&ParamInfo {
+ id: RetainParams::PARAM_WINDOW_TYPE_ID,
+ flags: ParamInfoFlags::IS_READONLY,
+ cookie: Cookie::default(),
+ name: b"Window Function",
+ module: b"",
+ min_value: 0.0,
+ max_value: 4.0,
+ default_value: DEFAULT_WINDOW_TYPE.as_byte() as f64,
+ });
+ }
+
+ if param_index == 3 {
+ info.set(&ParamInfo {
+ id: RetainParams::PARAM_COMPLEMENT_ID,
+ flags: ParamInfoFlags::IS_READONLY,
+ cookie: Cookie::default(),
+ name: b"Complement",
+ module: b"",
+ min_value: 0.0,
+ max_value: 1.0,
+ default_value: DEFAULT_COMPLEMENT as u8 as f64,
+ });
+ }
}
fn get_value(&mut self, param_id: ClapId) -> Option<f64> {
match param_id {
- RetainParamsShared::PARAM_ORDER_ID => Some(self.params.get_order() as f64),
- RetainParamsShared::PARAM_WINDOW_SIZE_ID => Some(self.params.get_window_size() as f64),
- RetainParamsShared::PARAM_WINDOW_TYPE_ID => {
- Some(self.params.get_window_type().as_byte() as f64)
+ RetainParams::PARAM_ORDER_ID => Some(self.shared.params.get_order() as f64),
+ RetainParams::PARAM_WINDOW_SIZE_ID => {
+ Some(self.shared.params.get_window_size().inner() as f64)
+ }
+ RetainParams::PARAM_WINDOW_TYPE_ID => {
+ Some(self.shared.params.get_window_type().as_byte() as f64)
}
- RetainParamsShared::PARAM_COMPLEMENT_ID => {
- Some(self.params.get_complement() as u8 as f64)
+ RetainParams::PARAM_COMPLEMENT_ID => {
+ Some(self.shared.params.get_complement() as u8 as f64)
}
_ => None,
}
}
- // TODO: update for order
fn value_to_text(
&mut self,
param_id: ClapId,
value: f64,
writer: &mut ParamDisplayWriter,
) -> std::fmt::Result {
- if param_id == RetainParamsShared::PARAM_ORDER_ID {
- write!(writer, "{0:.2} %", value * 100.0)
+ if param_id == RetainParams::PARAM_ORDER_ID {
+ write!(writer, "{}", value as u64)
} else {
Err(std::fmt::Error)
}
}
- // TODO: update for order
fn text_to_value(&mut self, param_id: ClapId, text: &CStr) -> Option<f64> {
let text = text.to_str().ok()?;
- if param_id == RetainParamsShared::PARAM_ORDER_ID {
- let text = text.strip_suffix('%').unwrap_or(text).trim();
- let percentage: f64 = text.parse().ok()?;
- Some(percentage / 100.0)
+ if param_id == RetainParams::PARAM_ORDER_ID {
+ let max = self.shared.params.get_window_size().inner() as f64;
+
+ let order_value = text.parse::<f64>().ok()?;
+
+ Some(order_value.clamp(0.0, max))
} else {
None
}
@@ -385,7 +319,7 @@ impl PluginMainThreadParams for RetainPluginMainThread<'_> {
_output_parameter_changes: &mut OutputEvents,
) {
for event in input_parameter_changes {
- self.params.handle_event(event);
+ self.shared.params.handle_event(event);
}
}
}
diff --git a/src/window_size.rs b/src/window_size.rs
index 620a307..c84a137 100644
--- a/src/window_size.rs
+++ b/src/window_size.rs
@@ -1,7 +1,7 @@
/// The max value of the custom window size is `u32::MAX`.
/// The min value of the custom window size is `WindowSize::Size256`.
/// This is because it's the maximum latency one can report to a CLAP host.
-#[derive(Debug, PartialEq)]
+#[derive(Debug, Clone, PartialEq)]
pub enum WindowSize {
Size256,
Size512,
diff --git a/src/window_type.rs b/src/window_type.rs
index c181c6d..7fb7d58 100644
--- a/src/window_type.rs
+++ b/src/window_type.rs
@@ -6,7 +6,7 @@ use crate::{
window_size::WindowSize,
};
-#[derive(PartialEq)]
+#[derive(Clone, PartialEq)]
pub enum WindowType {
Rectangular,
Hann,
@@ -47,17 +47,6 @@ impl WindowType {
.into_iter()
}
- pub fn from_byte(bits: u8) -> Self {
- match bits {
- 0 => Self::Rectangular,
- 1 => Self::Hann,
- 2 => Self::Hamming,
- 3 => Self::BlackmanHarris,
- 4 => Self::Sine4,
- _ => panic!("Invalid window type"),
- }
- }
-
pub fn as_byte(&self) -> u8 {
match self {
Self::Rectangular => 0,
@@ -68,3 +57,16 @@ impl WindowType {
}
}
}
+
+impl From<u8> for WindowType {
+ fn from(item: u8) -> Self {
+ match item {
+ 0 => Self::Rectangular,
+ 1 => Self::Hann,
+ 2 => Self::Hamming,
+ 3 => Self::BlackmanHarris,
+ 4 => Self::Sine4,
+ _ => panic!("Invalid window type"),
+ }
+ }
+}