1use std::fmt;
4
5#[derive(Clone, Debug, PartialEq)]
7pub enum Until {
8 Holds(Term, Cmp, Term),
9 All(Box<Until>, Box<Until>),
10 Any(Box<Until>, Box<Until>),
11}
12
13#[derive(Clone, Copy, Debug, PartialEq)]
15pub enum Term {
16 Time,
17 Number(f64),
18 Envelope,
19}
20
21#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub enum Cmp {
23 Lt,
24 Le,
25 Gt,
26 Ge,
27}
28
29impl Cmp {
30 fn holds(self, a: f64, b: f64) -> bool {
31 match self {
32 Cmp::Lt => a < b,
33 Cmp::Le => a <= b,
34 Cmp::Gt => a > b,
35 Cmp::Ge => a >= b,
36 }
37 }
38}
39
40impl Until {
41 pub fn checked(&self) -> Result<(), String> {
42 match self {
43 Until::All(a, b) | Until::Any(a, b) => {
44 a.checked()?;
45 b.checked()
46 }
47 Until::Holds(Term::Time, _, Term::Time) => Err("`t` compares with a number".into()),
48 Until::Holds(Term::Time, _, Term::Envelope)
49 | Until::Holds(Term::Envelope, _, Term::Time) => {
50 Err("`t` is a time and `envelope(t)` a level".into())
51 }
52 Until::Holds(..) => Ok(()),
53 }
54 }
55
56 fn times(&self, out: &mut Vec<f64>) {
57 match self {
58 Until::All(a, b) | Until::Any(a, b) => {
59 a.times(out);
60 b.times(out);
61 }
62 Until::Holds(Term::Time, _, Term::Number(v))
63 | Until::Holds(Term::Number(v), _, Term::Time) => out.push(*v),
64 Until::Holds(..) => {}
65 }
66 }
67
68 pub(crate) fn first(&self, known: &Known, from: i64, to: i64) -> Option<i64> {
70 let frame = known.frame as i64;
71 let first_frame = (from - known.start).div_euclid(frame);
72 let mut candidates: Vec<i64> = (first_frame..)
73 .map(|k| known.start + k * frame)
74 .take_while(|n| *n < to)
75 .map(|n| n.max(from))
76 .collect();
77 let mut times = Vec::new();
78 self.times(&mut times);
79 let sr = f64::from(known.rate);
80 for v in times {
81 let n = (v * sr).round() as i64;
82 candidates.extend((n - 1..=n + 1).filter(|n| (from..to).contains(n)));
83 }
84 candidates.sort_unstable();
85 candidates.dedup();
86 candidates
87 .into_iter()
88 .find(|n| self.holds(known, *n) == Some(true))
89 }
90
91 fn holds(&self, known: &Known, n: i64) -> Option<bool> {
92 match self {
93 Until::All(a, b) => match (a.holds(known, n), b.holds(known, n)) {
94 (Some(false), _) | (_, Some(false)) => Some(false),
95 (Some(true), Some(true)) => Some(true),
96 _ => None,
97 },
98 Until::Any(a, b) => match (a.holds(known, n), b.holds(known, n)) {
99 (Some(true), _) | (_, Some(true)) => Some(true),
100 (Some(false), Some(false)) => Some(false),
101 _ => None,
102 },
103 Until::Holds(a, cmp, b) => Some(cmp.holds(known.value(*a, n)?, known.value(*b, n)?)),
104 }
105 }
106}
107
108pub(crate) struct Known<'a> {
111 planes: Vec<&'a [f64]>,
112 base: i64,
113 start: i64,
114 frame: usize,
115 rate: u32,
116 ended: bool,
117}
118
119impl<'a> Known<'a> {
120 pub(crate) fn new(
121 planes: Vec<&'a [f64]>,
122 base: i64,
123 start: i64,
124 frame: usize,
125 rate: u32,
126 ended: bool,
127 ) -> Self {
128 Known {
129 planes,
130 base,
131 start,
132 frame: frame.max(1),
133 rate,
134 ended,
135 }
136 }
137
138 fn frame_level(&self, n: i64) -> Option<f64> {
140 let frame = self.frame as i64;
141 let from = self.start + (n - self.start).div_euclid(frame) * frame;
142 let end = self.base + self.planes.iter().map(|p| p.len()).min().unwrap_or(0) as i64;
143 if from < self.base {
144 return None;
145 }
146 let to = match from + frame <= end {
147 true => from + frame,
148 false if self.ended => end,
149 false => return None,
150 };
151 let held: Vec<&[f64]> = self
152 .planes
153 .iter()
154 .map(|p| &p[(from - self.base) as usize..(to - self.base) as usize])
155 .collect();
156 Some(sva_samples::measure::envelope::level(&held))
157 }
158
159 fn value(&self, term: Term, n: i64) -> Option<f64> {
160 match term {
161 Term::Time => Some(n as f64 / f64::from(self.rate)),
162 Term::Number(v) => Some(v),
163 Term::Envelope => self.frame_level(n),
164 }
165 }
166}
167
168impl fmt::Display for Term {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 match self {
171 Term::Time => write!(f, "t"),
172 Term::Number(v) => write!(f, "{v}"),
173 Term::Envelope => write!(f, "envelope(t)"),
174 }
175 }
176}
177
178impl fmt::Display for Until {
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 let side = |term: &Term, other: &Term| match (term, other) {
182 (Term::Number(v), Term::Envelope) => format!("{:.1}db", 20.0 * v.log10()),
183 (Term::Number(v), Term::Time) => format!("{v}s"),
184 (term, _) => term.to_string(),
185 };
186 match self {
187 Until::All(a, b) => write!(f, "({a} and {b})"),
188 Until::Any(a, b) => write!(f, "({a} or {b})"),
189 Until::Holds(a, cmp, b) => {
190 let op = match cmp {
191 Cmp::Lt => "<",
192 Cmp::Le => "<=",
193 Cmp::Gt => ">",
194 Cmp::Ge => ">=",
195 };
196 write!(f, "{} {op} {}", side(a, b), side(b, a))
197 }
198 }
199 }
200}