refactor: split lib.rs into params and editor modules
Move parameter structs, defaults, and build_settings into src/params.rs; move the egui editor into src/editor.rs. lib.rs now holds only the plugin shell, DSP wiring, and process(). No behavior change (16/16 tests pass). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+199
@@ -0,0 +1,199 @@
|
||||
//! Plugin parameters and their layout.
|
||||
//!
|
||||
//! Holds the global controls plus four `CompressorParams` blocks (low/mid/high + the 'All'
|
||||
//! aggregate channel). `build_settings` translates a channel's params into the per-block
|
||||
//! [`CompressorSettings`] the DSP consumes.
|
||||
|
||||
use nih_plug::prelude::*;
|
||||
use nih_plug_egui::EguiState;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::dsp::compressor::{Compressor, CompressorSettings, MAX_LOOKAHEAD_MS};
|
||||
|
||||
/// Level-detection mode for a compressor's detector.
|
||||
#[derive(Enum, PartialEq, Clone, Copy)]
|
||||
pub enum DetectionMode {
|
||||
#[id = "peak"]
|
||||
#[name = "Peak"]
|
||||
Peak,
|
||||
#[id = "rms"]
|
||||
#[name = "RMS"]
|
||||
Rms,
|
||||
}
|
||||
|
||||
#[derive(Params)]
|
||||
pub struct Codename206Params {
|
||||
#[persist = "editor-state"]
|
||||
pub editor_state: Arc<EguiState>,
|
||||
|
||||
/// Low/Mid crossover frequency.
|
||||
#[id = "xover_lo"]
|
||||
pub crossover_low_hz: FloatParam,
|
||||
/// Mid/High crossover frequency.
|
||||
#[id = "xover_hi"]
|
||||
pub crossover_high_hz: FloatParam,
|
||||
/// Global look-ahead time (constant reported latency — safe to adjust during playback).
|
||||
#[id = "lookahead"]
|
||||
pub look_ahead_ms: FloatParam,
|
||||
|
||||
/// Output brickwall ceiling (the limiter never lets output exceed this).
|
||||
#[id = "ceiling"]
|
||||
pub output_ceiling_db: FloatParam,
|
||||
/// Output limiter release time.
|
||||
#[id = "lim_rel"]
|
||||
pub limiter_release_ms: FloatParam,
|
||||
|
||||
#[nested(id_prefix = "low", group = "Low")]
|
||||
pub low: CompressorParams,
|
||||
#[nested(id_prefix = "mid", group = "Mid")]
|
||||
pub mid: CompressorParams,
|
||||
#[nested(id_prefix = "high", group = "High")]
|
||||
pub high: CompressorParams,
|
||||
#[nested(id_prefix = "all", group = "All")]
|
||||
pub all: CompressorParams,
|
||||
}
|
||||
|
||||
#[derive(Params)]
|
||||
pub struct CompressorParams {
|
||||
#[id = "detect"]
|
||||
pub detection: EnumParam<DetectionMode>,
|
||||
#[id = "thresh"]
|
||||
pub threshold_db: FloatParam,
|
||||
#[id = "ratio"]
|
||||
pub ratio: FloatParam,
|
||||
#[id = "knee"]
|
||||
pub knee_db: FloatParam,
|
||||
#[id = "attack"]
|
||||
pub attack_ms: FloatParam,
|
||||
#[id = "release"]
|
||||
pub release_ms: FloatParam,
|
||||
#[id = "makeup"]
|
||||
pub makeup_db: FloatParam,
|
||||
#[id = "bypass"]
|
||||
pub bypass: BoolParam,
|
||||
}
|
||||
|
||||
impl Default for Codename206Params {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
editor_state: EguiState::from_size(760, 520),
|
||||
|
||||
crossover_low_hz: FloatParam::new(
|
||||
"Crossover Lo/Mid",
|
||||
200.0,
|
||||
FloatRange::Skewed { min: 30.0, max: 1_000.0, factor: FloatRange::skew_factor(-1.0) },
|
||||
)
|
||||
.with_value_to_string(formatters::v2s_f32_hz_then_khz(0))
|
||||
.with_string_to_value(formatters::s2v_f32_hz_then_khz()),
|
||||
|
||||
crossover_high_hz: FloatParam::new(
|
||||
"Crossover Mid/Hi",
|
||||
2_500.0,
|
||||
FloatRange::Skewed { min: 500.0, max: 18_000.0, factor: FloatRange::skew_factor(-1.0) },
|
||||
)
|
||||
.with_value_to_string(formatters::v2s_f32_hz_then_khz(0))
|
||||
.with_string_to_value(formatters::s2v_f32_hz_then_khz()),
|
||||
|
||||
look_ahead_ms: FloatParam::new(
|
||||
"Look-ahead",
|
||||
2.0,
|
||||
FloatRange::Linear { min: 0.0, max: MAX_LOOKAHEAD_MS },
|
||||
)
|
||||
.with_unit(" ms")
|
||||
.with_value_to_string(formatters::v2s_f32_rounded(2)),
|
||||
|
||||
output_ceiling_db: FloatParam::new(
|
||||
"Ceiling",
|
||||
0.0,
|
||||
FloatRange::Linear { min: -24.0, max: 0.0 },
|
||||
)
|
||||
.with_unit(" dB")
|
||||
.with_value_to_string(formatters::v2s_f32_rounded(1)),
|
||||
|
||||
limiter_release_ms: FloatParam::new(
|
||||
"Limiter Release",
|
||||
100.0,
|
||||
FloatRange::Skewed { min: 1.0, max: 1_000.0, factor: FloatRange::skew_factor(-2.0) },
|
||||
)
|
||||
.with_unit(" ms")
|
||||
.with_value_to_string(formatters::v2s_f32_rounded(1)),
|
||||
|
||||
low: CompressorParams::default(),
|
||||
mid: CompressorParams::default(),
|
||||
high: CompressorParams::default(),
|
||||
all: CompressorParams::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CompressorParams {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
detection: EnumParam::new("Detection", DetectionMode::Peak),
|
||||
|
||||
threshold_db: FloatParam::new(
|
||||
"Threshold",
|
||||
-18.0,
|
||||
FloatRange::Linear { min: -60.0, max: 0.0 },
|
||||
)
|
||||
.with_unit(" dB")
|
||||
.with_value_to_string(formatters::v2s_f32_rounded(1)),
|
||||
|
||||
ratio: FloatParam::new(
|
||||
"Ratio",
|
||||
2.0,
|
||||
FloatRange::Skewed { min: 1.0, max: 20.0, factor: FloatRange::skew_factor(-1.0) },
|
||||
)
|
||||
.with_value_to_string(Arc::new(|v| format!("{v:.2} : 1")))
|
||||
.with_string_to_value(Arc::new(|s| {
|
||||
s.split(':').next().and_then(|x| x.trim().parse::<f32>().ok())
|
||||
})),
|
||||
|
||||
knee_db: FloatParam::new("Knee", 6.0, FloatRange::Linear { min: 0.0, max: 24.0 })
|
||||
.with_unit(" dB")
|
||||
.with_value_to_string(formatters::v2s_f32_rounded(1)),
|
||||
|
||||
attack_ms: FloatParam::new(
|
||||
"Attack",
|
||||
10.0,
|
||||
FloatRange::Skewed { min: 0.0, max: 100.0, factor: FloatRange::skew_factor(-2.0) },
|
||||
)
|
||||
.with_unit(" ms")
|
||||
.with_value_to_string(formatters::v2s_f32_rounded(2)),
|
||||
|
||||
release_ms: FloatParam::new(
|
||||
"Release",
|
||||
100.0,
|
||||
FloatRange::Skewed { min: 1.0, max: 1_000.0, factor: FloatRange::skew_factor(-2.0) },
|
||||
)
|
||||
.with_unit(" ms")
|
||||
.with_value_to_string(formatters::v2s_f32_rounded(1)),
|
||||
|
||||
makeup_db: FloatParam::new("Makeup", 0.0, FloatRange::Linear { min: -12.0, max: 24.0 })
|
||||
.with_smoother(SmoothingStyle::Linear(20.0))
|
||||
.with_unit(" dB")
|
||||
.with_value_to_string(formatters::v2s_f32_rounded(1)),
|
||||
|
||||
bypass: BoolParam::new("Bypass", false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the per-block compressor settings for one channel's params (makeup filled per sample).
|
||||
pub fn build_settings(
|
||||
p: &CompressorParams,
|
||||
lookahead: usize,
|
||||
sample_rate: f32,
|
||||
) -> CompressorSettings {
|
||||
CompressorSettings {
|
||||
threshold_db: p.threshold_db.value(),
|
||||
ratio: p.ratio.value(),
|
||||
knee_db: p.knee_db.value(),
|
||||
attack_coef: Compressor::time_to_coef(p.attack_ms.value(), sample_rate),
|
||||
release_coef: Compressor::time_to_coef(p.release_ms.value(), sample_rate),
|
||||
makeup_db: 0.0,
|
||||
lookahead_samples: lookahead,
|
||||
use_rms: p.detection.value() == DetectionMode::Rms,
|
||||
bypass: p.bypass.value(),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user