diff --git a/Cargo.lock b/Cargo.lock index 0ca56ed7..af9ba7fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -288,6 +288,7 @@ name = "diopser" version = "0.1.0" dependencies = [ "nih_plug", + "nih_plug_egui", ] [[package]] diff --git a/plugins/diopser/Cargo.toml b/plugins/diopser/Cargo.toml index 57965fc9..bafb8e60 100644 --- a/plugins/diopser/Cargo.toml +++ b/plugins/diopser/Cargo.toml @@ -16,3 +16,4 @@ simd = ["nih_plug/simd"] [dependencies] nih_plug = { path = "../../", features = ["assert_process_allocs"] } +nih_plug_egui = { path = "../../nih_plug_egui" } diff --git a/plugins/diopser/src/editor.rs b/plugins/diopser/src/editor.rs new file mode 100644 index 00000000..db52cd0a --- /dev/null +++ b/plugins/diopser/src/editor.rs @@ -0,0 +1,39 @@ +// Diopser: a phase rotation plugin +// Copyright (C) 2021-2022 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use nih_plug::prelude::Editor; +use nih_plug_egui::widgets::generic_ui; +use nih_plug_egui::{create_egui_editor, egui, EguiState}; +use std::pin::Pin; +use std::sync::Arc; + +use crate::DiopserParams; + +// Makes sense to also definei this here, makes it a bit easier to keep track of +pub fn default_state() -> Arc { + EguiState::from_size(220, 330) +} + +pub fn create( + params: Pin>, + editor_state: Arc, +) -> Option> { + create_egui_editor(editor_state, (), move |egui_ctx, setter, _state| { + egui::CentralPanel::default().show(egui_ctx, |ui| { + generic_ui::create(ui, params.as_ref(), setter, generic_ui::GenericSlider); + }); + }) +} diff --git a/plugins/diopser/src/lib.rs b/plugins/diopser/src/lib.rs index b9583602..777a8c3b 100644 --- a/plugins/diopser/src/lib.rs +++ b/plugins/diopser/src/lib.rs @@ -23,11 +23,13 @@ compile_error!("Compiling without SIMD support is currently not supported"); extern crate nih_plug; use nih_plug::prelude::*; +use nih_plug_egui::EguiState; use std::pin::Pin; use std::simd::f32x2; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +mod editor; mod filter; /// How many all-pass filters we can have in series at most. The filter stages parameter determines @@ -42,12 +44,10 @@ const MAX_AUTOMATION_STEP_SIZE: u32 = 512; // All features from the original Diopser have been implemented (and the spread control has been // improved). Other features I want to implement are: // - Briefly muting the output when changing the number of filters to get rid of the clicks -// - A GUI -// -// TODO: Decide on whether to keep the scalar version or to just only support SIMD. Issue is that -// packed_simd requires a nightly compiler. +// - A proper GUI struct Diopser { - params: Pin>, + params: Pin>, + editor_state: Arc, /// Needed for computing the filter coefficients. sample_rate: f32, @@ -72,7 +72,7 @@ struct Diopser { // TODO: Some combinations of parameters can cause really loud resonance. We should limit the // resonance and filter stages parameter ranges in the GUI until the user unlocks. #[derive(Params)] -struct DiopserParams { +pub struct DiopserParams { /// The number of all-pass filters applied in series. #[id = "stages"] filter_stages: IntParam, @@ -112,7 +112,8 @@ impl Default for Diopser { let should_update_filters = Arc::new(AtomicBool::new(false)); Self { - params: Box::pin(DiopserParams::new(should_update_filters.clone())), + params: Arc::pin(DiopserParams::new(should_update_filters.clone())), + editor_state: editor::default_state(), sample_rate: 1.0, @@ -125,7 +126,7 @@ impl Default for Diopser { } impl DiopserParams { - pub fn new(should_update_filters: Arc) -> Self { + fn new(should_update_filters: Arc) -> Self { Self { filter_stages: IntParam::new( "Filter Stages", @@ -221,6 +222,10 @@ impl Plugin for Diopser { self.params.as_ref() } + fn editor(&self) -> Option> { + editor::create(self.params.clone(), self.editor_state.clone()) + } + fn accepts_bus_config(&self, config: &BusConfig) -> bool { // The SIMD version only supports stereo config.num_input_channels == config.num_output_channels && config.num_input_channels == 2 diff --git a/plugins/examples/gain-gui/src/lib.rs b/plugins/examples/gain-gui/src/lib.rs index 7adb9dd0..7dea77f7 100644 --- a/plugins/examples/gain-gui/src/lib.rs +++ b/plugins/examples/gain-gui/src/lib.rs @@ -85,6 +85,8 @@ impl Plugin for Gain { (), move |egui_ctx, setter, _state| { egui::CentralPanel::default().show(egui_ctx, |ui| { + // NOTE: See `plugins/diopser/src/editor.rs` for an example using the generic UI widget + // This is a fancy widget that can get all the information it needs to properly // display and modify the parameter from the parametr itself // It's not yet fully implemented, as the text is missing.