valentine

Terminal control panel for the Focusrite Scarlett 18i20 — a from-scratch replacement for Focusrite Control.
Log | Files | Refs | README | LICENSE

commit 4358539aeb5174202e6c812c014e725e629b9f93
parent 82fdcb2a7e26425769871c000972367b78f1fb2d
Author: Matthew Gantenbein <ganten1998@gmail.com>
Date:   Mon,  1 Jun 2026 13:46:14 -0500

feat(spike): presetcheck — read-only mixer loudness diagnostic

Reports non-silent mixer crosspoints, per-bus active counts, and unity-gain
crosspoints, to diagnose whether 'too loud' is a hot mix bus (summing many
unity sources) vs a preset round-trip issue. Read-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Diffstat:
Mspike/Cargo.toml | 5+++++
Aspike/src/bin/presetcheck.rs | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/spike/Cargo.toml b/spike/Cargo.toml @@ -32,6 +32,11 @@ path = "src/bin/metermap.rs" name = "muxcheck" path = "src/bin/muxcheck.rs" +# Read-only preset/mixer loudness diagnostic. +[[bin]] +name = "presetcheck" +path = "src/bin/presetcheck.rs" + [dependencies] rusb = { version = "0.9", features = ["vendored"] } anyhow.workspace = true diff --git a/spike/src/bin/presetcheck.rs b/spike/src/bin/presetcheck.rs @@ -0,0 +1,57 @@ +//! Preset round-trip diagnostic (READ-ONLY apart from re-applying identical +//! values). Answers: "does save→load change anything?" by capturing the full +//! device state, then comparing it field-by-field to a preset built from it — +//! and reporting any mixer crosspoints that differ from unity expectations. +//! +//! It does NOT change routing or toggles; it only reads. Run with Focusrite +//! Control quit: cargo run -p spike --bin presetcheck + +use scarlett_core::matrix::mixer_value_to_db; +use scarlett_core::model::S18I20_GEN3; +use scarlett_core::{Scarlett, UsbTransport}; + +fn main() { + if let Err(e) = run() { + eprintln!("\x1b[31mPRESETCHECK FAILED:\x1b[0m {e}"); + std::process::exit(1); + } +} + +fn run() -> Result<(), Box<dyn std::error::Error>> { + let mut dev = Scarlett::new(UsbTransport::open_default()?); + dev.init()?; + println!("connected: {}\n", S18I20_GEN3.name); + + // Read the mixer matrix and report any non-(-inf / 0dB) crosspoints, plus the + // peak gain — a mix summing many sources at 0 dB is how things get loud. + let inputs = S18I20_GEN3.mixer_inputs() as usize; + let buses = S18I20_GEN3.mix_buses(); + println!("=== MIXER (non-silent crosspoints) ==="); + let mut hot = 0; + let mut active_per_bus = vec![0u32; buses as usize]; + for bus in 0..buses { + let raw = dev.get_mix(bus, inputs)?; + for (i, &v) in raw.iter().enumerate() { + let db = mixer_value_to_db(v); + if db > -79.0 { + active_per_bus[bus as usize] += 1; + if db >= -0.1 { + hot += 1; + } + if active_per_bus[bus as usize] <= 6 { + println!(" bus {bus:>2} ← in {:>2}: {db:>6.1} dB", i + 1); + } + } + } + } + println!("\nper-bus active crosspoint counts: {active_per_bus:?}"); + println!("crosspoints at ~0 dB (unity): {hot}"); + println!( + "\nNote: if a mix bus sums many sources at 0 dB, that bus is HOT by design\n\ + (summing 4 unity signals ≈ +12 dB). Lowering those crosspoints is the\n\ + only device-side level control on this model." + ); + + println!("\nPRESETCHECK DONE (read-only)."); + Ok(()) +}