1use crate::grid::SR_F;
5use crate::input::{BandType, EngineConfig, LayoutKind, Peq, SubManual, SubMode};
6
7#[derive(Debug, Clone, PartialEq)]
8pub struct SubFilter {
9 pub hp_hz: f64,
10 pub hp_type: BandType,
11 pub lp_hz: f64,
12 pub lp_type: BandType,
13 pub peq: Vec<Peq>,
14}
15
16#[derive(Debug, Clone, PartialEq)]
17pub struct Layout {
18 pub kind: LayoutKind,
19 pub rear_trim_ms: f64,
20 pub members: Vec<String>,
21}
22
23#[derive(Debug, Clone)]
24pub struct Setup {
25 pub sub_manual: Vec<(String, SubManual)>,
26 pub sub_filters: Vec<(String, SubFilter)>,
27 pub layouts: Vec<(String, Layout)>,
28 pub lift_ms: f64,
29 pub lift_capped_from_ms: Option<f64>,
30 pub max_latency_ms: f64,
31 pub rc_lo: f64,
32 pub rc_hi_manual: Option<f64>,
33 pub rc_hi: f64,
34 pub rc_bands: Vec<(f64, f64)>,
35 pub lf_align: bool,
37 pub mode_decay: bool,
38 pub hf_phase: bool,
40 pub dip_limit: bool,
42 pub peq_bands: usize,
43 pub input_hp_hz: Option<f64>,
44}
45
46impl Setup {
47 pub fn new(config: &EngineConfig) -> Self {
48 let sub_manual: Vec<_> = config
49 .sub_manual
50 .iter()
51 .filter(|(r, _)| config.subs.contains(r))
52 .cloned()
53 .collect();
54 let mut sub_filters: Vec<_> = sub_manual
55 .iter()
56 .filter_map(|(r, m)| {
57 let peq: Vec<_> = m.peq.iter().copied().filter(|b| b.2 != 0.0).collect();
58 (m.hp_hz > 0.0 || m.lp_hz > 0.0 || !peq.is_empty()).then(|| {
59 (
60 r.clone(),
61 SubFilter {
62 hp_hz: m.hp_hz,
63 hp_type: m.hp_type,
64 lp_hz: m.lp_hz,
65 lp_type: m.lp_type,
66 peq,
67 },
68 )
69 })
70 })
71 .collect();
72 let mut layouts = Vec::new();
73 for (name, layout) in &config.bundle_layouts {
74 let members: Vec<_> = config
75 .subs
76 .iter()
77 .filter(|r| {
78 sub_manual.iter().any(|(role, m)| {
79 role == *r
80 && m.mode == SubMode::Bundle
81 && (if m.bundle.is_empty() { "A" } else { &m.bundle }) == name
82 })
83 })
84 .cloned()
85 .collect();
86 let Some(first) = members.first() else {
87 continue;
88 };
89 let lead = sub_filters
90 .iter()
91 .find(|(r, _)| r == first)
92 .map(|(_, f)| f.clone());
93 for r in &members[1..] {
94 if let Some(filter) = &lead {
95 if let Some((_, value)) = sub_filters.iter_mut().find(|(role, _)| role == r) {
96 *value = filter.clone();
97 } else {
98 sub_filters.push((r.clone(), filter.clone()));
99 }
100 } else {
101 sub_filters.retain(|(role, _)| role != r);
102 }
103 }
104 layouts.push((
105 name.clone(),
106 Layout {
107 kind: layout.kind,
108 rear_trim_ms: layout.rear_trim_ms,
109 members,
110 },
111 ));
112 }
113 let cap_ms = 0.7 * config.taps as f64 / SR_F * 1000.0;
114 let capped = config.lift_ms > cap_ms;
115 let lift_ms = if capped { cap_ms } else { config.lift_ms };
116 let max_latency_ms = config.max_latency_ms.map_or(lift_ms + 15.0, |v| {
117 if capped {
118 v - (config.lift_ms - cap_ms)
119 } else {
120 v
121 }
122 });
123 Self {
124 sub_manual,
125 sub_filters,
126 layouts,
127 lift_ms,
128 lift_capped_from_ms: capped.then_some(config.lift_ms),
129 max_latency_ms,
130 rc_lo: config.rc_range.0,
131 rc_hi_manual: config.rc_range.1,
132 rc_hi: config.rc_range.1.filter(|v| *v != 0.0).unwrap_or(500.0),
133 rc_bands: config.rc_bands.clone(),
134 lf_align: config.lf_align,
135 mode_decay: config.mode_decay,
136 hf_phase: config.hf_phase,
137 dip_limit: config.dip_limit,
138 peq_bands: config.peq_bands.unwrap_or(16),
139 input_hp_hz: config.input_hp_hz,
140 }
141 }
142}