use nih_plug::prelude::*; use nih_plug_egui::{create_egui_editor, egui, widgets, EguiState}; use std::sync::Arc; /// Codename 206 — landmark build. /// /// This is intentionally tiny: a single full-band gain parameter exposed through one /// egui slider. It is the foundation the multiband compressor/limiter (see README.md) /// will be built on top of. The signal path is currently just `sample *= gain`. struct Codename206 { params: Arc, } #[derive(Params)] struct Codename206Params { /// The egui editor's window state (size). Persisted with the parameter state so a /// resized window is restored on reload. #[persist = "editor-state"] editor_state: Arc, /// Full-band output gain. Stored as a linear gain multiplier but displayed in dB. #[id = "gain"] pub gain: FloatParam, } impl Default for Codename206 { fn default() -> Self { Self { params: Arc::new(Codename206Params::default()), } } } impl Default for Codename206Params { fn default() -> Self { Self { editor_state: EguiState::from_size(300, 140), // Stored as linear gain, displayed/edited in dB. Skewed so the slider feels // linear in decibels across the -30..+30 dB range. gain: FloatParam::new( "Gain", util::db_to_gain(0.0), FloatRange::Skewed { min: util::db_to_gain(-30.0), max: util::db_to_gain(30.0), factor: FloatRange::gain_skew_factor(-30.0, 30.0), }, ) // Linear-gain storage needs logarithmic smoothing to avoid zipper noise. .with_smoother(SmoothingStyle::Logarithmic(50.0)) .with_unit(" dB") .with_value_to_string(formatters::v2s_f32_gain_to_db(2)) .with_string_to_value(formatters::s2v_f32_gain_to_db()), } } } impl Plugin for Codename206 { const NAME: &'static str = "206 prototype"; const VENDOR: &'static str = "Novoyuuparosk"; const URL: &'static str = env!("CARGO_PKG_HOMEPAGE"); const EMAIL: &'static str = "mikkeli@novoyuuparosk.org"; const VERSION: &'static str = env!("CARGO_PKG_VERSION"); const AUDIO_IO_LAYOUTS: &'static [AudioIOLayout] = &[ AudioIOLayout { main_input_channels: NonZeroU32::new(2), main_output_channels: NonZeroU32::new(2), ..AudioIOLayout::const_default() }, AudioIOLayout { main_input_channels: NonZeroU32::new(1), main_output_channels: NonZeroU32::new(1), ..AudioIOLayout::const_default() }, ]; const MIDI_INPUT: MidiConfig = MidiConfig::None; const MIDI_OUTPUT: MidiConfig = MidiConfig::None; const SAMPLE_ACCURATE_AUTOMATION: bool = true; type SysExMessage = (); type BackgroundTask = (); fn params(&self) -> Arc { self.params.clone() } fn editor(&mut self, _async_executor: AsyncExecutor) -> Option> { let params = self.params.clone(); create_egui_editor( self.params.editor_state.clone(), (), |_, _| {}, move |egui_ctx, setter, _state| { egui::CentralPanel::default().show(egui_ctx, |ui| { ui.heading("Codename 206"); ui.separator(); ui.label("Gain"); ui.add(widgets::ParamSlider::for_param(¶ms.gain, setter)); }); }, ) } fn process( &mut self, buffer: &mut Buffer, _aux: &mut AuxiliaryBuffers, _context: &mut impl ProcessContext, ) -> ProcessStatus { for channel_samples in buffer.iter_samples() { let gain = self.params.gain.smoothed.next(); for sample in channel_samples { *sample *= gain; } } ProcessStatus::Normal } } impl ClapPlugin for Codename206 { const CLAP_ID: &'static str = "com.mikkeli.codename-206"; const CLAP_DESCRIPTION: Option<&'static str> = Some("Multiband compressor/limiter (landmark: full-band gain)"); const CLAP_MANUAL_URL: Option<&'static str> = Some(Self::URL); const CLAP_SUPPORT_URL: Option<&'static str> = None; const CLAP_FEATURES: &'static [ClapFeature] = &[ ClapFeature::AudioEffect, ClapFeature::Stereo, ClapFeature::Mono, ClapFeature::Compressor, ClapFeature::Limiter, ]; } impl Vst3Plugin for Codename206 { const VST3_CLASS_ID: [u8; 16] = *b"Codename206Maxi!"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] = &[Vst3SubCategory::Fx, Vst3SubCategory::Dynamics]; } nih_export_clap!(Codename206); nih_export_vst3!(Codename206);