Add peak/RMS detection switch; sweep docs to match code

- Compressor: switchable peak / RMS detection (EnumParam<DetectionMode> in lib.rs
  -> use_rms bool in CompressorSettings; DSP stays framework-agnostic). RMS is a
  one-pole running mean of the linked squared level with a hardcoded 5 ms window,
  updated whenever active so peak<->RMS switching is seamless. New unit test
  (RMS compresses a sine less than peak); 6 tests total.
- README: reconciled Implementation Order checklists with actual progress
  (Stages 1-2 done; look-ahead/latency + basic UI pulled forward), annotated the
  project structure (implemented vs planned), and corrected the Latency and
  Denormal-flushing notes to match the code (set_latency_samples once / constant
  latency; in-code denormal flush). Overview and goals left unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Mikkeli Matlock
2026-06-15 20:02:23 +09:00
parent 8d9eaeaffc
commit 0f66e9638c
3 changed files with 128 additions and 40 deletions
+19
View File
@@ -5,6 +5,17 @@ use std::sync::Arc;
mod dsp;
use dsp::compressor::{Compressor, CompressorSettings, MAX_LOOKAHEAD_MS};
/// Level-detection mode for the compressor's detector.
#[derive(Enum, PartialEq, Clone, Copy)]
enum DetectionMode {
#[id = "peak"]
#[name = "Peak"]
Peak,
#[id = "rms"]
#[name = "RMS"]
Rms,
}
/// Codename 206 — Stage 2: a single full-band compressor with look-ahead.
///
/// The `CompressorParams` struct is `#[nested]` so the exact same controls + DSP can be
@@ -33,6 +44,8 @@ struct Codename206Params {
#[derive(Params)]
struct CompressorParams {
#[id = "detect"]
pub detection: EnumParam<DetectionMode>,
#[id = "thresh"]
pub threshold_db: FloatParam,
#[id = "ratio"]
@@ -80,6 +93,8 @@ impl Default for Codename206Params {
impl Default for CompressorParams {
fn default() -> Self {
Self {
detection: EnumParam::new("Detection", DetectionMode::Peak),
threshold_db: FloatParam::new(
"Threshold",
-18.0,
@@ -188,6 +203,9 @@ impl Plugin for Codename206 {
ui.heading(Self::NAME);
ui.separator();
egui::Grid::new("params").num_columns(2).show(ui, |ui| {
ui.label("Detection");
ui.add(widgets::ParamSlider::for_param(&params.comp.detection, setter));
ui.end_row();
ui.label("Threshold");
ui.add(widgets::ParamSlider::for_param(&params.comp.threshold_db, setter));
ui.end_row();
@@ -260,6 +278,7 @@ impl Plugin for Codename206 {
release_coef: Compressor::time_to_coef(c.release_ms.value(), self.sample_rate),
makeup_db: 0.0,
lookahead_samples: lookahead,
use_rms: c.detection.value() == DetectionMode::Rms,
bypass: c.bypass.value(),
};