1
0
Fork 0

Wrap Diopser safe mode boolean in a struct

This struct will also be used to limit the parameter ranges later.
This commit is contained in:
Robbert van der Helm 2022-11-23 01:00:45 +01:00
parent 9a77bd2918
commit 4eb7614ee7
4 changed files with 71 additions and 20 deletions

View file

@ -20,7 +20,6 @@ use nih_plug::prelude::{Editor, Plugin};
use nih_plug_vizia::vizia::prelude::*; use nih_plug_vizia::vizia::prelude::*;
use nih_plug_vizia::widgets::*; use nih_plug_vizia::widgets::*;
use nih_plug_vizia::{assets, create_vizia_editor, ViziaState, ViziaTheming}; use nih_plug_vizia::{assets, create_vizia_editor, ViziaState, ViziaTheming};
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use self::button::SafeModeButton; use self::button::SafeModeButton;
@ -30,8 +29,11 @@ use crate::Diopser;
mod analyzer; mod analyzer;
mod button; mod button;
mod safe_mode;
mod xy_pad; mod xy_pad;
pub use safe_mode::SafeModeClamper;
const EDITOR_WIDTH: u32 = 600; const EDITOR_WIDTH: u32 = 600;
const EDITOR_HEIGHT: u32 = 490; const EDITOR_HEIGHT: u32 = 490;
@ -49,8 +51,7 @@ pub(crate) struct Data {
pub(crate) spectrum: Arc<Mutex<SpectrumOutput>>, pub(crate) spectrum: Arc<Mutex<SpectrumOutput>>,
/// Whether the safe mode button is enabled. The number of filter stages is capped at 40 while /// Whether the safe mode button is enabled. The number of filter stages is capped at 40 while
/// this is active. /// this is active.
/// TODO: Actually hook up safe mode pub(crate) safe_mode_clamper: SafeModeClamper,
pub(crate) safe_mode: Arc<AtomicBool>,
} }
impl Model for Data {} impl Model for Data {}
@ -106,7 +107,7 @@ fn top_bar(cx: &mut Context) {
.with_label("Automation Precision") .with_label("Automation Precision")
.id("automation-precision"); .id("automation-precision");
SafeModeButton::new(cx, Data::safe_mode, "Safe mode").left(Pixels(10.0)); SafeModeButton::new(cx, Data::safe_mode_clamper, "Safe mode").left(Pixels(10.0));
ParamButton::new(cx, Data::params, |params| &params.bypass) ParamButton::new(cx, Data::params, |params| &params.bypass)
.for_bypass() .for_bypass()

View file

@ -15,13 +15,13 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use nih_plug_vizia::vizia::prelude::*; use nih_plug_vizia::vizia::prelude::*;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
/// A custom toggleable button coupled to an `Arc<AtomicBool`. Otherwise this is very similar to the use super::SafeModeClamper;
/// param button.
/// A custom toggleable button that toggles safe mode whenever it is Alt+clicked. Otherwise this is
/// very similar to the param button.
#[derive(Lens)] #[derive(Lens)]
pub struct SafeModeButton<L: Lens<Target = Arc<AtomicBool>>> { pub struct SafeModeButton<L: Lens<Target = SafeModeClamper>> {
lens: L, lens: L,
/// The number of (fractional) scrolled lines that have not yet been turned into parameter /// The number of (fractional) scrolled lines that have not yet been turned into parameter
@ -29,8 +29,8 @@ pub struct SafeModeButton<L: Lens<Target = Arc<AtomicBool>>> {
scrolled_lines: f32, scrolled_lines: f32,
} }
impl<L: Lens<Target = Arc<AtomicBool>>> SafeModeButton<L> { impl<L: Lens<Target = SafeModeClamper>> SafeModeButton<L> {
/// Creates a new button bound to the `Arc<AtomicBool>`. /// Creates a new button bound to the [`SafeModeClamper`].
pub fn new<T>(cx: &mut Context, lens: L, label: impl Res<T>) -> Handle<Self> pub fn new<T>(cx: &mut Context, lens: L, label: impl Res<T>) -> Handle<Self>
where where
T: ToString, T: ToString,
@ -42,13 +42,13 @@ impl<L: Lens<Target = Arc<AtomicBool>>> SafeModeButton<L> {
.build(cx, move |cx| { .build(cx, move |cx| {
Label::new(cx, label); Label::new(cx, label);
}) })
.checked(lens.map(|v| v.load(Ordering::Relaxed))) .checked(lens.map(|v| v.status()))
// We'll pretend this is a param-button, so this class is used for assigning a unique color // We'll pretend this is a param-button, so this class is used for assigning a unique color
.class("safe-mode") .class("safe-mode")
} }
} }
impl<L: Lens<Target = Arc<AtomicBool>>> View for SafeModeButton<L> { impl<L: Lens<Target = SafeModeClamper>> View for SafeModeButton<L> {
fn element(&self) -> Option<&'static str> { fn element(&self) -> Option<&'static str> {
// Reuse the styling from param-button // Reuse the styling from param-button
Some("param-button") Some("param-button")
@ -60,9 +60,10 @@ impl<L: Lens<Target = Arc<AtomicBool>>> View for SafeModeButton<L> {
WindowEvent::MouseDown(MouseButton::Left) WindowEvent::MouseDown(MouseButton::Left)
| WindowEvent::MouseDoubleClick(MouseButton::Left) | WindowEvent::MouseDoubleClick(MouseButton::Left)
| WindowEvent::MouseTripleClick(MouseButton::Left) => { | WindowEvent::MouseTripleClick(MouseButton::Left) => {
// We can just unconditionally toggle the boolean here // We can just unconditionally toggle the boolean here. When safe mode is enabled
let atomic = self.lens.get(cx); // this immediately clamps the affected parameters to their new range.
atomic.fetch_xor(true, Ordering::AcqRel); let safe_mode_clamper = self.lens.get(cx);
safe_mode_clamper.toggle(cx);
meta.consume(); meta.consume();
} }
@ -70,13 +71,13 @@ impl<L: Lens<Target = Arc<AtomicBool>>> View for SafeModeButton<L> {
self.scrolled_lines += scroll_y; self.scrolled_lines += scroll_y;
if self.scrolled_lines.abs() >= 1.0 { if self.scrolled_lines.abs() >= 1.0 {
let atomic = self.lens.get(cx); let safe_mode_clamper = self.lens.get(cx);
if self.scrolled_lines >= 1.0 { if self.scrolled_lines >= 1.0 {
atomic.store(true, Ordering::SeqCst); safe_mode_clamper.enable(cx);
self.scrolled_lines -= 1.0; self.scrolled_lines -= 1.0;
} else { } else {
atomic.store(false, Ordering::SeqCst); safe_mode_clamper.disable(cx);
self.scrolled_lines += 1.0; self.scrolled_lines += 1.0;
} }
} }

View file

@ -0,0 +1,48 @@
//! Utilities for Diopser's safe-mode mechanism.
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use nih_plug_vizia::vizia::prelude::EventContext;
use crate::params::DiopserParams;
/// Restricts the ranges of several parameters when enabled. This makes it more difficult to
/// generate load resonances with Diopser's default settings.
#[derive(Debug, Clone)]
pub struct SafeModeClamper {
/// Whether the safe mode toggle has been enabled.
enabled: Arc<AtomicBool>,
}
impl SafeModeClamper {
pub fn new(params: Arc<DiopserParams>) -> Self {
Self {
enabled: params.safe_mode.clone(),
}
}
/// Return the current status of the safe mode swtich.
pub fn status(&self) -> bool {
self.enabled.load(Ordering::Relaxed)
}
/// Enable or disable safe mode. Enabling safe mode immediately clamps the parameters to their
/// new restricted ranges.
pub fn toggle(&self, cx: &mut EventContext) {
// TODO: Restrict the parameter ranges when the button is enabled
self.enabled.fetch_xor(true, Ordering::Relaxed);
}
/// Enable safe mode. Enabling safe mode immediately clamps the parameters to their new
/// restricted ranges.
pub fn enable(&self, cx: &mut EventContext) {
// TODO: Restrict the parameter ranges when the button is enabled
self.enabled.store(true, Ordering::Relaxed);
}
/// Disable safe mode.
pub fn disable(&self, cx: &mut EventContext) {
self.enabled.store(false, Ordering::Relaxed);
}
}

View file

@ -20,6 +20,7 @@
compile_error!("Compiling without SIMD support is currently not supported"); compile_error!("Compiling without SIMD support is currently not supported");
use atomic_float::AtomicF32; use atomic_float::AtomicF32;
use editor::SafeModeClamper;
use nih_plug::prelude::*; use nih_plug::prelude::*;
use std::simd::f32x2; use std::simd::f32x2;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
@ -130,7 +131,7 @@ impl Plugin for Diopser {
sample_rate: self.sample_rate.clone(), sample_rate: self.sample_rate.clone(),
spectrum: self.spectrum_output.clone(), spectrum: self.spectrum_output.clone(),
safe_mode: self.params.safe_mode.clone(), safe_mode_clamper: SafeModeClamper::new(self.params.clone()),
}, },
self.params.editor_state.clone(), self.params.editor_state.clone(),
) )