1pub mod ops;
4pub mod renderer;
5pub mod tape;
6
7use crate::buffer::Buffer;
8use crate::error::SampleError;
9use crate::filters::FilterSite;
10use crate::physics::{Solver, site};
11use ops::{Layout, Op, lower};
12use renderer::{NodeRenderer, Site};
13use tape::{Tape, Window};
14
15pub use ops::Layout as MachineLayout;
16
17struct Program {
19 ops: Vec<Op>,
20 widths: Vec<usize>,
21 sites: Vec<Site>,
22 pub width: usize,
23}
24
25pub struct Ctx<'a> {
29 pub rate: u32,
30 pub origin_secs: f64,
31 pub len: usize,
32 pub reads: &'a [Window<'a>],
33 pub self_planes: &'a [f64],
34 pub written: usize,
35}
36
37impl NodeRenderer {
38 fn compile(&self, layout: &Layout) -> Result<Program, SampleError> {
39 let (mut ops, mut widths) = (Vec::new(), Vec::new());
40 let width = lower(self, layout, &mut ops, &mut widths)?;
41 Ok(Program {
42 ops,
43 widths,
44 sites: layout.sites.clone(),
45 width,
46 })
47 }
48
49 pub fn run(&self, layout: &Layout, ctx: &Ctx) -> Result<Buffer, SampleError> {
51 let mut machine = Machine::open(self, layout, ctx.rate, ctx.origin_secs)?;
52 let mut own = Tape::new(machine.width(), ctx.len);
53 let past = match ctx.self_planes.is_empty() {
54 true => Past::Own,
55 false => Past::Fixed {
56 planes: ctx.self_planes,
57 len: ctx.len,
58 written: ctx.written,
59 },
60 };
61 machine.steps(ctx.len, ctx.reads, &past, &mut own)?;
62 let mut out = Buffer::of_planes(ctx.rate, own.into_planes());
63 out.origin_secs = ctx.origin_secs;
64 Ok(out)
65 }
66}
67
68#[derive(Clone)]
69enum State {
70 Filter(FilterSite),
71 Physics(Box<dyn Solver>),
72}
73
74impl Clone for Box<dyn Solver> {
75 fn clone(&self) -> Box<dyn Solver> {
76 self.boxed()
77 }
78}
79
80fn open(p: &Program, rate: u32) -> Result<Vec<State>, SampleError> {
83 let mut lanes = vec![1usize; p.sites.len()];
84 for (slot, op) in p.ops.iter().enumerate() {
85 if let Op::Filter(id) = op {
86 lanes[id.0 as usize] = p.widths[slot];
87 }
88 }
89 p.sites
90 .iter()
91 .zip(lanes)
92 .map(|(s, width)| {
93 Ok(match s {
94 Site::Filter(shape) => State::Filter(FilterSite::new(
95 *shape,
96 width,
97 &[0.0],
98 &[0.0],
99 &[0.0],
100 f64::from(rate),
101 )),
102 Site::Physics(params) => State::Physics(site(params, rate)?),
103 })
104 })
105 .collect()
106}
107
108struct Stack {
110 values: Vec<Vec<f64>>,
111 pending: Vec<usize>,
112}
113
114impl Stack {
115 fn of(widths: &[usize]) -> Stack {
116 Stack {
117 values: widths.iter().map(|&w| vec![0.0; w]).collect(),
118 pending: Vec::with_capacity(widths.len()),
119 }
120 }
121}
122
123fn part(v: &[f64], c: usize) -> f64 {
125 v[c % v.len()]
126}
127
128enum Past<'a> {
129 Own,
130 Fixed {
131 planes: &'a [f64],
132 len: usize,
133 written: usize,
134 },
135}
136
137pub struct Machine {
140 program: Program,
141 states: Vec<State>,
142 stack: Stack,
143 rate: u32,
144 origin_secs: f64,
145}
146
147#[derive(Clone)]
148pub struct MachineState {
149 sites: Vec<Site>,
150 states: Vec<State>,
151}
152
153impl Machine {
154 pub fn open(
155 renderer: &NodeRenderer,
156 layout: &Layout,
157 rate: u32,
158 origin_secs: f64,
159 ) -> Result<Machine, SampleError> {
160 let program = renderer.compile(layout)?;
161 let states = open(&program, rate)?;
162 let stack = Stack::of(&program.widths);
163 Ok(Machine {
164 program,
165 states,
166 stack,
167 rate,
168 origin_secs,
169 })
170 }
171
172 pub fn width(&self) -> usize {
173 self.program.width
174 }
175
176 pub fn run_to(
177 &mut self,
178 to: usize,
179 reads: &[Window],
180 own: &mut Tape,
181 ) -> Result<(), SampleError> {
182 for state in &mut self.states {
183 if let State::Filter(filter) = state {
184 filter.forget_frames();
185 }
186 }
187 self.steps(to, reads, &Past::Own, own)
188 }
189
190 fn steps(
191 &mut self,
192 to: usize,
193 reads: &[Window],
194 past: &Past,
195 own: &mut Tape,
196 ) -> Result<(), SampleError> {
197 let sr = f64::from(self.rate);
198 let p = &self.program;
199 for i in own.end()..to {
200 let t = self.origin_secs + i as f64 / sr;
201 let here = Here {
202 reads,
203 past,
204 own,
205 i,
206 t,
207 sr,
208 };
209 step(p, &here, &mut self.states, &mut self.stack)?;
210 let top = &self.stack.values[*self
211 .stack
212 .pending
213 .last()
214 .expect("a renderer leaves one value")];
215 for c in 0..p.width {
216 own.push(c, part(top, c));
217 }
218 }
219 Ok(())
220 }
221
222 pub fn solver(&self, site: usize) -> Option<&dyn Solver> {
224 match self.states.get(site)? {
225 State::Physics(solver) => Some(solver.as_ref()),
226 State::Filter(_) => None,
227 }
228 }
229
230 pub fn filter(&self, site: usize) -> Option<&FilterSite> {
231 match self.states.get(site)? {
232 State::Filter(filter) => Some(filter),
233 State::Physics(_) => None,
234 }
235 }
236
237 pub fn state(&self) -> MachineState {
238 MachineState {
239 sites: self.program.sites.clone(),
240 states: self.states.clone(),
241 }
242 }
243
244 pub fn carry(&mut self, held: &MachineState) -> Result<(), SampleError> {
247 if held.sites.len() != self.program.sites.len() {
248 return Err(SampleError::StateMismatch);
249 }
250 for (at, (mine, theirs)) in self.program.sites.iter().zip(&held.sites).enumerate() {
251 let taken = match (mine, theirs, &mut self.states[at], &held.states[at]) {
252 _ if mine == theirs => {
253 self.states[at] = held.states[at].clone();
254 true
255 }
256 (
257 Site::Physics(a),
258 Site::Physics(b),
259 State::Physics(solver),
260 State::Physics(motion),
261 ) if a.differs_in_release_alone(b) => solver.take_motion(motion.as_ref()),
262 _ => false,
263 };
264 if !taken {
265 return Err(SampleError::StateMismatch);
266 }
267 }
268 Ok(())
269 }
270}
271
272struct Here<'a> {
273 reads: &'a [Window<'a>],
274 past: &'a Past<'a>,
275 own: &'a Tape,
276 i: usize,
277 t: f64,
278 sr: f64,
279}
280
281fn step(
284 p: &Program,
285 here: &Here,
286 states: &mut [State],
287 stack: &mut Stack,
288) -> Result<(), SampleError> {
289 stack.pending.clear();
290 for (slot, op) in p.ops.iter().enumerate() {
291 let at = stack.pending.len() - arity_of(op);
292 let (done, rest) = stack.values.split_at_mut(slot);
293 fill(op, done, &stack.pending[at..], &mut rest[0], here, states)?;
294 stack.pending.truncate(at);
295 stack.pending.push(slot);
296 }
297 Ok(())
298}
299
300fn arity_of(op: &Op) -> usize {
301 match op {
302 Op::Const(_) | Op::Time | Op::Read { .. } | Op::SelfAt { .. } | Op::Physics(_) => 0,
303 Op::Map(_) | Op::Crop { .. } | Op::Channel(_) => 1,
304 Op::Sub | Op::Div | Op::Pow | Op::Zip(_) => 2,
305 Op::Add(n) | Op::Mul(n) | Op::Join(n) => *n,
306 Op::Filter(_) => 4,
307 }
308}
309
310fn fill(
311 op: &Op,
312 done: &[Vec<f64>],
313 srcs: &[usize],
314 result: &mut [f64],
315 here: &Here,
316 states: &mut [State],
317) -> Result<(), SampleError> {
318 let (i, t, sr) = (here.i, here.t, here.sr);
319 let arg = |k: usize| done[srcs[k]].as_slice();
320 match op {
321 Op::Const(v) => result[0] = *v,
322 Op::Time => result[0] = t,
323 Op::Read { id, shift } => {
324 let window = here.reads[id.0 as usize];
325 let at = i as i64 + shift;
326 for (c, slot) in result.iter_mut().enumerate() {
327 *slot = window.at(c, at);
328 }
329 }
330 Op::SelfAt { steps } => {
331 let at = i as i64 - i64::from(*steps);
332 for (c, slot) in result.iter_mut().enumerate() {
333 *slot = match here.past {
334 Past::Own => here.own.window().at(c, at),
335 Past::Fixed {
336 planes,
337 len,
338 written,
339 } => usize::try_from(at)
340 .ok()
341 .filter(|k| k < written)
342 .and_then(|k| planes.get(c * len + k).copied())
343 .unwrap_or(0.0),
344 };
345 }
346 }
347 Op::Add(_) | Op::Mul(_) => {
348 let product = matches!(op, Op::Mul(_));
349 for (c, slot) in result.iter_mut().enumerate() {
350 *slot =
351 srcs.iter()
352 .enumerate()
353 .fold(f64::from(u8::from(product)), |acc, (k, _)| {
354 if product {
355 acc * part(arg(k), c)
356 } else {
357 acc + part(arg(k), c)
358 }
359 });
360 }
361 }
362 Op::Sub | Op::Div | Op::Pow | Op::Zip(_) => {
363 for (c, slot) in result.iter_mut().enumerate() {
364 let (a, b) = (part(arg(0), c), part(arg(1), c));
365 *slot = match op {
366 Op::Sub => a - b,
367 Op::Div => a / b,
368 Op::Pow => a.powf(b),
369 Op::Zip(f) => f.apply(a, b),
370 _ => unreachable!("the arm's own guard"),
371 };
372 }
373 }
374 Op::Map(f) => {
375 for (c, slot) in result.iter_mut().enumerate() {
376 *slot = f.apply(part(arg(0), c));
377 }
378 }
379 Op::Crop { a, b, rise, fall } => {
380 let gain = crate::collapse::crop_gain(t, *a, *b, *rise, *fall);
381 for (c, slot) in result.iter_mut().enumerate() {
382 *slot = match gain {
383 0.0 => 0.0,
384 gain => part(arg(0), c) * gain,
385 };
386 }
387 }
388 Op::Join(_) => {
389 let mut c = 0;
390 for k in 0..srcs.len() {
391 for &v in arg(k) {
392 result[c] = v;
393 c += 1;
394 }
395 }
396 }
397 Op::Channel(k) => result[0] = arg(0)[*k],
398 Op::Filter(id) => {
399 let State::Filter(filter) = &mut states[id.0 as usize] else {
400 unreachable!("a filter op names a filter site")
401 };
402 filter.process(arg(0), arg(1), arg(2), arg(3), result, sr, i);
403 }
404 Op::Physics(id) => {
405 let State::Physics(solver) = &mut states[id.0 as usize] else {
406 unreachable!("a physics op names a physics site")
407 };
408 result[0] = solver.step()?;
409 }
410 }
411 Ok(())
412}