1use crate::input::Peq;
4
5#[derive(Debug, Clone, PartialEq)]
6pub enum Note {
7 LiftCapped {
8 from_ms: f64,
9 taps: usize,
10 lift_ms: f64,
11 },
12 SubFilters(Vec<(String, crate::setup::SubFilter)>),
13 LowProtect {
14 role: String,
15 rolloff_hz: f64,
16 hp_hz: Option<f64>,
17 limited: bool,
18 reduced: usize,
19 cuts: usize,
20 },
21 RcLimit {
22 hz: f64,
23 auto: bool,
24 schroeder_hz: Option<f64>,
25 basis: secs_types::calibration::RcHiBasis,
26 factor: u8,
27 band_hz: Option<f64>,
28 band_t60_s: Option<f64>,
29 positions: Option<usize>,
30 },
31 RcBands {
32 bands: Vec<(f64, f64)>,
33 },
34 LfAlign {
39 role: String,
40 strength: f64,
41 arrival_ms: Option<f64>,
42 limited: bool,
43 },
44 ModeDecay {
48 role: String,
49 target_t60_s: f64,
50 modes: Vec<(f64, f64, f64)>,
51 },
52 Latency {
53 latency_ms: f64,
54 lift_ms: f64,
55 main_extra_ms: f64,
56 },
57 PhaseStrength(Vec<(String, f64)>),
58 PhaseBand(Vec<(String, Option<f64>)>),
59 LongModeBoost {
61 cap_db: f64,
62 modes: Vec<(f64, f64)>,
63 },
64 GdCuts {
65 role: String,
66 cuts: Vec<Peq>,
67 },
68 BaCost(f64),
70 BaBusPass {
71 first: f64,
72 second: f64,
73 kept_first: bool,
74 },
75 BaManual,
76 LayoutFallback(String),
77 Layout(String),
78 TwoWay {
79 roles: Vec<String>,
80 gain_db: f64,
81 xo_hz: f64,
82 },
83 BusGainAnchored(f64),
84 Mimo(MimoNote),
85}
86
87#[derive(Debug, Clone, PartialEq)]
89pub enum MimoNote {
90 InsufficientPositions {
91 measured: usize,
92 },
93 ExcludedSupports(Vec<String>),
94 SupportRanges(Vec<(String, Option<(f64, f64)>)>),
95 GuardReduced {
96 role: String,
97 gain_db: f64,
98 },
99 GuardDisabled {
100 role: String,
101 },
102 SupportLimit {
103 max_supports: usize,
104 },
105 FirBudget {
106 support_count: usize,
107 taps_total: usize,
108 },
109}
110
111#[cfg(test)]
112impl MimoNote {
113 pub(crate) fn oracle_text(&self) -> String {
115 match self {
116 Self::InsufficientPositions { measured } => {
117 format!("측정 위치 {measured}곳 — MIMO 는 3곳 이상일 때만")
118 }
119 Self::ExcludedSupports(roles) => format!("서포트 제외(사용자): {}", roles.join(", ")),
120 Self::SupportRanges(ranges) => format!(
121 "서포트 대역 {}",
122 ranges
123 .iter()
124 .map(|(role, range)| match range {
125 Some((lo, hi)) => format!("{role} {lo:.0}–{hi:.0}"),
126 None => format!("{role} 제외"),
127 })
128 .collect::<Vec<_>>()
129 .join(", ")
130 ),
131 Self::GuardReduced { role, gain_db } => {
132 format!("{role}: 대역 늦은 에너지 악화로 서포트 {gain_db:.0} dB")
133 }
134 Self::GuardDisabled { role } => format!("{role}: MIMO 끔(악화)"),
135 Self::SupportLimit { max_supports } => format!("입력당 서포트 ≤ {max_supports}"),
136 Self::FirBudget {
137 support_count,
138 taps_total,
139 } => {
140 let digits = taps_total.to_string();
141 let grouped = digits
142 .chars()
143 .enumerate()
144 .fold(String::new(), |mut out, (i, ch)| {
145 if i > 0 && (digits.len() - i).is_multiple_of(3) {
146 out.push(',');
147 }
148 out.push(ch);
149 out
150 });
151 format!("FIR 서포트 {support_count}개 · 총 {grouped}탭(48 kHz)")
152 }
153 }
154 }
155}