1use std::sync::Arc;
4
5use crate::{
6 Design, EngineConfig, EngineError, ExportView, MeasurementSet, measurement::Prepared,
7 setup::Setup,
8};
9
10#[derive(Debug, Clone, Copy)]
13pub enum ExportAxis {
14 Measurement,
15 Corrected,
16}
17
18#[derive(Debug)]
21pub struct DesignReplay {
22 measurements: Arc<MeasurementSet>,
23 config: EngineConfig,
24 setup: Setup,
25 prepared: Prepared,
26}
27
28impl DesignReplay {
29 pub(crate) fn new(
30 measurements: &MeasurementSet,
31 config: &EngineConfig,
32 setup: Setup,
33 prepared: &Prepared,
34 ) -> Self {
35 Self {
36 measurements: Arc::new(measurements.clone()),
37 config: config.clone(),
38 setup,
39 prepared: prepared.clone(),
40 }
41 }
42
43 pub fn measurements(&self) -> &MeasurementSet {
44 &self.measurements
45 }
46
47 pub fn config(&self) -> &EngineConfig {
48 &self.config
49 }
50
51 pub fn base_s(&self) -> f64 {
52 self.prepared.base_s
53 }
54
55 pub fn export_view(&self, design: &Design) -> Result<ExportView, EngineError> {
58 self.export_view_until(design, &|| false)
59 }
60
61 pub fn export_ir(
66 &self,
67 design: &Design,
68 spectrum: &[crate::C],
69 axis: ExportAxis,
70 ) -> (Vec<f64>, f64) {
71 let samples = secs_dsp::fft::irfft(spectrum, crate::grid::N_FFT)
72 .into_iter()
73 .map(|sample| f64::from(sample as f32))
74 .collect();
75 let t0 = match axis {
76 ExportAxis::Measurement => self.base_s(),
77 ExportAxis::Corrected => self.base_s() - design.chain.latency_ms / 1000.0,
78 };
79 (samples, t0)
80 }
81
82 pub fn mimo_responses(
85 &self,
86 design: &Design,
87 paths: &secs_types::chain::MimoPaths,
88 ) -> Result<Vec<(String, Vec<crate::C>)>, EngineError> {
89 crate::replay_mimo::responses(design, &self.export_view(design)?, paths)
90 }
91
92 pub(crate) fn export_view_until(
93 &self,
94 design: &Design,
95 cancelled: &dyn Fn() -> bool,
96 ) -> Result<ExportView, EngineError> {
97 crate::export_view::export_view_prepared(
98 design,
99 self.measurements(),
100 &self.prepared,
101 cancelled,
102 )
103 }
104
105 pub fn matches(&self, set: &MeasurementSet, config: &EngineConfig) -> bool {
109 self.config == *config
110 && self.measurements.positions.len() == set.positions.len()
111 && self
112 .measurements
113 .positions
114 .iter()
115 .zip(&set.positions)
116 .all(|((p, a), (q, b))| {
117 p == q
118 && a.len() == b.len()
119 && a.iter().zip(b).all(|((r, a), (s, b))| {
120 r == s
121 && a.sample_rate == b.sample_rate
122 && a.t0.to_bits() == b.t0.to_bits()
123 && match (&a.samples, &b.samples) {
124 (crate::Samples::F32(a), crate::Samples::F32(b)) => {
125 Arc::ptr_eq(a, b)
126 }
127 (crate::Samples::F64(a), crate::Samples::F64(b)) => {
128 Arc::ptr_eq(a, b)
129 }
130 _ => false,
131 }
132 })
133 })
134 }
135
136 pub(crate) fn prepared(&self) -> &Prepared {
137 &self.prepared
138 }
139
140 pub(crate) fn setup(&self) -> &Setup {
141 &self.setup
142 }
143
144 pub(crate) fn bytes(set: &MeasurementSet, config: &EngineConfig, setup: &Setup) -> u64 {
148 fn strings(values: &[String]) -> usize {
149 values.iter().map(|s| 32 + s.len()).sum()
150 }
151 fn manual(values: &[(String, crate::input::SubManual)]) -> usize {
152 values
153 .iter()
154 .map(|(r, m)| {
155 256 + r.len() + m.bundle.len() + m.allpass.len() * 16 + m.peq.len() * 24
156 })
157 .sum()
158 }
159 let measurements: usize = set
160 .positions
161 .iter()
162 .map(|(_, roles)| {
163 128 + roles.iter().map(|(r, _)| 320 + 5 * r.len()).sum::<usize>()
166 })
167 .sum();
168 let config_bytes = strings(&config.mains)
169 + strings(&config.subs)
170 + config
171 .groups
172 .iter()
173 .map(|(g, rs)| 64 + g.len() + strings(rs))
174 .sum::<usize>()
175 + config.target.points.len() * 16
176 + config.xo.iter().map(|(g, _)| 48 + g.len()).sum::<usize>()
177 + manual(&config.sub_manual)
178 + config
179 .bundle_layouts
180 .iter()
181 .map(|(g, _)| 64 + g.len())
182 .sum::<usize>();
183 let setup_bytes = manual(&setup.sub_manual)
184 + setup
185 .sub_filters
186 .iter()
187 .map(|(r, f)| 96 + r.len() + f.peq.len() * 24)
188 .sum::<usize>()
189 + setup
190 .layouts
191 .iter()
192 .map(|(g, l)| 80 + g.len() + strings(&l.members))
193 .sum::<usize>();
194 (std::mem::size_of::<Self>() + 128 + measurements + config_bytes + setup_bytes) as u64
195 }
196}