valentine

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

adatset.rs (3205B)


      1 //! Persisting ADAT attenuation test. Sets the ADAT monitor group to a given dB
      2 //! via the exact TUI path (route via mixer + set_group_level) and LEAVES it
      3 //! there so you can listen. This isolates "does the bus write audibly change
      4 //! ADAT?" from all TUI plumbing.
      5 //!
      6 //!   cargo run -p spike --bin adatset -- -40     # quiet it, listen
      7 //!   cargo run -p spike --bin adatset -- 0       # back to unity (via mixer)
      8 //!   cargo run -p spike --bin adatset -- direct  # restore ADAT ← PCM direct
      9 //!
     10 //! Run with Focusrite Control quit.
     11 
     12 use scarlett_core::matrix::MonitorGroup;
     13 use scarlett_core::model::S18I20_GEN3;
     14 use scarlett_core::mux::PORT_COUNT_18I20_GEN3;
     15 use scarlett_core::{Scarlett, UsbTransport};
     16 
     17 fn main() {
     18     if let Err(e) = run() {
     19         eprintln!("\x1b[31mADATSET FAILED:\x1b[0m {e}");
     20         std::process::exit(1);
     21     }
     22 }
     23 
     24 fn adat() -> &'static MonitorGroup {
     25     scarlett_core::matrix::MONITOR_GROUPS
     26         .iter()
     27         .find(|g| g.name.starts_with("ADAT"))
     28         .unwrap()
     29 }
     30 
     31 fn run() -> Result<(), Box<dyn std::error::Error>> {
     32     let arg = std::env::args().nth(1).unwrap_or_else(|| "-40".into());
     33     let mut dev = Scarlett::new(UsbTransport::open_default()?);
     34     dev.init()?;
     35     let pc = PORT_COUNT_18I20_GEN3;
     36     let g = adat();
     37     let inputs = S18I20_GEN3.mixer_inputs() as usize;
     38 
     39     if arg == "direct" {
     40         dev.route_group_direct(pc, g)?;
     41         println!("ADAT restored to direct-from-DAW (ADAT Out ← PCM 13-20). Listen.");
     42         return Ok(());
     43     }
     44 
     45     let db: f32 = arg.parse().map_err(|_| "pass a dB number, or 'direct'")?;
     46     println!("Routing ADAT via mixer and setting level to {db} dB (persisting)…");
     47 
     48     // Write the 3 sample-rate-band tables SEPARATELY to see which one fails.
     49     use scarlett_core::mux::{id_to_num, mux_assignment_18i20_gen3, num_dsts, Dir, MuxState};
     50     let n = |dir, id| id_to_num(&pc, dir, id).unwrap_or(0);
     51     let entries = dev.get_mux(num_dsts(&pc))?;
     52     let mut st = MuxState::from_entries(pc, &entries);
     53     for i in 0..g.count {
     54         st.set(n(Dir::Out, 0x300 + g.mix_in_base + i), n(Dir::In, 0x600 + g.pcm_base + i));
     55         st.set(n(Dir::Out, g.out_id_base + i), n(Dir::In, 0x300 + g.bus_base + i));
     56     }
     57     let tables = st.encode_all(&mux_assignment_18i20_gen3());
     58     for (i, t) in tables.iter().enumerate() {
     59         match dev.write_routing_table(i as u16, t) {
     60             Ok(()) => println!("  table {i} ({} entries): OK", t.len()),
     61             Err(e) => println!("  table {i} ({} entries): FAILED — {e}", t.len()),
     62         }
     63     }
     64     if let Err(e) = dev.set_group_level(g, db, inputs) {
     65         println!("  set_group_level: FAILED — {e}");
     66     } else {
     67         println!("  set_group_level: OK");
     68     }
     69 
     70     // Read back so we report the truth.
     71     let raw = dev.get_mix(g.bus_base, inputs)?;
     72     let got = scarlett_core::matrix::mixer_value_to_db(
     73         raw.get(g.mix_in_base as usize).copied().unwrap_or(0),
     74     );
     75     println!("done. Mix bus {} input {} now reads {got:.1} dB.", g.bus_base, g.mix_in_base + 1);
     76     println!("\n>>> LISTEN NOW: did your ADAT monitoring get quieter? <<<");
     77     println!("(restore with: cargo run -p spike --bin adatset -- direct)");
     78     Ok(())
     79 }