|
1 | 1 | use caw_core::{Buf, Sig, SigCtx, SigT}; |
2 | 2 | use itertools::izip; |
3 | 3 |
|
4 | | -struct SequenceLooper<X, S, T, R, N> |
| 4 | +#[derive(Default)] |
| 5 | +struct Sequence<T> { |
| 6 | + sequence: Vec<T>, |
| 7 | + index: usize, |
| 8 | +} |
| 9 | + |
| 10 | +impl<T> Sequence<T> { |
| 11 | + fn tick(&mut self) { |
| 12 | + assert!(self.sequence.len() > 0); |
| 13 | + self.index = (self.index + 1) % self.sequence.len(); |
| 14 | + } |
| 15 | + |
| 16 | + fn current(&self) -> &T { |
| 17 | + &self.sequence[self.index] |
| 18 | + } |
| 19 | + |
| 20 | + fn current_mut(&mut self) -> &mut T { |
| 21 | + &mut self.sequence[self.index] |
| 22 | + } |
| 23 | + |
| 24 | + fn resize_with<F: FnMut() -> T>(&mut self, length: usize, f: F) { |
| 25 | + if length != self.sequence.len() { |
| 26 | + let length = length.max(1); |
| 27 | + self.sequence.resize_with(length, f); |
| 28 | + if self.index >= length { |
| 29 | + self.index = 0; |
| 30 | + } |
| 31 | + } |
| 32 | + } |
| 33 | + |
| 34 | + fn new_with<F: FnMut() -> T>(length: usize, f: F) -> Self { |
| 35 | + let length = length.max(1); |
| 36 | + let mut sequence = Vec::new(); |
| 37 | + sequence.resize_with(length, f); |
| 38 | + Self { sequence, index: 0 } |
| 39 | + } |
| 40 | +} |
| 41 | + |
| 42 | +struct KeyLooper<X, S, T, C, N> |
5 | 43 | where |
6 | 44 | X: Clone, |
7 | 45 | S: SigT<Item = Option<X>>, |
8 | 46 | T: SigT<Item = bool>, |
9 | | - R: SigT<Item = bool>, |
| 47 | + C: SigT<Item = bool>, |
10 | 48 | N: SigT<Item = u32>, |
11 | 49 | { |
12 | 50 | sig: S, |
| 51 | + last_value: S::Item, |
13 | 52 | tick: T, |
14 | | - recording: R, |
| 53 | + clearing: C, |
15 | 54 | length: N, |
16 | | - sequence: Vec<S::Item>, |
| 55 | + sequence: Sequence<S::Item>, |
17 | 56 | buf: Vec<S::Item>, |
18 | 57 | } |
19 | 58 |
|
20 | | -impl<X, S, T, R, N> SigT for SequenceLooper<X, S, T, R, N> |
| 59 | +impl<X, S, T, C, N> SigT for KeyLooper<X, S, T, C, N> |
21 | 60 | where |
22 | 61 | X: Clone, |
23 | 62 | S: SigT<Item = Option<X>>, |
24 | 63 | T: SigT<Item = bool>, |
25 | | - R: SigT<Item = bool>, |
| 64 | + C: SigT<Item = bool>, |
26 | 65 | N: SigT<Item = u32>, |
27 | 66 | { |
28 | 67 | type Item = S::Item; |
29 | 68 |
|
30 | 69 | fn sample(&mut self, ctx: &SigCtx) -> impl Buf<Self::Item> { |
| 70 | + self.buf.clear(); |
31 | 71 | self.buf.resize_with(ctx.num_samples, || None); |
32 | 72 | let sig = self.sig.sample(ctx); |
33 | 73 | let tick = self.tick.sample(ctx); |
34 | | - let recording = self.recording.sample(ctx); |
| 74 | + let clearing = self.clearing.sample(ctx); |
35 | 75 | let length = self.length.sample(ctx); |
36 | | - for (out, sample, tick, recording, length) in izip! { |
| 76 | + for (out, sample, tick, clearing, length) in izip! { |
37 | 77 | self.buf.iter_mut(), |
38 | 78 | sig.iter(), |
39 | 79 | tick.iter(), |
40 | | - recording.iter(), |
| 80 | + clearing.iter(), |
41 | 81 | length.iter(), |
42 | 82 | } { |
43 | | - *out = sample; |
| 83 | + self.sequence.resize_with(length as usize, || None); |
| 84 | + if tick { |
| 85 | + self.sequence.tick(); |
| 86 | + self.last_value = None; |
| 87 | + } else if sample.is_some() { |
| 88 | + self.last_value = sample.clone(); |
| 89 | + } |
| 90 | + if clearing { |
| 91 | + *self.sequence.current_mut() = None; |
| 92 | + } else if self.last_value.is_some() { |
| 93 | + *self.sequence.current_mut() = self.last_value.clone(); |
| 94 | + } |
| 95 | + *out = self.sequence.current().clone(); |
44 | 96 | } |
45 | 97 | &self.buf |
46 | 98 | } |
47 | 99 | } |
48 | 100 |
|
49 | | -pub fn sequence_looper<X: Clone>( |
| 101 | +pub fn key_looper<X: Clone>( |
50 | 102 | sig: impl SigT<Item = Option<X>>, |
51 | 103 | tick: impl SigT<Item = bool>, |
52 | | - recording: impl SigT<Item = bool>, |
| 104 | + clearing: impl SigT<Item = bool>, |
53 | 105 | length: impl SigT<Item = u32>, |
54 | 106 | ) -> Sig<impl SigT<Item = Option<X>>> { |
55 | | - Sig(SequenceLooper { |
| 107 | + Sig(KeyLooper { |
| 108 | + sig, |
| 109 | + last_value: None, |
| 110 | + tick, |
| 111 | + clearing, |
| 112 | + length, |
| 113 | + sequence: Sequence::new_with(1, || None), |
| 114 | + buf: Vec::new(), |
| 115 | + }) |
| 116 | +} |
| 117 | + |
| 118 | +struct ValueLooper<S, T, R, N> |
| 119 | +where |
| 120 | + S: SigT, |
| 121 | + S::Item: Clone, |
| 122 | + T: SigT<Item = bool>, |
| 123 | + R: SigT<Item = bool>, |
| 124 | + N: SigT<Item = u32>, |
| 125 | +{ |
| 126 | + sig: S, |
| 127 | + tick: T, |
| 128 | + recording: R, |
| 129 | + length: N, |
| 130 | + sequence: Sequence<Option<S::Item>>, |
| 131 | + buf: Vec<S::Item>, |
| 132 | +} |
| 133 | + |
| 134 | +impl<S, T, R, N> SigT for ValueLooper<S, T, R, N> |
| 135 | +where |
| 136 | + S: SigT, |
| 137 | + S::Item: Clone, |
| 138 | + T: SigT<Item = bool>, |
| 139 | + R: SigT<Item = bool>, |
| 140 | + N: SigT<Item = u32>, |
| 141 | +{ |
| 142 | + type Item = S::Item; |
| 143 | + |
| 144 | + fn sample(&mut self, ctx: &SigCtx) -> impl Buf<Self::Item> { |
| 145 | + self.buf.clear(); |
| 146 | + let sig = self.sig.sample(ctx); |
| 147 | + let tick = self.tick.sample(ctx); |
| 148 | + let recording = self.recording.sample(ctx); |
| 149 | + let length = self.length.sample(ctx); |
| 150 | + for (sample, tick, recording, length) in izip! { |
| 151 | + sig.iter(), |
| 152 | + tick.iter(), |
| 153 | + recording.iter(), |
| 154 | + length.iter(), |
| 155 | + } { |
| 156 | + self.sequence.resize_with(length as usize, || None); |
| 157 | + if tick { |
| 158 | + self.sequence.tick(); |
| 159 | + } |
| 160 | + let stored = self.sequence.current_mut(); |
| 161 | + let out = match (recording, stored.clone()) { |
| 162 | + (true, _) | (_, None) => { |
| 163 | + *stored = Some(sample.clone()); |
| 164 | + sample |
| 165 | + } |
| 166 | + (_, Some(stored)) => stored, |
| 167 | + }; |
| 168 | + self.buf.push(out); |
| 169 | + } |
| 170 | + &self.buf |
| 171 | + } |
| 172 | +} |
| 173 | + |
| 174 | +pub fn value_looper<T: Clone>( |
| 175 | + sig: impl SigT<Item = T>, |
| 176 | + tick: impl SigT<Item = bool>, |
| 177 | + recording: impl SigT<Item = bool>, |
| 178 | + length: impl SigT<Item = u32>, |
| 179 | +) -> Sig<impl SigT<Item = T>> { |
| 180 | + Sig(ValueLooper { |
56 | 181 | sig, |
57 | 182 | tick, |
58 | 183 | recording, |
59 | 184 | length, |
60 | | - sequence: Vec::new(), |
| 185 | + sequence: Sequence::new_with(1, || None), |
61 | 186 | buf: Vec::new(), |
62 | 187 | }) |
63 | 188 | } |
0 commit comments