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 if p.width != own.width() {
234 return Err(SampleError::OwnWidth {
235 writes: p.width,
236 holds: own.width(),
237 });
238 }
239 while own.end() < to {
240 let from = own.end();
241 let most = (to - from).min(BLOCK as i64 - from.rem_euclid(BLOCK as i64)) as usize;
242 let len = p.block(from, most, &mut self.block.recurrent);
243 let here = Here {
244 reads,
245 own: own.within(Extent::from(origin)),
246 grid: self.grid,
247 };
248 let (held, refused) =
249 block::run(p, &mut self.block, &here, &mut self.states, (from, len));
250 for i in 0..held {
251 let top = self.block.top(p, i);
252 for c in 0..p.width {
253 own.push(c, part(top, c));
254 }
255 }
256 if let Some(e) = refused {
257 return Err(e);
258 }
259 }
260 Ok(())
261 }
262
263 pub fn solver(&self, site: usize) -> Option<&dyn Solver> {
265 match self.states.get(site)? {
266 State::Physics(solver) => Some(solver.as_ref()),
267 State::Filter(_) => None,
268 }
269 }
270
271 pub fn filter(&self, site: usize) -> Option<&FilterSite> {
272 match self.states.get(site)? {
273 State::Filter(filter) => Some(filter),
274 State::Physics(_) => None,
275 }
276 }
277
278 pub fn state(&self) -> MachineState {
279 MachineState {
280 sites: self.compiled_ops.sites.clone(),
281 states: self.states.clone(),
282 }
283 }
284
285 pub fn restart(&mut self) {
286 self.states = open(&self.compiled_ops, self.grid).expect("the sites opened once already");
287 }
288
289 pub fn accepts(&self, held: &MachineState) -> bool {
291 held.sites == self.compiled_ops.sites
292 }
293
294 pub fn carry(&mut self, held: &MachineState) -> bool {
296 let taken = self.accepts(held);
297 if taken {
298 self.states.clone_from(&held.states);
299 }
300 taken
301 }
302}
303
304impl CompiledOps {
305 fn block(&self, from: i64, most: usize, recurrent: &mut Vec<bool>) -> usize {
308 let reach: Vec<Option<usize>> = self
309 .ops
310 .iter()
311 .map(|op| own_reach(op, from, most))
312 .collect();
313 let len = reach
314 .iter()
315 .flatten()
316 .filter(|n| **n >= RUN)
317 .fold(most, |len, n| len.min(*n))
318 .max(1);
319 recurrent.clear();
320 for (slot, reach) in reach.iter().enumerate() {
321 let reads = self.args[slot].iter().any(|a| recurrent[*a]);
322 recurrent.push(reads || reach.is_some_and(|n| n < len));
323 }
324 len
325 }
326}
327
328fn own_reach(op: &Op, from: i64, most: usize) -> Option<usize> {
330 match op {
331 Op::Read {
332 slot: Slot::Own,
333 at,
334 }
335 | Op::ReadScaled {
336 slot: Slot::Own,
337 at,
338 ..
339 } => {
340 let last = |len: usize| from + len as i64 - 1;
341 let mut len = most;
342 while len > 1 && at.at(from).max(at.at(last(len))) >= from {
343 len /= 2;
344 }
345 Some(match at.at(from).max(at.at(last(len))) < from {
346 true => len,
347 false => 0,
348 })
349 }
350 Op::Indexed {
351 slot: Slot::Own,
352 reach,
353 ..
354 } => Some(match reach {
355 Some((_, most)) if *most < 0 => {
356 usize::try_from(most.unsigned_abs()).unwrap_or(usize::MAX)
357 }
358 _ => 0,
359 }),
360 _ => None,
361 }
362}
363
364const RUN: usize = 16;
366
367#[cfg(test)]
368mod tests {
369 use super::renderer::{BufId, Index, Map, NodeRenderer, Slot};
370 use super::*;
371 use crate::grid::{Extent, Round, WIDE};
372
373 const LONG: [i64; 2] = [1489, 1721];
374
375 fn feedback() -> NodeRenderer {
377 let own = |lag: i64, k: usize| NodeRenderer::Channel {
378 x: Box::new(NodeRenderer::Read {
379 slot: Slot::Own,
380 map: Map::shift(-lag),
381 }),
382 k,
383 };
384 let input = NodeRenderer::Read {
385 slot: Slot::Read(BufId(0)),
386 map: Map::shift(0),
387 };
388 let line = |k: usize| {
389 let mix = LONG
390 .iter()
391 .enumerate()
392 .map(|(j, lag)| NodeRenderer::Mul(vec![NodeRenderer::Const(0.6), own(*lag, j)]));
393 let fed = NodeRenderer::Add(std::iter::once(input.clone()).chain(mix).collect());
394 NodeRenderer::Add(vec![
395 NodeRenderer::Mul(vec![NodeRenderer::Const(0.7), fed]),
396 NodeRenderer::Mul(vec![NodeRenderer::Const(0.2), own(1, k)]),
397 ])
398 };
399 NodeRenderer::Join(vec![line(0), line(1)])
400 }
401
402 fn ran(to: i64) -> Vec<Vec<f64>> {
403 let layout = Layout {
404 grid: Grid::of(48_000),
405 width: 2,
406 read_widths: vec![1],
407 sites: Vec::new(),
408 };
409 let spanned =
410 Spanned::new(&feedback(), &layout, (0, to), &[Extent::EVERYWHERE]).expect("a program");
411 let mut input = Buffer::empty(48_000, 1, to as usize, 0);
412 (0..to).for_each(|n| input.push(0, f64::from(u8::from(n % 4800 == 0))));
413 let mut out = Buffer::empty(48_000, 2, to as usize, 0);
414 let mut machine = Machine::over(&spanned, 0).expect("a machine");
415 machine
416 .run_to(to, &[input.within(Extent::from(0))], (&mut out, 0))
417 .expect("samples");
418 out.planes
419 }
420
421 #[test]
424 fn identical_reads_of_a_loops_own_past_run_once() {
425 let to = 24_000;
426 let layout = Layout {
427 grid: Grid::of(48_000),
428 width: 2,
429 read_widths: vec![1],
430 sites: Vec::new(),
431 };
432 assert_eq!(lowered(&feedback(), &layout).expect("ops").0.ops.len(), 20);
433 let planes = ran(to);
434 let mut y = vec![vec![0.0f64; to as usize]; 2];
435 let past = |y: &[Vec<f64>], k: usize, n: i64| match n {
436 n if n < 0 => 0.0,
437 n => y[k][n as usize],
438 };
439 for n in 0..to {
440 let input = f64::from(u8::from(n % 4800 == 0));
441 let mut fed = 0.0 + input;
442 for (j, lag) in LONG.iter().enumerate() {
443 fed += 1.0 * 0.6 * past(&y, j, n - lag);
444 }
445 for k in 0..2 {
446 y[k][n as usize] = 0.0 + 1.0 * 0.7 * fed + 1.0 * 0.2 * past(&y, k, n - 1);
447 }
448 }
449 let bits = |p: &[Vec<f64>]| -> Vec<Vec<u64>> {
450 p.iter()
451 .map(|c| c.iter().map(|v| v.to_bits()).collect())
452 .collect()
453 };
454 assert_eq!(bits(&planes), bits(&y));
455 }
456
457 fn through_every_op() -> NodeRenderer {
460 use super::renderer::{Binary, Formula, Unary};
461 use NodeRenderer::{Const, Map as Of, Mul};
462 let own = |lag: i64, k: usize| NodeRenderer::Channel {
463 x: Box::new(NodeRenderer::Read {
464 slot: Slot::Own,
465 map: Map::shift(-lag),
466 }),
467 k,
468 };
469 let input = NodeRenderer::Read {
470 slot: Slot::Read(BufId(0)),
471 map: Map::shift(0),
472 };
473 let b = Box::new;
474 let filtered = NodeRenderer::Filter {
475 site: super::renderer::SiteId(0),
476 from: 0,
477 x: b(NodeRenderer::Add(vec![
478 input.clone(),
479 Mul(vec![Const(0.5), own(1, 0)]),
480 ])),
481 cutoff: b(NodeRenderer::Add(vec![
482 Const(800.0),
483 Mul(vec![Const(400.0), Of(Unary::Sin, b(own(1, 1)))]),
484 ])),
485 q: b(Const(0.7)),
486 gain: b(Const(0.0)),
487 };
488 let paired = NodeRenderer::Add(vec![
489 NodeRenderer::Zip(
490 Binary::Max,
491 b(NodeRenderer::Div(b(own(2, 0)), b(Const(3.0)))),
492 b(own(1, 1)),
493 ),
494 NodeRenderer::Pow(b(Const(0.9)), b(own(1, 0))),
495 ]);
496 let cropped = NodeRenderer::Crop {
497 x: b(NodeRenderer::Sub(b(paired), b(Const(0.5)))),
498 window: (100, 20_000),
499 a: 100.0 / 48_000.0,
500 b: 20_000.0 / 48_000.0,
501 rise: 0.01,
502 fall: 0.01,
503 };
504 let drawn = NodeRenderer::Formula {
505 formula: Formula::Drawn {
506 seed: 7,
507 rate: 1_000,
508 },
509 width: 1,
510 time: b(NodeRenderer::Add(vec![
511 NodeRenderer::Time,
512 Mul(vec![Const(0.000_1), own(1, 0)]),
513 ])),
514 };
515 let back = || {
516 let length = NodeRenderer::Add(vec![
517 Const(0.000_2),
518 Mul(vec![Const(0.000_1), Of(Unary::Sin, b(own(1, 1)))]),
519 ]);
520 Index::Add(vec![
521 Index::At(Map::whole(1, 0)),
522 Index::Neg(Box::new(Index::Step(b(length), Round::Floor))),
523 ])
524 };
525 let delayed = NodeRenderer::Indexed {
526 slot: Slot::Own,
527 index: back(),
528 reach: Some((-14, -4)),
529 };
530 let lag = NodeRenderer::Sub(b(NodeRenderer::Time), b(NodeRenderer::Instant(back())));
531 NodeRenderer::Join(vec![
532 NodeRenderer::Add(vec![
533 Mul(vec![Const(0.3), filtered]),
534 Mul(vec![Const(0.2), cropped]),
535 Mul(vec![Const(0.1), drawn]),
536 Mul(vec![
537 Const(0.3),
538 NodeRenderer::Channel {
539 x: b(delayed),
540 k: 1,
541 },
542 ]),
543 ]),
544 NodeRenderer::Add(vec![
545 Mul(vec![Const(0.5), input]),
546 Mul(vec![Const(0.4), own(1, 1)]),
547 Mul(vec![Const(10.0), lag]),
548 ]),
549 ])
550 }
551
552 #[test]
555 fn a_loop_through_every_op_writes_what_a_sample_at_a_time_run_does() {
556 let to = 12_000;
557 let layout = Layout {
558 grid: Grid::of(48_000),
559 width: 2,
560 read_widths: vec![1],
561 sites: vec![Site::Filter(sva_formula::Shape::Lowpass)],
562 };
563 let spanned = Spanned::new(&through_every_op(), &layout, (0, to), &[Extent::EVERYWHERE])
564 .expect("a program");
565 let mut input = Buffer::empty(48_000, 1, to as usize, 0);
566 (0..to).for_each(|n| input.push(0, f64::from(u8::from(n % 2400 == 0))));
567 let run = |step: i64| {
568 let mut out = Buffer::empty(48_000, 2, to as usize, 0);
569 let mut machine = Machine::over(&spanned, 0).expect("a machine");
570 let mut at = 0;
571 while at < to {
572 at = (at + step).min(to);
573 machine
574 .run_to(at, &[input.within(Extent::from(0))], (&mut out, 0))
575 .expect("samples");
576 }
577 let bits = out.planes.iter().flatten().map(|v| v.to_bits());
578 bits.collect::<Vec<u64>>()
579 };
580 let whole = run(to);
581 assert!(whole.iter().all(|v| f64::from_bits(*v).is_finite()));
582 assert_eq!(whole, run(1));
583 assert_eq!(whole, run(37));
584 }
585
586 fn delayed() -> NodeRenderer {
588 let now = Index::At(Map::whole(1, 0));
589 let length = NodeRenderer::Add(vec![
590 NodeRenderer::Const(0.002),
591 NodeRenderer::Mul(vec![
592 NodeRenderer::Const(0.000_2),
593 NodeRenderer::Map(
594 super::renderer::Unary::Sin,
595 Box::new(NodeRenderer::Mul(vec![
596 NodeRenderer::Const(18.85),
597 NodeRenderer::Time,
598 ])),
599 ),
600 ]),
601 ]);
602 let back = Index::Neg(Box::new(Index::Step(Box::new(length), Round::Floor)));
603 let echo = Index::Add(vec![now.clone(), Index::At(Map::whole(0, -1489))]);
604 NodeRenderer::Add(vec![
605 NodeRenderer::Indexed {
606 slot: Slot::Read(BufId(0)),
607 index: Index::Add(vec![now, back]),
608 reach: None,
609 },
610 NodeRenderer::Mul(vec![
611 NodeRenderer::Const(0.5),
612 NodeRenderer::Indexed {
613 slot: Slot::Own,
614 index: echo,
615 reach: Some((-1489, -1489)),
616 },
617 ]),
618 ])
619 }
620
621 #[test]
624 fn a_delay_and_an_echo_round_no_index_in_wide_integers() {
625 let to = 9_600;
626 let layout = Layout {
627 grid: Grid::of(48_000),
628 width: 1,
629 read_widths: vec![1],
630 sites: Vec::new(),
631 };
632 let spanned =
633 Spanned::new(&delayed(), &layout, (0, to), &[Extent::EVERYWHERE]).expect("a program");
634 let mut input = Buffer::empty(48_000, 1, to as usize, 0);
635 (0..to).for_each(|n| input.push(0, (n as f64 * 0.01).sin()));
636 let mut out = Buffer::empty(48_000, 1, to as usize, 0);
637 let mut machine = Machine::over(&spanned, 0).expect("a machine");
638 let before = WIDE.with(std::cell::Cell::get);
639 machine
640 .run_to(to, &[input.within(Extent::from(0))], (&mut out, 0))
641 .expect("samples");
642 assert_eq!(WIDE.with(std::cell::Cell::get), before);
643 }
644}