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