Skip to main content

sva_samples/machine/
tape.rs

1// Concern: one node's output over a trailing span of the grid, and a view of any span | Non-concern: what writes it, how far back a reader reaches | IO: (component, index) -> f64
2
3use crate::buffer::Buffer;
4use crate::collapse::Extent;
5
6/// Samples `[base, end)` of one node's output; it is silent before `origin`.
7#[derive(Clone, Debug, PartialEq)]
8pub struct Tape {
9    planes: Vec<Vec<f64>>,
10    base: i64,
11    origin: i64,
12}
13
14impl Tape {
15    pub fn new(width: usize, capacity: usize, origin: i64) -> Tape {
16        Tape {
17            planes: (0..width.max(1))
18                .map(|_| Vec::with_capacity(capacity))
19                .collect(),
20            base: origin,
21            origin,
22        }
23    }
24
25    pub fn width(&self) -> usize {
26        self.planes.len()
27    }
28
29    pub fn base(&self) -> i64 {
30        self.base
31    }
32
33    pub fn origin(&self) -> i64 {
34        self.origin
35    }
36
37    pub fn planes(&self) -> &[Vec<f64>] {
38        &self.planes
39    }
40
41    pub fn capacity(&self) -> usize {
42        self.planes[0].capacity()
43    }
44
45    pub fn end(&self) -> i64 {
46        self.base + self.planes[0].len() as i64
47    }
48
49    pub fn window(&self) -> Window<'_> {
50        self.within(Extent::from(self.origin))
51    }
52
53    pub fn within(&self, support: Extent) -> Window<'_> {
54        Window {
55            planes: &self.planes,
56            base: self.base,
57            support,
58            period: None,
59            offset: 0,
60        }
61    }
62
63    pub fn since(&self, c: usize, from: i64) -> &[f64] {
64        &self.planes[c][(from - self.base) as usize..]
65    }
66
67    pub fn push(&mut self, c: usize, value: f64) {
68        self.planes[c].push(value);
69    }
70
71    /// Everything from `end` on dropped.
72    pub fn cut(&mut self, end: i64) {
73        let kept = (end - self.base).clamp(0, self.planes[0].len() as i64) as usize;
74        for plane in &mut self.planes {
75            plane.truncate(kept);
76        }
77    }
78
79    pub fn forget_before(&mut self, from: i64) {
80        let gone = (from - self.base).clamp(0, self.planes[0].len() as i64) as usize;
81        if gone == 0 {
82            return;
83        }
84        for plane in &mut self.planes {
85            plane.drain(..gone);
86        }
87        self.base += gone as i64;
88    }
89
90    pub fn into_planes(self) -> Vec<Vec<f64>> {
91        self.planes
92    }
93
94    pub fn into_buffer(self, rate: u32) -> Buffer {
95        let mut out = Buffer::of_planes(rate, self.planes);
96        out.start = self.base;
97        out
98    }
99}
100
101/// A buffer held whole, silent before it starts.
102impl From<Buffer> for Tape {
103    fn from(buffer: Buffer) -> Tape {
104        Tape {
105            planes: buffer.planes,
106            base: buffer.start,
107            origin: buffer.start,
108        }
109    }
110}
111
112/// A view of held samples; a periodic value's samples are held over one period from 0, and
113/// sample `k` is sample `k mod period`.
114#[derive(Clone, Copy, Debug)]
115pub struct Window<'a> {
116    planes: &'a [Vec<f64>],
117    base: i64,
118    support: Extent,
119    period: Option<i64>,
120    /// Sample `k` of the view is sample `k + offset` of what it views.
121    offset: i64,
122}
123
124impl<'a> Window<'a> {
125    pub fn of(buffer: &'a Buffer, support: Extent) -> Window<'a> {
126        Window {
127            planes: &buffer.planes,
128            base: buffer.start,
129            support,
130            period: None,
131            offset: 0,
132        }
133    }
134
135    pub fn folded(self, period: Option<i64>) -> Window<'a> {
136        Window { period, ..self }
137    }
138
139    pub fn shifted(self, by: i64) -> Window<'a> {
140        Window {
141            offset: self.offset + by,
142            ..self
143        }
144    }
145
146    fn fold(&self, k: i64) -> i64 {
147        let k = k.saturating_add(self.offset);
148        match self.period {
149            Some(n) if self.support.contains(k) => k.rem_euclid(n),
150            _ => k,
151        }
152    }
153
154    /// `None` for a sample inside the support this window does not hold.
155    pub fn get(&self, c: usize, k: i64) -> Option<f64> {
156        let k = self.fold(k);
157        let plane = &self.planes[c];
158        let held = k
159            .checked_sub(self.base)
160            .and_then(|at| usize::try_from(at).ok())
161            .and_then(|at| plane.get(at));
162        match held {
163            Some(v) => Some(*v),
164            None => (!self.support.contains(k)).then_some(0.0),
165        }
166    }
167
168    /// Samples `[k, k + len)` of component `c`, where held unfolded.
169    pub fn run(&self, c: usize, k: i64, len: usize) -> Option<&'a [f64]> {
170        if self.period.is_some() {
171            return None;
172        }
173        let at = usize::try_from(k.checked_add(self.offset)?.checked_sub(self.base)?).ok()?;
174        self.planes.get(c)?.get(at..at.checked_add(len)?)
175    }
176
177    /// A sample not held inside the support is a reader past its extent.
178    pub fn at(&self, c: usize, k: i64) -> f64 {
179        let k = self.fold(k);
180        let plane = &self.planes[c];
181        if let Some(held) = k
182            .checked_sub(self.base)
183            .and_then(|at| usize::try_from(at).ok())
184            .and_then(|at| plane.get(at))
185        {
186            return *held;
187        }
188        if !self.support.contains(k) {
189            return 0.0;
190        }
191        panic!(
192            "sample {k} is not held: this node holds [{}, {}) and is nonzero over [{}, {})",
193            self.base,
194            self.base + plane.len() as i64,
195            self.support.start,
196            self.support.end
197        )
198    }
199}