1use malloc_size_of_derive::MallocSizeOf;
6
7use crate::block::{Block, FRAMES_PER_BLOCK_USIZE, Tick};
8use crate::node::BlockInfo;
9
10#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, MallocSizeOf)]
11pub enum ParamType {
12 Frequency,
13 Detune,
14 Gain,
15 Q,
16 Pan,
17 PlaybackRate,
18 Position(ParamDir),
19 Forward(ParamDir),
20 Up(ParamDir),
21 Orientation(ParamDir),
22 Offset,
23}
24
25#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, MallocSizeOf)]
26pub enum ParamDir {
27 X,
28 Y,
29 Z,
30}
31
32pub struct Param {
36 val: f32,
37 kind: ParamRate,
38 events: Vec<AutomationEvent>,
39 current_event: usize,
40 event_start_time: Tick,
41 event_start_value: f32,
42 blocks: Vec<Block>,
44 block_mix_val: f32,
46 summed: bool,
48 dirty: bool,
49}
50
51#[derive(Copy, Clone, Eq, PartialEq, Debug, MallocSizeOf)]
52pub enum ParamRate {
53 KRate,
55 ARate,
57}
58
59impl Param {
60 pub fn new(val: f32) -> Self {
61 Param {
62 val,
63 kind: ParamRate::ARate,
64 events: vec![],
65 current_event: 0,
66 event_start_time: Tick(0),
67 event_start_value: val,
68 blocks: Vec::new(),
69 block_mix_val: 0.,
70 summed: false,
71 dirty: false,
72 }
73 }
74
75 pub fn new_krate(val: f32) -> Self {
76 Param {
77 val,
78 kind: ParamRate::KRate,
79 events: vec![],
80 current_event: 0,
81 event_start_time: Tick(0),
82 event_start_value: val,
83 blocks: Vec::new(),
84 block_mix_val: 0.,
85 summed: false,
86 dirty: false,
87 }
88 }
89
90 pub fn update(&mut self, block: &BlockInfo, tick: Tick) -> bool {
97 let mut changed = self.dirty;
98 self.dirty = false;
99 if tick.0 == 0 {
100 self.summed = true;
101 if let Some(first) = self.blocks.pop() {
102 let block = self
105 .blocks
106 .drain(..)
107 .fold(first, |acc, block| acc.sum(block));
108 self.blocks.push(block);
109 }
110 } else if self.kind == ParamRate::KRate {
111 return changed;
112 }
113
114 changed |= if let Some(block) = self.blocks.first() {
119 self.block_mix_val = block.data_chan_frame(tick.0 as usize, 0);
121 true
122 } else {
123 false
124 };
125
126 if self.events.len() <= self.current_event {
127 return changed;
128 }
129
130 let current_tick = block.absolute_tick(tick);
131 let mut current_event = &self.events[self.current_event];
132
133 loop {
138 let mut move_next = false;
139 if let Some(done_time) = current_event.done_time() {
140 if done_time < current_tick {
142 move_next = true;
143 }
144 } else if let Some(next) = self.events.get(self.current_event + 1) {
145 if let Some(start_time) = next.start_time() {
148 if start_time <= current_tick {
150 move_next = true;
151 }
152 } else {
153 if current_event.time() <= current_tick {
159 move_next = true;
160 } else {
161 return changed;
163 }
164 }
165 }
166 if move_next {
167 self.current_event += 1;
168 self.event_start_value = self.val;
169 self.event_start_time = current_tick;
170 if let Some(next) = self.events.get(self.current_event + 1) {
171 current_event = next;
172 continue;
174 } else {
175 return changed;
176 }
177 }
178 break;
179 }
180
181 current_event.run(
182 &mut self.val,
183 current_tick,
184 self.event_start_time,
185 self.event_start_value,
186 )
187 }
188
189 pub fn value(&self) -> f32 {
190 self.val + self.block_mix_val
194 }
195
196 pub fn set_rate(&mut self, rate: ParamRate) {
197 self.kind = rate;
198 }
199
200 pub(crate) fn insert_event(&mut self, event: AutomationEvent) {
201 if let AutomationEvent::SetValue(val) = event {
202 self.val = val;
203 self.event_start_value = val;
204 self.dirty = true;
205 return;
206 }
207
208 let time = event.time();
209
210 let result = self.events.binary_search_by(|e| e.time().cmp(&time));
211 let idx = match result {
213 Ok(idx) => idx,
214 Err(idx) => idx,
215 };
216
217 if let Some(is_hold) = event.cancel_event() {
221 self.events.truncate(idx);
222 if !is_hold {
223 if self.current_event >= self.events.len() {
226 self.val = self.event_start_value;
227 }
228 }
229 return;
231 }
232 self.events.insert(idx, event);
233 }
236
237 pub(crate) fn add_block(&mut self, block: Block) {
238 debug_assert!(block.chan_count() == 1);
239 if self.summed {
244 self.blocks.clear();
245 }
246 self.blocks.push(block)
247 }
248
249 pub(crate) fn flush_to_block(&mut self, info: &BlockInfo, block: &mut [f32]) {
255 if self.current_event >= self.events.len() && self.blocks.is_empty() {
257 if self.val != 0. {
258 for block_tick in &mut block[0..FRAMES_PER_BLOCK_USIZE] {
259 *block_tick = self.val;
261 }
262 }
263 } else {
265 for block_tick in &mut block[0..FRAMES_PER_BLOCK_USIZE] {
266 self.update(info, Tick(*block_tick as u64));
267 *block_tick = self.val;
268 }
269 }
270 }
271}
272
273#[derive(Clone, Copy, Eq, PartialEq, Debug, MallocSizeOf)]
274pub enum RampKind {
275 Linear,
276 Exponential,
277}
278
279#[derive(Clone, PartialEq, Debug)]
280pub(crate) enum AutomationEvent {
282 SetValue(f32),
283 SetValueAtTime(f32, Tick),
284 RampToValueAtTime(RampKind, f32, Tick),
285 SetTargetAtTime(f32, Tick, f64),
286 SetValueCurveAtTime(
287 Vec<f32>,
288 Tick,
289 Tick,
290 ),
291 CancelAndHoldAtTime(Tick),
292 CancelScheduledValues(Tick),
293}
294
295#[derive(Clone, PartialEq, Debug, MallocSizeOf)]
296pub enum UserAutomationEvent {
298 SetValue(f32),
299 SetValueAtTime(f32, f64),
300 RampToValueAtTime(RampKind, f32, f64),
301 SetTargetAtTime(f32, f64, f64),
302 SetValueCurveAtTime(Vec<f32>, f64, f64),
303 CancelAndHoldAtTime(f64),
304 CancelScheduledValues(f64),
305}
306
307impl UserAutomationEvent {
308 pub(crate) fn convert_to_event(self, rate: f32) -> AutomationEvent {
309 match self {
310 UserAutomationEvent::SetValue(val) => AutomationEvent::SetValue(val),
311 UserAutomationEvent::SetValueAtTime(val, time) => {
312 AutomationEvent::SetValueAtTime(val, Tick::from_time(time, rate))
313 },
314 UserAutomationEvent::RampToValueAtTime(kind, val, time) => {
315 AutomationEvent::RampToValueAtTime(kind, val, Tick::from_time(time, rate))
316 },
317 UserAutomationEvent::SetValueCurveAtTime(values, start, duration) => {
318 AutomationEvent::SetValueCurveAtTime(
319 values,
320 Tick::from_time(start, rate),
321 Tick::from_time(duration, rate),
322 )
323 },
324 UserAutomationEvent::SetTargetAtTime(val, start, tau) => {
325 AutomationEvent::SetTargetAtTime(
326 val,
327 Tick::from_time(start, rate),
328 tau * rate as f64,
329 )
330 },
331 UserAutomationEvent::CancelScheduledValues(t) => {
332 AutomationEvent::CancelScheduledValues(Tick::from_time(t, rate))
333 },
334 UserAutomationEvent::CancelAndHoldAtTime(t) => {
335 AutomationEvent::CancelAndHoldAtTime(Tick::from_time(t, rate))
336 },
337 }
338 }
339}
340
341impl AutomationEvent {
342 pub fn time(&self) -> Tick {
344 match *self {
345 AutomationEvent::SetValueAtTime(_, tick) => tick,
346 AutomationEvent::SetValueCurveAtTime(_, start, _) => start,
347 AutomationEvent::RampToValueAtTime(_, _, tick) => tick,
348 AutomationEvent::SetTargetAtTime(_, start, _) => start,
349 AutomationEvent::CancelAndHoldAtTime(t) => t,
350 AutomationEvent::CancelScheduledValues(tick) => tick,
351 AutomationEvent::SetValue(..) => {
352 unreachable!("SetValue should never appear in the timeline")
353 },
354 }
355 }
356
357 pub fn done_time(&self) -> Option<Tick> {
358 match *self {
359 AutomationEvent::SetValueAtTime(_, tick) => Some(tick),
360 AutomationEvent::RampToValueAtTime(_, _, tick) => Some(tick),
361 AutomationEvent::SetValueCurveAtTime(_, start, duration) => Some(start + duration),
362 AutomationEvent::SetTargetAtTime(..) => None,
363 AutomationEvent::CancelAndHoldAtTime(t) => Some(t),
364 AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) => {
365 unreachable!("CancelScheduledValues/SetValue should never appear in the timeline")
366 },
367 }
368 }
369
370 pub fn start_time(&self) -> Option<Tick> {
371 match *self {
372 AutomationEvent::SetValueAtTime(_, tick) => Some(tick),
373 AutomationEvent::RampToValueAtTime(..) => None,
374 AutomationEvent::SetValueCurveAtTime(_, start, _) => Some(start),
375 AutomationEvent::SetTargetAtTime(_, start, _) => Some(start),
376 AutomationEvent::CancelAndHoldAtTime(t) => Some(t),
377 AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) => {
378 unreachable!("CancelScheduledValues/SetValue should never appear in the timeline")
379 },
380 }
381 }
382
383 pub fn cancel_event(&self) -> Option<bool> {
386 match *self {
387 AutomationEvent::CancelAndHoldAtTime(..) => Some(true),
388 AutomationEvent::CancelScheduledValues(..) => Some(false),
389 _ => None,
390 }
391 }
392
393 pub fn run(
397 &self,
398 value: &mut f32,
399 current_tick: Tick,
400 event_start_time: Tick,
401 event_start_value: f32,
402 ) -> bool {
403 if matches!(self.start_time(), Some(start_time) if start_time > current_tick) {
404 return false;
407 }
408
409 match *self {
410 AutomationEvent::SetValueAtTime(val, time) => {
411 if current_tick == time {
412 *value = val;
413 true
414 } else {
415 false
416 }
417 },
418 AutomationEvent::RampToValueAtTime(kind, val, time) => {
419 let progress =
420 (current_tick - event_start_time).0 as f32 / (time - event_start_time).0 as f32;
421 match kind {
422 RampKind::Linear => {
423 *value = event_start_value + (val - event_start_value) * progress;
424 },
425 RampKind::Exponential => {
426 let ratio = val / event_start_value;
427 if event_start_value == 0. || ratio < 0. {
428 if time == current_tick {
429 *value = val;
430 } else {
431 *value = event_start_value;
432 }
433 } else {
434 *value = event_start_value * (ratio).powf(progress);
435 }
436 },
437 }
438 true
439 },
440 AutomationEvent::SetTargetAtTime(val, start, tau) => {
441 let exp = -((current_tick - start) / tau);
442 *value = val + (event_start_value - val) * exp.exp() as f32;
443 true
444 },
445 AutomationEvent::SetValueCurveAtTime(ref values, start, duration) => {
446 let progress = ((current_tick.0 as f32) - (start.0 as f32)) / (duration.0 as f32);
447 debug_assert!(progress >= 0.);
448 let n = values.len() as f32;
449 let k_float = (n - 1.) * progress;
450 let k = k_float.floor();
451 if (k + 1.) < n {
452 let progress = k_float - k;
453 *value =
454 values[k as usize] * (1. - progress) + values[(k + 1.) as usize] * progress;
455 } else {
456 *value = values[(n - 1.) as usize];
457 }
458 true
459 },
460 AutomationEvent::CancelAndHoldAtTime(..) => false,
461 AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) => {
462 unreachable!("CancelScheduledValues/SetValue should never appear in the timeline")
463 },
464 }
465 }
466}