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