1mod block;
4mod kernels;
5mod live;
6pub mod ops;
7mod read;
8pub mod renderer;
9mod tape;
10
11use std::sync::Arc;
12
13use crate::buffer::{Buffer, SampleView};
14use crate::collapse::Program;
15use crate::error::SampleError;
16use crate::filters::FilterSite;
17use crate::grid::Extent;
18use crate::grid::Grid;
19use crate::physics::{Solver, site};
20use block::{BLOCK, BlockScratch};
21use ops::{Layout, Op, lowered};
22use read::Here;
23use renderer::{Formula, Index, NodeRenderer, Site, Slot};
24
25pub use live::{Span, Spanned};
26
27pub use ops::Layout as MachineLayout;
28
29#[derive(Clone)]
32pub(super) struct CompiledOps {
33 ops: Vec<Op>,
34 widths: Vec<usize>,
35 args: Vec<Vec<usize>>,
36 formulas: Vec<(Formula, Arc<Vec<Program>>)>,
38 indices: Vec<Index<usize>>,
39 sites: Vec<Site>,
40 pub width: usize,
41}
42
43impl NodeRenderer {
44 pub(super) fn compile(&self, layout: &Layout) -> Result<CompiledOps, SampleError> {
45 let (lowered, width) = lowered(self, layout)?;
46 let mut formulas: Vec<(Formula, Arc<Vec<Program>>)> = lowered
47 .formulas
48 .into_iter()
49 .map(|f| (f, Arc::new(Vec::new())))
50 .collect();
51 for (slot, op) in lowered.ops.iter().enumerate() {
52 if let Op::Formula { at } = op
53 && let (Formula::Written(w), programs) = &mut formulas[*at]
54 {
55 let each = (0..lowered.widths[slot]).map(|c| Program::of(&[&w.body], &w.refs, c));
56 *programs = Arc::new(each.collect());
57 }
58 }
59 Ok(CompiledOps {
60 ops: lowered.ops,
61 widths: lowered.widths,
62 args: lowered.args,
63 formulas,
64 indices: lowered.indices,
65 sites: layout.sites.clone(),
66 width,
67 })
68 }
69}
70
71#[derive(Clone)]
72enum State {
73 Filter(FilterSite),
74 Physics(Box<dyn Solver>),
75}
76
77impl Clone for Box<dyn Solver> {
78 fn clone(&self) -> Box<dyn Solver> {
79 self.boxed()
80 }
81}
82
83fn open(p: &CompiledOps, grid: Grid) -> Result<Vec<State>, SampleError> {
86 let mut lanes = vec![1usize; p.sites.len()];
87 for (slot, op) in p.ops.iter().enumerate() {
88 if let Op::Filter { site, .. } = op {
89 lanes[site.0 as usize] = p.widths[slot];
90 }
91 }
92 p.sites
93 .iter()
94 .zip(lanes)
95 .map(|(s, width)| {
96 Ok(match s {
97 Site::Filter(shape) => State::Filter(FilterSite::new(
98 *shape,
99 width,
100 &[0.0],
101 &[0.0],
102 &[0.0],
103 grid.sr(),
104 )),
105 Site::Physics(params) => State::Physics(site(params, grid.sr())?),
106 })
107 })
108 .collect()
109}
110
111fn part(v: &[f64], c: usize) -> f64 {
113 v[c.min(v.len() - 1)]
114}
115
116pub type Own<'a> = (&'a mut Buffer, i64);
118
119pub struct Machine {
122 compiled_ops: CompiledOps,
123 states: Vec<State>,
124 block: BlockScratch,
125 grid: Grid,
126 ahead: Vec<(i64, CompiledOps)>,
128}
129
130#[derive(Clone)]
131pub struct MachineState {
132 sites: Vec<Site>,
133 states: Vec<State>,
134}
135
136impl State {
137 fn bytes(&self) -> usize {
138 match self {
139 State::Filter(filter) => filter.bytes(),
140 State::Physics(solver) => solver.bytes(),
141 }
142 }
143}
144
145impl MachineState {
146 pub fn bytes(&self) -> usize {
147 let states: usize = self.states.iter().map(State::bytes).sum();
148 size_of::<Self>() + std::mem::size_of_val(self.sites.as_slice()) + states
149 }
150}
151
152impl Machine {
153 pub fn over(spanned: &Spanned, at: i64) -> Result<Machine, SampleError> {
155 let grid = spanned.grid();
156 let mut ahead: Vec<(i64, CompiledOps)> = spanned
157 .compiled()
158 .iter()
159 .filter(|(span, _)| span.to > at)
160 .map(|(span, compiled_ops)| (span.from, compiled_ops.clone()))
161 .collect();
162 ahead.reverse();
163 let first = match ahead.pop() {
164 Some((_, compiled_ops)) => compiled_ops,
165 None => spanned.silent()?,
166 };
167 let states = open(&first, grid)?;
168 let block = BlockScratch::of(&first.widths);
169 Ok(Machine {
170 compiled_ops: first,
171 states,
172 block,
173 grid,
174 ahead,
175 })
176 }
177
178 pub fn width(&self) -> usize {
179 self.compiled_ops.width
180 }
181
182 pub fn stateful(&self) -> bool {
183 !self.compiled_ops.sites.is_empty()
184 }
185
186 pub fn bytes(&self) -> usize {
187 self.states.iter().map(State::bytes).sum()
188 }
189
190 pub fn run_to(&mut self, to: i64, reads: &[SampleView], own: Own) -> Result<(), SampleError> {
191 for state in &mut self.states {
192 if let State::Filter(filter) = state {
193 filter.forget_frames();
194 }
195 }
196 self.steps(to, reads, own)
197 }
198
199 pub fn run_on(&mut self, to: i64, reads: &[SampleView], own: Own) -> Result<(), SampleError> {
201 self.steps(to, reads, own)
202 }
203
204 fn steps(
205 &mut self,
206 to: i64,
207 reads: &[SampleView],
208 (own, origin): Own,
209 ) -> Result<(), SampleError> {
210 loop {
211 while let Some((from, _)) = self.ahead.last()
212 && *from <= own.end()
213 {
214 let (_, compiled_ops) = self.ahead.pop().expect("a span ahead");
215 self.block = BlockScratch::of(&compiled_ops.widths);
216 self.compiled_ops = compiled_ops;
217 }
218 let until = self.ahead.last().map_or(to, |(from, _)| (*from).min(to));
219 self.stepped(until, reads, (own, origin))?;
220 if own.end() >= to {
221 return Ok(());
222 }
223 }
224 }
225
226 fn stepped(
227 &mut self,
228 to: i64,
229 reads: &[SampleView],
230 (own, origin): Own,
231 ) -> Result<(), SampleError> {
232 let p = &self.compiled_ops;
233 while own.end() < to {
234 let from = own.end();
235 let most = (to - from).min(BLOCK as i64 - from.rem_euclid(BLOCK as i64)) as usize;
236 let len = p.block(from, most, &mut self.block.recurrent);
237 let here = Here {
238 reads,
239 own: own.within(Extent::from(origin)),
240 grid: self.grid,
241 };
242 let (held, refused) =
243 block::run(p, &mut self.block, &here, &mut self.states, (from, len));
244 for i in 0..held {
245 let top = self.block.top(p, i);
246 for c in 0..p.width {
247 own.push(c, part(top, c));
248 }
249 }
250 if let Some(e) = refused {
251 return Err(e);
252 }
253 }
254 Ok(())
255 }
256
257 pub fn solver(&self, site: usize) -> Option<&dyn Solver> {
259 match self.states.get(site)? {
260 State::Physics(solver) => Some(solver.as_ref()),
261 State::Filter(_) => None,
262 }
263 }
264
265 pub fn filter(&self, site: usize) -> Option<&FilterSite> {
266 match self.states.get(site)? {
267 State::Filter(filter) => Some(filter),
268 State::Physics(_) => None,
269 }
270 }
271
272 pub fn state(&self) -> MachineState {
273 MachineState {
274 sites: self.compiled_ops.sites.clone(),
275 states: self.states.clone(),
276 }
277 }
278
279 pub fn restart(&mut self) {
280 self.states = open(&self.compiled_ops, self.grid).expect("the sites opened once already");
281 }
282
283 pub fn accepts(&self, held: &MachineState) -> bool {
285 held.sites == self.compiled_ops.sites
286 }
287
288 pub fn carry(&mut self, held: &MachineState) -> bool {
290 let taken = self.accepts(held);
291 if taken {
292 self.states.clone_from(&held.states);
293 }
294 taken
295 }
296}
297
298impl CompiledOps {
299 fn block(&self, from: i64, most: usize, recurrent: &mut Vec<bool>) -> usize {
302 let reach: Vec<Option<usize>> = self
303 .ops
304 .iter()
305 .map(|op| own_reach(op, from, most))
306 .collect();
307 let len = reach
308 .iter()
309 .flatten()
310 .filter(|n| **n >= RUN)
311 .fold(most, |len, n| len.min(*n))
312 .max(1);
313 recurrent.clear();
314 for (slot, reach) in reach.iter().enumerate() {
315 let reads = self.args[slot].iter().any(|a| recurrent[*a]);
316 recurrent.push(reads || reach.is_some_and(|n| n < len));
317 }
318 len
319 }
320}
321
322fn own_reach(op: &Op, from: i64, most: usize) -> Option<usize> {
324 match op {
325 Op::Read {
326 slot: Slot::Own,
327 at,
328 }
329 | Op::ReadScaled {
330 slot: Slot::Own,
331 at,
332 ..
333 } => {
334 let last = |len: usize| from + len as i64 - 1;
335 let mut len = most;
336 while len > 1 && at.at(from).max(at.at(last(len))) >= from {
337 len /= 2;
338 }
339 Some(match at.at(from).max(at.at(last(len))) < from {
340 true => len,
341 false => 0,
342 })
343 }
344 Op::Indexed {
345 slot: Slot::Own,
346 reach,
347 ..
348 } => Some(match reach {
349 Some((_, most)) if *most < 0 => {
350 usize::try_from(most.unsigned_abs()).unwrap_or(usize::MAX)
351 }
352 _ => 0,
353 }),
354 _ => None,
355 }
356}
357
358const RUN: usize = 16;
360
361#[cfg(test)]
362mod tests {
363 use super::renderer::{BufId, Index, Map, NodeRenderer, Slot};
364 use super::*;
365 use crate::grid::{Extent, Round, WIDE};
366
367 const LONG: [i64; 2] = [1489, 1721];
368
369 fn feedback() -> NodeRenderer {
371 let own = |lag: i64, k: usize| NodeRenderer::Channel {
372 x: Box::new(NodeRenderer::Read {
373 slot: Slot::Own,
374 map: Map::shift(-lag),
375 }),
376 k,
377 };
378 let input = NodeRenderer::Read {
379 slot: Slot::Read(BufId(0)),
380 map: Map::shift(0),
381 };
382 let line = |k: usize| {
383 let mix = LONG
384 .iter()
385 .enumerate()
386 .map(|(j, lag)| NodeRenderer::Mul(vec![NodeRenderer::Const(0.6), own(*lag, j)]));
387 let fed = NodeRenderer::Add(std::iter::once(input.clone()).chain(mix).collect());
388 NodeRenderer::Add(vec![
389 NodeRenderer::Mul(vec![NodeRenderer::Const(0.7), fed]),
390 NodeRenderer::Mul(vec![NodeRenderer::Const(0.2), own(1, k)]),
391 ])
392 };
393 NodeRenderer::Join(vec![line(0), line(1)])
394 }
395
396 fn ran(to: i64) -> Vec<Vec<f64>> {
397 let layout = Layout {
398 grid: Grid::of(48_000),
399 width: 2,
400 read_widths: vec![1],
401 sites: Vec::new(),
402 };
403 let spanned =
404 Spanned::new(&feedback(), &layout, (0, to), &[Extent::EVERYWHERE]).expect("a program");
405 let mut input = Buffer::empty(48_000, 1, to as usize, 0);
406 (0..to).for_each(|n| input.push(0, f64::from(u8::from(n % 4800 == 0))));
407 let mut out = Buffer::empty(48_000, 2, to as usize, 0);
408 let mut machine = Machine::over(&spanned, 0).expect("a machine");
409 machine
410 .run_to(to, &[input.within(Extent::from(0))], (&mut out, 0))
411 .expect("samples");
412 out.planes
413 }
414
415 #[test]
418 fn identical_reads_of_a_loops_own_past_run_once() {
419 let to = 24_000;
420 let layout = Layout {
421 grid: Grid::of(48_000),
422 width: 2,
423 read_widths: vec![1],
424 sites: Vec::new(),
425 };
426 assert_eq!(lowered(&feedback(), &layout).expect("ops").0.ops.len(), 20);
427 let planes = ran(to);
428 let mut y = vec![vec![0.0f64; to as usize]; 2];
429 let past = |y: &[Vec<f64>], k: usize, n: i64| match n {
430 n if n < 0 => 0.0,
431 n => y[k][n as usize],
432 };
433 for n in 0..to {
434 let input = f64::from(u8::from(n % 4800 == 0));
435 let mut fed = 0.0 + input;
436 for (j, lag) in LONG.iter().enumerate() {
437 fed += 1.0 * 0.6 * past(&y, j, n - lag);
438 }
439 for k in 0..2 {
440 y[k][n as usize] = 0.0 + 1.0 * 0.7 * fed + 1.0 * 0.2 * past(&y, k, n - 1);
441 }
442 }
443 let bits = |p: &[Vec<f64>]| -> Vec<Vec<u64>> {
444 p.iter()
445 .map(|c| c.iter().map(|v| v.to_bits()).collect())
446 .collect()
447 };
448 assert_eq!(bits(&planes), bits(&y));
449 }
450
451 fn through_every_op() -> NodeRenderer {
454 use super::renderer::{Binary, Formula, Unary};
455 use NodeRenderer::{Const, Map as Of, Mul};
456 let own = |lag: i64, k: usize| NodeRenderer::Channel {
457 x: Box::new(NodeRenderer::Read {
458 slot: Slot::Own,
459 map: Map::shift(-lag),
460 }),
461 k,
462 };
463 let input = NodeRenderer::Read {
464 slot: Slot::Read(BufId(0)),
465 map: Map::shift(0),
466 };
467 let b = Box::new;
468 let filtered = NodeRenderer::Filter {
469 site: super::renderer::SiteId(0),
470 from: 0,
471 x: b(NodeRenderer::Add(vec![
472 input.clone(),
473 Mul(vec![Const(0.5), own(1, 0)]),
474 ])),
475 cutoff: b(NodeRenderer::Add(vec![
476 Const(800.0),
477 Mul(vec![Const(400.0), Of(Unary::Sin, b(own(1, 1)))]),
478 ])),
479 q: b(Const(0.7)),
480 gain: b(Const(0.0)),
481 };
482 let paired = NodeRenderer::Add(vec![
483 NodeRenderer::Zip(
484 Binary::Max,
485 b(NodeRenderer::Div(b(own(2, 0)), b(Const(3.0)))),
486 b(own(1, 1)),
487 ),
488 NodeRenderer::Pow(b(Const(0.9)), b(own(1, 0))),
489 ]);
490 let cropped = NodeRenderer::Crop {
491 x: b(NodeRenderer::Sub(b(paired), b(Const(0.5)))),
492 window: (100, 20_000),
493 a: 100.0 / 48_000.0,
494 b: 20_000.0 / 48_000.0,
495 rise: 0.01,
496 fall: 0.01,
497 };
498 let drawn = NodeRenderer::Formula {
499 formula: Formula::Drawn {
500 seed: 7,
501 rate: 1_000,
502 },
503 width: 1,
504 time: b(NodeRenderer::Add(vec![
505 NodeRenderer::Time,
506 Mul(vec![Const(0.000_1), own(1, 0)]),
507 ])),
508 };
509 let back = || {
510 let length = NodeRenderer::Add(vec![
511 Const(0.000_2),
512 Mul(vec![Const(0.000_1), Of(Unary::Sin, b(own(1, 1)))]),
513 ]);
514 Index::Add(vec![
515 Index::At(Map::whole(1, 0)),
516 Index::Neg(Box::new(Index::Step(b(length), Round::Floor))),
517 ])
518 };
519 let delayed = NodeRenderer::Indexed {
520 slot: Slot::Own,
521 index: back(),
522 reach: Some((-14, -4)),
523 };
524 let lag = NodeRenderer::Sub(b(NodeRenderer::Time), b(NodeRenderer::Instant(back())));
525 NodeRenderer::Join(vec![
526 NodeRenderer::Add(vec![
527 Mul(vec![Const(0.3), filtered]),
528 Mul(vec![Const(0.2), cropped]),
529 Mul(vec![Const(0.1), drawn]),
530 Mul(vec![
531 Const(0.3),
532 NodeRenderer::Channel {
533 x: b(delayed),
534 k: 1,
535 },
536 ]),
537 ]),
538 NodeRenderer::Add(vec![
539 Mul(vec![Const(0.5), input]),
540 Mul(vec![Const(0.4), own(1, 1)]),
541 Mul(vec![Const(10.0), lag]),
542 ]),
543 ])
544 }
545
546 #[test]
549 fn a_loop_through_every_op_writes_what_a_sample_at_a_time_run_does() {
550 let to = 12_000;
551 let layout = Layout {
552 grid: Grid::of(48_000),
553 width: 2,
554 read_widths: vec![1],
555 sites: vec![Site::Filter(sva_formula::Shape::Lowpass)],
556 };
557 let spanned = Spanned::new(&through_every_op(), &layout, (0, to), &[Extent::EVERYWHERE])
558 .expect("a program");
559 let mut input = Buffer::empty(48_000, 1, to as usize, 0);
560 (0..to).for_each(|n| input.push(0, f64::from(u8::from(n % 2400 == 0))));
561 let run = |step: i64| {
562 let mut out = Buffer::empty(48_000, 2, to as usize, 0);
563 let mut machine = Machine::over(&spanned, 0).expect("a machine");
564 let mut at = 0;
565 while at < to {
566 at = (at + step).min(to);
567 machine
568 .run_to(at, &[input.within(Extent::from(0))], (&mut out, 0))
569 .expect("samples");
570 }
571 let bits = out.planes.iter().flatten().map(|v| v.to_bits());
572 bits.collect::<Vec<u64>>()
573 };
574 let whole = run(to);
575 assert!(whole.iter().all(|v| f64::from_bits(*v).is_finite()));
576 assert_eq!(whole, run(1));
577 assert_eq!(whole, run(37));
578 }
579
580 fn delayed() -> NodeRenderer {
582 let now = Index::At(Map::whole(1, 0));
583 let length = NodeRenderer::Add(vec![
584 NodeRenderer::Const(0.002),
585 NodeRenderer::Mul(vec![
586 NodeRenderer::Const(0.000_2),
587 NodeRenderer::Map(
588 super::renderer::Unary::Sin,
589 Box::new(NodeRenderer::Mul(vec![
590 NodeRenderer::Const(18.85),
591 NodeRenderer::Time,
592 ])),
593 ),
594 ]),
595 ]);
596 let back = Index::Neg(Box::new(Index::Step(Box::new(length), Round::Floor)));
597 let echo = Index::Add(vec![now.clone(), Index::At(Map::whole(0, -1489))]);
598 NodeRenderer::Add(vec![
599 NodeRenderer::Indexed {
600 slot: Slot::Read(BufId(0)),
601 index: Index::Add(vec![now, back]),
602 reach: None,
603 },
604 NodeRenderer::Mul(vec![
605 NodeRenderer::Const(0.5),
606 NodeRenderer::Indexed {
607 slot: Slot::Own,
608 index: echo,
609 reach: Some((-1489, -1489)),
610 },
611 ]),
612 ])
613 }
614
615 #[test]
618 fn a_delay_and_an_echo_round_no_index_in_wide_integers() {
619 let to = 9_600;
620 let layout = Layout {
621 grid: Grid::of(48_000),
622 width: 1,
623 read_widths: vec![1],
624 sites: Vec::new(),
625 };
626 let spanned =
627 Spanned::new(&delayed(), &layout, (0, to), &[Extent::EVERYWHERE]).expect("a program");
628 let mut input = Buffer::empty(48_000, 1, to as usize, 0);
629 (0..to).for_each(|n| input.push(0, (n as f64 * 0.01).sin()));
630 let mut out = Buffer::empty(48_000, 1, to as usize, 0);
631 let mut machine = Machine::over(&spanned, 0).expect("a machine");
632 let before = WIDE.with(std::cell::Cell::get);
633 machine
634 .run_to(to, &[input.within(Extent::from(0))], (&mut out, 0))
635 .expect("samples");
636 assert_eq!(WIDE.with(std::cell::Cell::get), before);
637 }
638}