1use std::any::Any;
4use std::slice::{Iter, IterMut};
5use std::sync::atomic::Ordering;
6use std::sync::{Arc, Mutex, OnceLock};
7
8use arrayvec::ArrayVec;
9
10use crate::context::AudioContextRegistration;
11use crate::node::{
12 AudioNode, AudioNodeOptions, ChannelConfig, ChannelCountMode, ChannelInterpretation,
13};
14use crate::render::{
15 AudioParamValues, AudioProcessor, AudioRenderQuantum, AudioWorkletGlobalScope,
16};
17use crate::{assert_valid_time_value, AtomicF32, RENDER_QUANTUM_SIZE};
18
19const SNAP_TO_TARGET: f32 = 1e-10;
23
24#[track_caller]
25fn assert_is_finite(value: f32) {
26 assert!(
27 value.is_finite(),
28 "TypeError - The provided value is non-finite."
29 );
30}
31
32#[track_caller]
33fn assert_strictly_positive(value: f64) {
34 assert!(
35 value.is_finite(),
36 "TypeError - The provided value is non-finite."
37 );
38 assert!(
39 value > 0.,
40 "RangeError - duration ({:?}) should be strictly positive",
41 value
42 );
43}
44
45#[track_caller]
46fn assert_not_zero(value: f32) {
47 assert_is_finite(value);
48 assert_ne!(
49 value, 0.,
50 "RangeError - value ({:?}) should not be equal to zero",
51 value
52 );
53}
54
55#[track_caller]
56fn assert_sequence_length(values: &[f32]) {
57 assert!(
58 values.len() >= 2,
59 "InvalidStateError - sequence length ({:?}) should not be less than 2",
60 values.len()
61 );
62}
63
64#[inline(always)]
66fn compute_linear_ramp_sample(
67 start_time: f64,
68 duration: f64,
69 start_value: f32,
70 diff: f32, time: f64,
72) -> f32 {
73 let phase = (time - start_time) / duration;
74 diff.mul_add(phase as f32, start_value)
75}
76
77#[inline(always)]
79fn compute_exponential_ramp_sample(
80 start_time: f64,
81 duration: f64,
82 start_value: f32,
83 ratio: f32, time: f64,
85) -> f32 {
86 let phase = (time - start_time) / duration;
87 start_value * ratio.powf(phase as f32)
88}
89
90#[inline(always)]
92fn compute_set_target_sample(
93 start_time: f64,
94 time_constant: f64,
95 end_value: f32,
96 diff: f32, time: f64,
98) -> f32 {
99 let exponent = -((time - start_time) / time_constant);
100 diff.mul_add(exponent.exp() as f32, end_value)
101}
102
103#[inline(always)]
106fn compute_set_value_curve_sample(
107 start_time: f64,
108 duration: f64,
109 values: &[f32],
110 time: f64,
111) -> f32 {
112 if time - start_time >= duration {
113 return values[values.len() - 1];
114 }
115
116 let position = (values.len() - 1) as f64 * (time - start_time) / duration;
117 let k = position as usize;
118 let phase = (position - position.floor()) as f32;
119 (values[k + 1] - values[k]).mul_add(phase, values[k])
120}
121
122#[derive(Copy, Clone, PartialEq, Eq, Debug)]
124pub enum AutomationRate {
125 A,
127 K,
130}
131
132impl AutomationRate {
133 fn is_a_rate(self) -> bool {
134 match self {
135 AutomationRate::A => true,
136 AutomationRate::K => false,
137 }
138 }
139}
140
141#[derive(Clone, Debug)]
143pub struct AudioParamDescriptor {
144 pub name: String,
145 pub automation_rate: AutomationRate,
146 pub default_value: f32,
147 pub min_value: f32,
148 pub max_value: f32,
149}
150
151#[derive(PartialEq, Eq, Debug, Copy, Clone)]
152enum AudioParamEventType {
153 SetValue,
154 SetValueAtTime,
155 LinearRampToValueAtTime,
156 ExponentialRampToValueAtTime,
157 CancelScheduledValues,
158 SetTargetAtTime,
159 CancelAndHoldAtTime,
160 SetValueCurveAtTime,
161}
162
163#[derive(Debug)]
164pub(crate) struct AudioParamEvent {
165 event_type: AudioParamEventType,
166 value: f32,
167 time: f64,
168 time_constant: Option<f64>, cancel_time: Option<f64>, duration: Option<f64>, values: Option<Box<[f32]>>, }
173
174#[derive(Debug, Default)]
184struct AudioParamEventTimeline {
185 inner: Vec<AudioParamEvent>,
186 dirty: bool,
187}
188
189impl AudioParamEventTimeline {
190 fn new() -> Self {
191 Self {
192 inner: Vec::with_capacity(32),
193 dirty: false,
194 }
195 }
196
197 fn push(&mut self, item: AudioParamEvent) {
198 self.dirty = true;
199 self.inner.push(item);
200 }
201
202 fn pop(&mut self) -> Option<AudioParamEvent> {
204 if !self.inner.is_empty() {
205 Some(self.inner.remove(0))
206 } else {
207 None
208 }
209 }
210
211 fn retain<F>(&mut self, func: F)
212 where
213 F: Fn(&AudioParamEvent) -> bool,
214 {
215 self.inner.retain(func);
216 }
217
218 fn replace_peek(&mut self, item: AudioParamEvent) {
223 self.inner[0] = item;
224 }
225
226 fn is_empty(&self) -> bool {
227 self.inner.is_empty()
228 }
229
230 fn unsorted_peek(&self) -> Option<&AudioParamEvent> {
231 self.inner.first()
232 }
233
234 fn peek(&self) -> Option<&AudioParamEvent> {
236 assert!(
237 !self.dirty,
238 "`AudioParamEventTimeline`: Invalid `.peek()` call, the queue is dirty"
239 );
240 self.inner.first()
241 }
242
243 fn next(&self) -> Option<&AudioParamEvent> {
244 assert!(
245 !self.dirty,
246 "`AudioParamEventTimeline`: Invalid `.next()` call, the queue is dirty"
247 );
248 self.inner.get(1)
249 }
250
251 fn sort(&mut self) {
252 self.inner
253 .sort_by(|a, b| a.time.partial_cmp(&b.time).unwrap());
254 self.dirty = false;
255 }
256
257 fn iter(&mut self) -> Iter<'_, AudioParamEvent> {
258 self.inner.iter()
259 }
260
261 fn iter_mut(&mut self) -> IterMut<'_, AudioParamEvent> {
262 self.inner.iter_mut()
263 }
264}
265
266#[derive(Clone)] pub struct AudioParam {
269 registration: Arc<AudioContextRegistration>,
270 raw_parts: AudioParamInner,
271}
272
273impl std::fmt::Debug for AudioParam {
274 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
275 f.debug_struct("AudioParam")
276 .field("registration", &self.registration())
277 .field("automation_rate", &self.automation_rate())
278 .field(
279 "automation_rate_constrained",
280 &self.raw_parts.automation_rate_constrained,
281 )
282 .field("default_value", &self.default_value())
283 .field("min_value", &self.min_value())
284 .field("max_value", &self.max_value())
285 .finish()
286 }
287}
288
289#[derive(Debug, Clone)]
291pub(crate) struct AudioParamInner {
292 default_value: f32, min_value: f32, max_value: f32, automation_rate_constrained: bool, automation_rate: Arc<Mutex<AutomationRate>>, current_value: Arc<AtomicF32>, }
299
300impl AudioNode for AudioParam {
301 fn registration(&self) -> &AudioContextRegistration {
302 &self.registration
303 }
304
305 fn channel_config(&self) -> &'static ChannelConfig {
306 static INSTANCE: OnceLock<ChannelConfig> = OnceLock::new();
307 INSTANCE.get_or_init(|| {
308 AudioNodeOptions {
309 channel_count: 1,
310 channel_count_mode: ChannelCountMode::Explicit,
311 channel_interpretation: ChannelInterpretation::Discrete,
312 }
313 .into()
314 })
315 }
316
317 fn number_of_inputs(&self) -> usize {
318 1
319 }
320
321 fn number_of_outputs(&self) -> usize {
322 1
323 }
324
325 fn set_channel_count(&self, _v: usize) {
326 panic!("NotSupportedError - AudioParam has channel count constraints");
327 }
328 fn set_channel_count_mode(&self, _v: ChannelCountMode) {
329 panic!("NotSupportedError - AudioParam has channel count mode constraints");
330 }
331 fn set_channel_interpretation(&self, _v: ChannelInterpretation) {
332 panic!("NotSupportedError - AudioParam has channel interpretation constraints");
333 }
334}
335
336impl AudioParam {
337 #[allow(clippy::missing_panics_doc)]
339 pub fn automation_rate(&self) -> AutomationRate {
340 *self.raw_parts.automation_rate.lock().unwrap()
341 }
342
343 pub fn set_automation_rate(&self, value: AutomationRate) {
349 assert!(
350 !self.raw_parts.automation_rate_constrained || value == self.automation_rate(),
351 "InvalidStateError - automation rate cannot be changed for this param"
352 );
353
354 let mut guard = self.raw_parts.automation_rate.lock().unwrap();
355 *guard = value;
356 self.registration().post_message(value);
357 drop(guard); }
360
361 pub(crate) fn set_automation_rate_constrained(&mut self, value: bool) {
362 self.raw_parts.automation_rate_constrained = value;
363 }
364
365 pub fn default_value(&self) -> f32 {
366 self.raw_parts.default_value
367 }
368
369 pub fn min_value(&self) -> f32 {
370 self.raw_parts.min_value
371 }
372
373 pub fn max_value(&self) -> f32 {
374 self.raw_parts.max_value
375 }
376
377 pub fn value(&self) -> f32 {
389 self.raw_parts.current_value.load(Ordering::Acquire)
390 }
391
392 pub fn set_value(&self, value: f32) -> &Self {
404 self.send_event(self.set_value_raw(value))
405 }
406
407 fn set_value_raw(&self, value: f32) -> AudioParamEvent {
408 assert_is_finite(value);
409 let clamped = value.clamp(self.raw_parts.min_value, self.raw_parts.max_value);
411 self.raw_parts
412 .current_value
413 .store(clamped, Ordering::Release);
414
415 AudioParamEvent {
418 event_type: AudioParamEventType::SetValue,
419 value,
420 time: 0.,
421 time_constant: None,
422 cancel_time: None,
423 duration: None,
424 values: None,
425 }
426 }
427
428 pub fn set_value_at_time(&self, value: f32, start_time: f64) -> &Self {
434 self.send_event(self.set_value_at_time_raw(value, start_time))
435 }
436
437 fn set_value_at_time_raw(&self, value: f32, start_time: f64) -> AudioParamEvent {
438 assert_is_finite(value);
439 assert_valid_time_value(start_time);
440
441 AudioParamEvent {
442 event_type: AudioParamEventType::SetValueAtTime,
443 value,
444 time: start_time,
445 time_constant: None,
446 cancel_time: None,
447 duration: None,
448 values: None,
449 }
450 }
451
452 pub fn linear_ramp_to_value_at_time(&self, value: f32, end_time: f64) -> &Self {
459 self.send_event(self.linear_ramp_to_value_at_time_raw(value, end_time))
460 }
461
462 fn linear_ramp_to_value_at_time_raw(&self, value: f32, end_time: f64) -> AudioParamEvent {
463 assert_is_finite(value);
464 assert_valid_time_value(end_time);
465
466 AudioParamEvent {
467 event_type: AudioParamEventType::LinearRampToValueAtTime,
468 value,
469 time: end_time,
470 time_constant: None,
471 cancel_time: None,
472 duration: None,
473 values: None,
474 }
475 }
476
477 pub fn exponential_ramp_to_value_at_time(&self, value: f32, end_time: f64) -> &Self {
486 self.send_event(self.exponential_ramp_to_value_at_time_raw(value, end_time))
487 }
488
489 fn exponential_ramp_to_value_at_time_raw(&self, value: f32, end_time: f64) -> AudioParamEvent {
490 assert_not_zero(value);
491 assert_valid_time_value(end_time);
492
493 AudioParamEvent {
494 event_type: AudioParamEventType::ExponentialRampToValueAtTime,
495 value,
496 time: end_time,
497 time_constant: None,
498 cancel_time: None,
499 duration: None,
500 values: None,
501 }
502 }
503
504 pub fn set_target_at_time(&self, value: f32, start_time: f64, time_constant: f64) -> &Self {
513 self.send_event(self.set_target_at_time_raw(value, start_time, time_constant))
514 }
515
516 fn set_target_at_time_raw(
517 &self,
518 value: f32,
519 start_time: f64,
520 time_constant: f64,
521 ) -> AudioParamEvent {
522 assert_is_finite(value);
523 assert_valid_time_value(start_time);
524 assert_valid_time_value(time_constant);
525
526 if time_constant == 0. {
528 AudioParamEvent {
529 event_type: AudioParamEventType::SetValueAtTime,
530 value,
531 time: start_time,
532 time_constant: None,
533 cancel_time: None,
534 duration: None,
535 values: None,
536 }
537 } else {
538 AudioParamEvent {
539 event_type: AudioParamEventType::SetTargetAtTime,
540 value,
541 time: start_time,
542 time_constant: Some(time_constant),
543 cancel_time: None,
544 duration: None,
545 values: None,
546 }
547 }
548 }
549
550 pub fn cancel_scheduled_values(&self, cancel_time: f64) -> &Self {
557 self.send_event(self.cancel_scheduled_values_raw(cancel_time))
558 }
559
560 fn cancel_scheduled_values_raw(&self, cancel_time: f64) -> AudioParamEvent {
561 assert_valid_time_value(cancel_time);
562
563 AudioParamEvent {
564 event_type: AudioParamEventType::CancelScheduledValues,
565 value: 0., time: cancel_time,
567 time_constant: None,
568 cancel_time: None,
569 duration: None,
570 values: None,
571 }
572 }
573
574 pub fn cancel_and_hold_at_time(&self, cancel_time: f64) -> &Self {
582 self.send_event(self.cancel_and_hold_at_time_raw(cancel_time))
583 }
584
585 fn cancel_and_hold_at_time_raw(&self, cancel_time: f64) -> AudioParamEvent {
586 assert_valid_time_value(cancel_time);
587
588 AudioParamEvent {
589 event_type: AudioParamEventType::CancelAndHoldAtTime,
590 value: 0., time: cancel_time,
592 time_constant: None,
593 cancel_time: None,
594 duration: None,
595 values: None,
596 }
597 }
598
599 pub fn set_value_curve_at_time(&self, values: &[f32], start_time: f64, duration: f64) -> &Self {
609 self.send_event(self.set_value_curve_at_time_raw(values, start_time, duration))
610 }
611
612 fn set_value_curve_at_time_raw(
613 &self,
614 values: &[f32],
615 start_time: f64,
616 duration: f64,
617 ) -> AudioParamEvent {
618 assert_sequence_length(values);
619 assert_valid_time_value(start_time);
620 assert_strictly_positive(duration);
621
622 let copy = values.to_vec();
625 let boxed_copy = copy.into_boxed_slice();
626
627 AudioParamEvent {
628 event_type: AudioParamEventType::SetValueCurveAtTime,
629 value: 0., time: start_time,
631 time_constant: None,
632 cancel_time: None,
633 duration: Some(duration),
634 values: Some(boxed_copy),
635 }
636 }
637
638 pub(crate) fn into_raw_parts(self) -> AudioParamInner {
640 let Self {
641 registration: _,
642 raw_parts,
643 } = self;
644 raw_parts
645 }
646
647 pub(crate) fn from_raw_parts(
649 registration: AudioContextRegistration,
650 raw_parts: AudioParamInner,
651 ) -> Self {
652 Self {
653 registration: registration.into(),
654 raw_parts,
655 }
656 }
657
658 fn send_event(&self, event: AudioParamEvent) -> &Self {
659 self.registration().post_message(event);
660 self
661 }
662}
663
664struct BlockInfos {
665 block_time: f64,
666 dt: f64,
667 count: usize,
668 is_a_rate: bool,
669 next_block_time: f64,
670}
671
672#[derive(Debug)]
673pub(crate) struct AudioParamProcessor {
674 default_value: f32, min_value: f32, max_value: f32, intrinsic_value: f32,
678 automation_rate: AutomationRate,
679 current_value: Arc<AtomicF32>,
680 event_timeline: AudioParamEventTimeline,
681 last_event: Option<AudioParamEvent>,
682 buffer: ArrayVec<f32, RENDER_QUANTUM_SIZE>,
683}
684
685impl AudioProcessor for AudioParamProcessor {
686 fn process(
687 &mut self,
688 inputs: &[AudioRenderQuantum],
689 outputs: &mut [AudioRenderQuantum],
690 _params: AudioParamValues<'_>,
691 scope: &AudioWorkletGlobalScope,
692 ) -> bool {
693 let period = 1. / scope.sample_rate as f64;
694
695 let input = &inputs[0]; let output = &mut outputs[0];
697
698 self.compute_intrinsic_values(scope.current_time, period, RENDER_QUANTUM_SIZE);
699 self.mix_to_output(input, output);
700
701 true }
703
704 fn onmessage(&mut self, msg: &mut dyn Any) {
705 if let Some(automation_rate) = msg.downcast_ref::<AutomationRate>() {
706 self.automation_rate = *automation_rate;
707 return;
708 }
709
710 if let Some(event) = msg.downcast_mut::<AudioParamEvent>() {
711 let tombstone_event = AudioParamEvent {
713 event_type: AudioParamEventType::SetValue,
714 value: Default::default(),
715 time: Default::default(),
716 time_constant: None,
717 cancel_time: None,
718 duration: None,
719 values: None,
720 };
721 let event = std::mem::replace(event, tombstone_event);
722 self.handle_incoming_event(event);
723 return;
724 };
725
726 log::warn!("AudioParamProcessor: Dropping incoming message {msg:?}");
727 }
728}
729
730impl AudioParamProcessor {
731 fn compute_intrinsic_values(&mut self, block_time: f64, dt: f64, count: usize) -> &[f32] {
735 self.compute_buffer(block_time, dt, count);
736 self.buffer.as_slice()
737 }
738
739 fn mix_to_output(&mut self, input: &AudioRenderQuantum, output: &mut AudioRenderQuantum) {
740 #[cfg(test)]
741 assert!(self.buffer.len() == 1 || self.buffer.len() == RENDER_QUANTUM_SIZE);
742
743 if self.buffer.len() == 1 || !self.automation_rate.is_a_rate() {
745 let mut value = self.buffer[0];
746
747 if input.is_silent() || !self.automation_rate.is_a_rate() {
751 output.set_single_valued(true);
752
753 value += input.channel_data(0)[0];
754
755 if value.is_nan() {
756 value = self.default_value;
757 } else {
758 value = value.max(self.min_value).min(self.max_value);
760 }
761 output.channel_data_mut(0)[0] = value;
762 } else {
763 output.set_single_valued(false);
765 *output = input.clone();
766 output.channel_data_mut(0).iter_mut().for_each(|o| {
767 *o += value;
768
769 if o.is_nan() {
770 *o = self.default_value;
771 } else {
772 *o = o.max(self.min_value).min(self.max_value);
774 }
775 });
776 }
777 } else {
778 *output = input.clone();
780 output.set_single_valued(false);
781
782 output
783 .channel_data_mut(0)
784 .iter_mut()
785 .zip(self.buffer.iter())
786 .for_each(|(o, p)| {
787 *o += p;
788
789 if o.is_nan() {
790 *o = self.default_value;
791 } else {
792 *o = o.max(self.min_value).min(self.max_value);
794 }
795 });
796 }
797 }
798
799 fn handle_incoming_event(&mut self, event: AudioParamEvent) {
800 if event.event_type == AudioParamEventType::CancelScheduledValues {
812 let some_current_event = self.event_timeline.unsorted_peek();
819
820 match some_current_event {
821 None => (),
822 Some(current_event) => {
823 match current_event.event_type {
831 AudioParamEventType::LinearRampToValueAtTime
832 | AudioParamEventType::ExponentialRampToValueAtTime
833 if current_event.time >= event.time => {
854 let last_event = self.last_event.as_ref().unwrap();
855 self.intrinsic_value = last_event.value;
856 }
857 _ => (),
858 }
859 }
860 }
861
862 self.event_timeline
865 .retain(|queued| queued.time < event.time);
866 return; }
868
869 if event.event_type == AudioParamEventType::CancelAndHoldAtTime {
870 let mut e1: Option<&mut AudioParamEvent> = None;
875 let mut e2: Option<&mut AudioParamEvent> = None;
876 let mut t1 = f64::MIN;
877 let mut t2 = f64::MAX;
878 self.event_timeline.sort();
880
881 for queued in self.event_timeline.iter_mut() {
882 if queued.time >= t1 && queued.time <= event.time {
885 t1 = queued.time;
886 e1 = Some(queued);
887 } else if queued.time < t2 && queued.time > event.time {
890 t2 = queued.time;
891 e2 = Some(queued);
892 }
893 }
894
895 if let Some(matched) = e2 {
897 if matched.event_type == AudioParamEventType::LinearRampToValueAtTime
904 || matched.event_type == AudioParamEventType::ExponentialRampToValueAtTime
905 {
906 matched.cancel_time = Some(event.time);
907 }
908 } else if let Some(matched) = e1 {
909 if matched.event_type == AudioParamEventType::SetTargetAtTime {
910 matched.cancel_time = Some(event.time);
914 } else if matched.event_type == AudioParamEventType::SetValueCurveAtTime {
915 let start_time = matched.time;
925 let duration = matched.duration.unwrap();
926
927 if event.time <= start_time + duration {
928 matched.cancel_time = Some(event.time);
929 }
930 }
931 }
932
933 self.event_timeline.retain(|queued| {
935 let mut time = queued.time;
936 if let Some(cancel_time) = queued.cancel_time {
938 time = cancel_time;
939 }
940
941 time <= event.time
942 });
943 return; }
945
946 if event.event_type == AudioParamEventType::SetValueCurveAtTime {
957 let start_time = event.time;
959 let end_time = start_time + event.duration.unwrap();
960
961 for queued in self.event_timeline.iter() {
962 assert!(
963 queued.time <= start_time || queued.time >= end_time,
964 "NotSupportedError - scheduling SetValueCurveAtTime ({:?}) at time of another automation event ({:?})",
965 event, queued,
966 );
967 }
968 }
969
970 if event.event_type == AudioParamEventType::SetValueAtTime
975 || event.event_type == AudioParamEventType::SetValue
976 || event.event_type == AudioParamEventType::LinearRampToValueAtTime
977 || event.event_type == AudioParamEventType::ExponentialRampToValueAtTime
978 || event.event_type == AudioParamEventType::SetTargetAtTime
979 {
980 for queued in self.event_timeline.iter() {
981 if queued.event_type == AudioParamEventType::SetValueCurveAtTime {
982 let start_time = queued.time;
983 let end_time = start_time + queued.duration.unwrap();
984
985 assert!(
986 event.time <= start_time || event.time >= end_time,
987 "NotSupportedError - scheduling automation event ({:?}) during SetValueCurveAtTime ({:?})",
988 event, queued,
989 );
990 }
991 }
992 }
993
994 if event.event_type == AudioParamEventType::SetValue {
996 self.intrinsic_value = event.value;
997 }
998
999 if self.event_timeline.is_empty()
1005 && self.last_event.is_none()
1006 && (event.event_type == AudioParamEventType::LinearRampToValueAtTime
1007 || event.event_type == AudioParamEventType::ExponentialRampToValueAtTime)
1008 {
1009 let set_value_event = AudioParamEvent {
1010 event_type: AudioParamEventType::SetValue,
1011 value: self.intrinsic_value,
1012 time: 0.,
1015 time_constant: None,
1016 cancel_time: None,
1017 duration: None,
1018 values: None,
1019 };
1020
1021 self.event_timeline.push(set_value_event);
1022 }
1023
1024 if self.event_timeline.is_empty()
1028 && event.event_type == AudioParamEventType::SetTargetAtTime
1029 {
1030 let set_value_event = AudioParamEvent {
1031 event_type: AudioParamEventType::SetValue,
1032 value: self.intrinsic_value,
1033 time: 0.,
1036 time_constant: None,
1037 cancel_time: None,
1038 duration: None,
1039 values: None,
1040 };
1041
1042 self.event_timeline.push(set_value_event);
1043 }
1044
1045 self.event_timeline.push(event);
1046 self.event_timeline.sort();
1047 }
1048
1049 fn compute_set_value_automation(&mut self, infos: &BlockInfos) -> bool {
1051 let event = self.event_timeline.peek().unwrap();
1052 let mut time = event.time;
1053
1054 if time == 0. {
1061 time = infos.block_time;
1062 }
1063
1064 if infos.is_a_rate {
1066 let end_index = ((time - infos.block_time).max(0.) / infos.dt).round() as usize;
1067 let end_index_clipped = end_index.min(infos.count);
1068
1069 for _ in self.buffer.len()..end_index_clipped {
1070 self.buffer.push(self.intrinsic_value);
1071 }
1072 }
1073
1074 if time > infos.next_block_time {
1076 return true;
1077 }
1078
1079 self.intrinsic_value = event.value;
1081
1082 #[allow(clippy::float_cmp)]
1084 if time != event.time {
1085 let mut event = self.event_timeline.pop().unwrap();
1086 event.time = time;
1087 self.last_event = Some(event);
1088 } else {
1089 self.last_event = self.event_timeline.pop();
1090 }
1091
1092 false
1093 }
1094
1095 fn compute_linear_ramp_automation(&mut self, infos: &BlockInfos) -> bool {
1098 let event = self.event_timeline.peek().unwrap();
1099 let last_event = self.last_event.as_ref().unwrap();
1100
1101 let start_time = last_event.time;
1102 let mut end_time = event.time;
1103 let duration = end_time - start_time;
1106 if let Some(cancel_time) = event.cancel_time {
1107 end_time = cancel_time;
1108 }
1109
1110 let start_value = last_event.value;
1111 let end_value = event.value;
1112 let diff = end_value - start_value;
1113
1114 if infos.is_a_rate {
1115 let start_index = self.buffer.len();
1116 let end_index = ((end_time - infos.block_time).max(0.) / infos.dt).round() as usize;
1119 let end_index_clipped = end_index.min(infos.count);
1120
1121 if end_index_clipped > start_index {
1124 let mut time = (start_index as f64).mul_add(infos.dt, infos.block_time);
1125
1126 let mut value = 0.;
1127 for _ in start_index..end_index_clipped {
1128 value =
1129 compute_linear_ramp_sample(start_time, duration, start_value, diff, time);
1130 self.buffer.push(value);
1131 time += infos.dt;
1132 }
1133 self.intrinsic_value = value;
1134 }
1135 }
1136
1137 if end_time >= infos.next_block_time {
1142 let value = compute_linear_ramp_sample(
1143 start_time,
1144 duration,
1145 start_value,
1146 diff,
1147 infos.next_block_time,
1148 );
1149 self.intrinsic_value = value;
1150
1151 return true;
1152 }
1153
1154 if event.cancel_time.is_some() {
1156 let value =
1157 compute_linear_ramp_sample(start_time, duration, start_value, diff, end_time);
1158
1159 self.intrinsic_value = value;
1160
1161 let mut last_event = self.event_timeline.pop().unwrap();
1162 last_event.time = end_time;
1163 last_event.value = value;
1164 self.last_event = Some(last_event);
1165 } else {
1167 self.intrinsic_value = end_value;
1168 self.last_event = self.event_timeline.pop();
1169 }
1170
1171 false
1172 }
1173
1174 fn compute_exponential_ramp_automation(&mut self, infos: &BlockInfos) -> bool {
1177 let event = self.event_timeline.peek().unwrap();
1178 let last_event = self.last_event.as_ref().unwrap();
1179
1180 let start_time = last_event.time;
1181 let mut end_time = event.time;
1182 let duration = end_time - start_time;
1185 if let Some(cancel_time) = event.cancel_time {
1186 end_time = cancel_time;
1187 }
1188
1189 let start_value = last_event.value;
1190 let end_value = event.value;
1191 let ratio = end_value / start_value;
1192
1193 if start_value == 0. || start_value * end_value < 0. {
1201 let event = AudioParamEvent {
1202 event_type: AudioParamEventType::SetValueAtTime,
1203 time: end_time,
1204 value: end_value,
1205 time_constant: None,
1206 cancel_time: None,
1207 duration: None,
1208 values: None,
1209 };
1210
1211 self.event_timeline.replace_peek(event);
1212 return false;
1213 }
1214
1215 if infos.is_a_rate {
1216 let start_index = self.buffer.len();
1217 let end_index = ((end_time - infos.block_time).max(0.) / infos.dt).round() as usize;
1220 let end_index_clipped = end_index.min(infos.count);
1221
1222 if end_index_clipped > start_index {
1223 let mut time = (start_index as f64).mul_add(infos.dt, infos.block_time);
1224
1225 let mut value = 0.;
1226 for _ in start_index..end_index_clipped {
1227 value = compute_exponential_ramp_sample(
1228 start_time,
1229 duration,
1230 start_value,
1231 ratio,
1232 time,
1233 );
1234
1235 self.buffer.push(value);
1236
1237 time += infos.dt;
1238 }
1239 self.intrinsic_value = value;
1240 }
1241 }
1242
1243 if end_time >= infos.next_block_time {
1248 let value = compute_exponential_ramp_sample(
1249 start_time,
1250 duration,
1251 start_value,
1252 ratio,
1253 infos.next_block_time,
1254 );
1255 self.intrinsic_value = value;
1256
1257 return true;
1258 }
1259
1260 if event.cancel_time.is_some() {
1262 let value =
1263 compute_exponential_ramp_sample(start_time, duration, start_value, ratio, end_time);
1264
1265 self.intrinsic_value = value;
1266
1267 let mut last_event = self.event_timeline.pop().unwrap();
1268 last_event.time = end_time;
1269 last_event.value = value;
1270 self.last_event = Some(last_event);
1271
1272 } else {
1274 self.intrinsic_value = end_value;
1275 self.last_event = self.event_timeline.pop();
1276 }
1277
1278 false
1279 }
1280
1281 fn compute_set_target_automation(&mut self, infos: &BlockInfos) -> bool {
1287 let event = self.event_timeline.peek().unwrap();
1288 let mut end_time = infos.next_block_time;
1289 let mut ended = false;
1290
1291 let some_next_event = self.event_timeline.next();
1293
1294 if let Some(next_event) = some_next_event {
1295 match next_event.event_type {
1296 AudioParamEventType::LinearRampToValueAtTime
1297 | AudioParamEventType::ExponentialRampToValueAtTime => {
1298 end_time = infos.block_time;
1311 ended = true;
1312 }
1313 _ => {
1314 if next_event.time < infos.next_block_time {
1317 end_time = next_event.time;
1318 ended = true;
1319 }
1320 }
1321 }
1322 }
1323
1324 if let Some(cancel_time) = event.cancel_time {
1326 if cancel_time < infos.next_block_time {
1327 end_time = cancel_time;
1328 ended = true;
1329 }
1330 }
1331
1332 let start_time = event.time;
1333 let start_value = self.last_event.as_ref().unwrap().value;
1337 let end_value = event.value;
1338 let diff = start_value - end_value;
1339 let time_constant = event.time_constant.unwrap();
1340
1341 if infos.is_a_rate {
1342 let start_index = self.buffer.len();
1343 let end_index = ((end_time - infos.block_time).max(0.) / infos.dt).round() as usize;
1346 let end_index_clipped = end_index.min(infos.count);
1347
1348 if end_index_clipped > start_index {
1349 let mut time = (start_index as f64).mul_add(infos.dt, infos.block_time);
1350
1351 let mut value = 0.;
1352 for _ in start_index..end_index_clipped {
1353 value = if time - start_time < 0. {
1355 self.intrinsic_value
1356 } else {
1357 compute_set_target_sample(start_time, time_constant, end_value, diff, time)
1358 };
1359
1360 self.buffer.push(value);
1361 time += infos.dt;
1362 }
1363 self.intrinsic_value = value;
1364 }
1365 }
1366
1367 if !ended {
1368 let value = compute_set_target_sample(
1372 start_time,
1373 time_constant,
1374 end_value,
1375 diff,
1376 infos.next_block_time,
1377 );
1378
1379 let diff = (end_value - value).abs();
1380
1381 if diff < SNAP_TO_TARGET {
1383 self.intrinsic_value = end_value;
1384
1385 if end_value == 0. {
1388 for v in self.buffer.iter_mut() {
1389 if v.is_subnormal() {
1390 *v = 0.;
1391 }
1392 }
1393 }
1394
1395 let event = AudioParamEvent {
1396 event_type: AudioParamEventType::SetValueAtTime,
1397 time: infos.next_block_time,
1398 value: end_value,
1399 time_constant: None,
1400 cancel_time: None,
1401 duration: None,
1402 values: None,
1403 };
1404
1405 self.event_timeline.replace_peek(event);
1406 } else {
1407 self.intrinsic_value = value;
1408 }
1409
1410 return true;
1411 }
1412
1413 let value = compute_set_target_sample(start_time, time_constant, end_value, diff, end_time);
1416
1417 self.intrinsic_value = value;
1418 let mut event = self.event_timeline.pop().unwrap();
1421 event.time = end_time;
1422 event.value = value;
1423 self.last_event = Some(event);
1424
1425 false
1426 }
1427
1428 fn compute_set_value_curve_automation(&mut self, infos: &BlockInfos) -> bool {
1429 let event = self.event_timeline.peek().unwrap();
1430 let start_time = event.time;
1431 let duration = event.duration.unwrap();
1432 let values = event.values.as_ref().unwrap();
1433 let mut end_time = start_time + duration;
1434
1435 if let Some(cancel_time) = event.cancel_time {
1439 end_time = cancel_time;
1440 }
1441
1442 if infos.is_a_rate {
1443 let start_index = self.buffer.len();
1444 let end_index = ((end_time - infos.block_time).max(0.) / infos.dt).round() as usize;
1447 let end_index_clipped = end_index.min(infos.count);
1448
1449 if end_index_clipped > start_index {
1450 let mut time = (start_index as f64).mul_add(infos.dt, infos.block_time);
1451
1452 let mut value = 0.;
1453 for _ in start_index..end_index_clipped {
1454 value = if time < start_time {
1456 self.intrinsic_value
1457 } else {
1458 compute_set_value_curve_sample(start_time, duration, values, time)
1459 };
1460
1461 self.buffer.push(value);
1462
1463 time += infos.dt;
1464 }
1465 self.intrinsic_value = value;
1466 }
1467 }
1468
1469 if end_time >= infos.next_block_time {
1471 let value =
1475 compute_set_value_curve_sample(start_time, duration, values, infos.next_block_time);
1476 self.intrinsic_value = value;
1477
1478 return true;
1479 }
1480
1481 if event.cancel_time.is_some() {
1483 let value = compute_set_value_curve_sample(start_time, duration, values, end_time);
1484
1485 self.intrinsic_value = value;
1486
1487 let mut last_event = self.event_timeline.pop().unwrap();
1488 last_event.time = end_time;
1489 last_event.value = value;
1490 self.last_event = Some(last_event);
1491 } else {
1493 let value = values[values.len() - 1];
1494
1495 let mut last_event = self.event_timeline.pop().unwrap();
1496 last_event.time = end_time;
1497 last_event.value = value;
1498
1499 self.intrinsic_value = value;
1500 self.last_event = Some(last_event);
1501 }
1502
1503 false
1504 }
1505
1506 fn compute_buffer(&mut self, block_time: f64, dt: f64, count: usize) {
1507 let clamped = self.intrinsic_value.clamp(self.min_value, self.max_value);
1510 self.current_value.store(clamped, Ordering::Release);
1511
1512 self.buffer.clear();
1514
1515 let is_a_rate = self.automation_rate.is_a_rate();
1516 let next_block_time = dt.mul_add(count as f64, block_time);
1517
1518 let is_constant_block = match self.event_timeline.peek() {
1531 None => true,
1532 Some(event) => {
1533 if event.event_type != AudioParamEventType::LinearRampToValueAtTime
1534 && event.event_type != AudioParamEventType::ExponentialRampToValueAtTime
1535 {
1536 event.time >= next_block_time
1537 } else {
1538 false
1539 }
1540 }
1541 };
1542
1543 if !is_a_rate || is_constant_block {
1544 self.buffer.push(self.intrinsic_value);
1545 if is_constant_block {
1547 return;
1548 }
1549 }
1550
1551 let block_infos = BlockInfos {
1553 block_time,
1554 dt,
1555 count,
1556 is_a_rate,
1557 next_block_time,
1558 };
1559
1560 loop {
1561 let next_event_type = self.event_timeline.peek().map(|e| e.event_type);
1562
1563 let exit_loop = match next_event_type {
1564 None => {
1565 if is_a_rate {
1566 for _ in self.buffer.len()..count {
1570 self.buffer.push(self.intrinsic_value);
1571 }
1572 }
1573 true
1574 }
1575 Some(AudioParamEventType::SetValue) | Some(AudioParamEventType::SetValueAtTime) => {
1576 self.compute_set_value_automation(&block_infos)
1577 }
1578 Some(AudioParamEventType::LinearRampToValueAtTime) => {
1579 self.compute_linear_ramp_automation(&block_infos)
1580 }
1581 Some(AudioParamEventType::ExponentialRampToValueAtTime) => {
1582 self.compute_exponential_ramp_automation(&block_infos)
1583 }
1584 Some(AudioParamEventType::SetTargetAtTime) => {
1585 self.compute_set_target_automation(&block_infos)
1586 }
1587 Some(AudioParamEventType::SetValueCurveAtTime) => {
1588 self.compute_set_value_curve_automation(&block_infos)
1589 }
1590 _ => panic!(
1591 "AudioParamEvent {:?} should not appear in AudioParamEventTimeline",
1592 next_event_type.unwrap()
1593 ),
1594 };
1595
1596 if exit_loop {
1597 break;
1598 }
1599 }
1600 }
1601}
1602
1603pub(crate) fn audio_param_pair(
1604 descriptor: AudioParamDescriptor,
1605 registration: AudioContextRegistration,
1606) -> (AudioParam, AudioParamProcessor) {
1607 let AudioParamDescriptor {
1608 automation_rate,
1609 default_value,
1610 max_value,
1611 min_value,
1612 ..
1613 } = descriptor;
1614
1615 assert_is_finite(default_value);
1616 assert_is_finite(min_value);
1617 assert_is_finite(max_value);
1618 assert!(
1619 min_value <= default_value,
1620 "InvalidStateError - AudioParam minValue should be <= defaultValue"
1621 );
1622 assert!(
1623 default_value <= max_value,
1624 "InvalidStateError - AudioParam defaultValue should be <= maxValue"
1625 );
1626
1627 let current_value = Arc::new(AtomicF32::new(default_value));
1628
1629 let param = AudioParam {
1630 registration: registration.into(),
1631 raw_parts: AudioParamInner {
1632 default_value,
1633 max_value,
1634 min_value,
1635 automation_rate_constrained: false,
1636 automation_rate: Arc::new(Mutex::new(automation_rate)),
1637 current_value: Arc::clone(¤t_value),
1638 },
1639 };
1640
1641 let processor = AudioParamProcessor {
1642 intrinsic_value: default_value,
1643 current_value,
1644 default_value,
1645 min_value,
1646 max_value,
1647 automation_rate,
1648 event_timeline: AudioParamEventTimeline::new(),
1649 last_event: None,
1650 buffer: ArrayVec::new(),
1651 };
1652
1653 (param, processor)
1654}
1655
1656#[cfg(test)]
1657mod tests {
1658 use float_eq::assert_float_eq;
1659
1660 use crate::context::{BaseAudioContext, OfflineAudioContext};
1661 use crate::render::Alloc;
1662
1663 use super::*;
1664
1665 #[test]
1666 #[should_panic]
1667 fn test_assert_strictly_positive_fail() {
1668 assert_strictly_positive(0.);
1669 }
1670
1671 #[test]
1672 fn test_assert_strictly_positive() {
1673 assert_strictly_positive(0.1);
1674 }
1675
1676 #[test]
1677 #[should_panic]
1678 fn test_assert_not_zero_fail() {
1679 assert_not_zero(0.);
1680 }
1681
1682 #[test]
1683 fn test_assert_not_zero() {
1684 assert_not_zero(-0.1);
1685 assert_not_zero(0.1);
1686 }
1687
1688 #[test]
1689 #[should_panic]
1690 fn test_assert_sequence_length_fail() {
1691 assert_sequence_length(&[0.; 1]);
1692 }
1693
1694 #[test]
1695 fn test_assert_sequence_length() {
1696 assert_sequence_length(&[0.; 2]);
1697 }
1698
1699 #[test]
1700 fn test_default_and_accessors() {
1701 let context = OfflineAudioContext::new(1, 1, 48000.);
1702
1703 let opts = AudioParamDescriptor {
1704 name: String::new(),
1705 automation_rate: AutomationRate::A,
1706 default_value: 0.,
1707 min_value: -10.,
1708 max_value: 10.,
1709 };
1710 let (param, _render) = audio_param_pair(opts, context.mock_registration());
1711
1712 assert_eq!(param.automation_rate(), AutomationRate::A);
1713 assert_float_eq!(param.default_value(), 0., abs_all <= 0.);
1714 assert_float_eq!(param.min_value(), -10., abs_all <= 0.);
1715 assert_float_eq!(param.max_value(), 10., abs_all <= 0.);
1716 assert_float_eq!(param.value(), 0., abs_all <= 0.);
1717 }
1718
1719 #[test]
1720 fn test_automation_rate_synchronicity_on_control_thread() {
1721 let context = OfflineAudioContext::new(1, 1, 48000.);
1722
1723 let opts = AudioParamDescriptor {
1724 name: String::new(),
1725 automation_rate: AutomationRate::A,
1726 default_value: 0.,
1727 min_value: 0.,
1728 max_value: 1.,
1729 };
1730 let (param, _render) = audio_param_pair(opts, context.mock_registration());
1731
1732 param.set_automation_rate(AutomationRate::K);
1733 assert_eq!(param.automation_rate(), AutomationRate::K);
1734 }
1735
1736 #[test]
1737 fn test_audioparam_clones_in_sync() {
1738 let context = OfflineAudioContext::new(1, 1, 48000.);
1739
1740 let opts = AudioParamDescriptor {
1741 name: String::new(),
1742 automation_rate: AutomationRate::A,
1743 default_value: 0.,
1744 min_value: -10.,
1745 max_value: 10.,
1746 };
1747 let (param1, mut render) = audio_param_pair(opts, context.mock_registration());
1748 let param2 = param1.clone();
1749
1750 param1.set_automation_rate(AutomationRate::K);
1752 assert_eq!(param2.automation_rate(), AutomationRate::K);
1753
1754 render.handle_incoming_event(param1.set_value_raw(2.));
1756 assert_float_eq!(param1.value(), 2., abs_all <= 0.);
1757 assert_float_eq!(param2.value(), 2., abs_all <= 0.);
1758
1759 render.handle_incoming_event(param2.set_value_raw(3.));
1761 assert_float_eq!(param1.value(), 3., abs_all <= 0.);
1762 assert_float_eq!(param2.value(), 3., abs_all <= 0.);
1763 }
1764
1765 #[test]
1766 fn test_set_value() {
1767 {
1768 let context = OfflineAudioContext::new(1, 1, 48000.);
1769
1770 let opts = AudioParamDescriptor {
1771 name: String::new(),
1772 automation_rate: AutomationRate::A,
1773 default_value: 0.,
1774 min_value: -10.,
1775 max_value: 10.,
1776 };
1777 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1778
1779 render.handle_incoming_event(param.set_value_raw(2.));
1780
1781 assert_float_eq!(param.value(), 2., abs_all <= 0.);
1782
1783 let vs = render.compute_intrinsic_values(0., 1., 10);
1784
1785 assert_float_eq!(param.value(), 2., abs_all <= 0.);
1786 assert_float_eq!(vs, &[2.; 10][..], abs_all <= 0.);
1787 }
1788
1789 {
1791 let context = OfflineAudioContext::new(1, 1, 48000.);
1792
1793 let opts = AudioParamDescriptor {
1794 name: String::new(),
1795 automation_rate: AutomationRate::A,
1796 default_value: 0.,
1797 min_value: 0.,
1798 max_value: 1.,
1799 };
1800 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1801
1802 render.handle_incoming_event(param.set_value_raw(2.));
1803
1804 assert_float_eq!(param.value(), 1., abs_all <= 0.);
1805
1806 let vs = render.compute_intrinsic_values(0., 1., 10);
1807
1808 assert_float_eq!(param.value(), 1., abs_all <= 0.);
1810 assert_float_eq!(vs, &[2.; 10][..], abs_all <= 0.);
1811 }
1812 }
1813
1814 #[test]
1815 fn test_steps_a_rate() {
1816 let context = OfflineAudioContext::new(1, 1, 48000.);
1817
1818 {
1819 let opts = AudioParamDescriptor {
1820 name: String::new(),
1821 automation_rate: AutomationRate::A,
1822 default_value: 0.,
1823 min_value: -10.,
1824 max_value: 10.,
1825 };
1826 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1827
1828 render.handle_incoming_event(param.set_value_at_time_raw(5., 2.0));
1829 render.handle_incoming_event(param.set_value_at_time_raw(12., 8.0)); render.handle_incoming_event(param.set_value_at_time_raw(8., 10.0)); let vs = render.compute_intrinsic_values(0., 1., 10);
1833 assert_float_eq!(
1834 vs,
1835 &[0., 0., 5., 5., 5., 5., 5., 5., 12., 12.][..],
1836 abs_all <= 0.
1837 );
1838
1839 let vs = render.compute_intrinsic_values(10., 1., 10);
1841 assert_float_eq!(vs, &[8.; 1][..], abs_all <= 0.);
1842 }
1843
1844 {
1845 let opts = AudioParamDescriptor {
1847 name: String::new(),
1848 automation_rate: AutomationRate::A,
1849 default_value: 0.,
1850 min_value: -10.,
1851 max_value: 10.,
1852 };
1853 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1854
1855 render.handle_incoming_event(param.set_value_at_time_raw(5., 2.0));
1856 render.handle_incoming_event(param.set_value_at_time_raw(8., 12.0));
1857
1858 let vs = render.compute_intrinsic_values(0., 1., 10);
1859 assert_float_eq!(
1860 vs,
1861 &[0., 0., 5., 5., 5., 5., 5., 5., 5., 5.][..],
1862 abs_all <= 0.
1863 );
1864
1865 let vs = render.compute_intrinsic_values(10., 1., 10);
1866 assert_float_eq!(
1867 vs,
1868 &[5., 5., 8., 8., 8., 8., 8., 8., 8., 8.][..],
1869 abs_all <= 0.
1870 );
1871 }
1872 }
1873
1874 #[test]
1875 fn test_steps_k_rate() {
1876 let context = OfflineAudioContext::new(1, 1, 48000.);
1877 let opts = AudioParamDescriptor {
1878 name: String::new(),
1879 automation_rate: AutomationRate::K,
1880 default_value: 0.,
1881 min_value: -10.,
1882 max_value: 10.,
1883 };
1884 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1885
1886 render.handle_incoming_event(param.set_value_at_time_raw(5., 2.0));
1887 render.handle_incoming_event(param.set_value_at_time_raw(12., 8.0)); render.handle_incoming_event(param.set_value_at_time_raw(8., 10.0)); render.handle_incoming_event(param.set_value_at_time_raw(3., 14.0)); let vs = render.compute_intrinsic_values(0., 1., 10);
1892 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
1893
1894 let vs = render.compute_intrinsic_values(10., 1., 10);
1895 assert_float_eq!(vs, &[8.; 1][..], abs_all <= 0.);
1896
1897 let vs = render.compute_intrinsic_values(20., 1., 10);
1898 assert_float_eq!(vs, &[3.; 1][..], abs_all <= 0.);
1899 }
1900
1901 #[test]
1902 fn test_linear_ramp_arate() {
1903 let context = OfflineAudioContext::new(1, 1, 48000.);
1904
1905 let opts = AudioParamDescriptor {
1906 name: String::new(),
1907 automation_rate: AutomationRate::A,
1908 default_value: 0.,
1909 min_value: -10.,
1910 max_value: 10.,
1911 };
1912 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1913
1914 render.handle_incoming_event(param.set_value_at_time_raw(5., 2.0));
1916 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(8.0, 5.0));
1918 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(0., 13.0));
1920
1921 let vs = render.compute_intrinsic_values(0., 1., 10);
1922 assert_float_eq!(
1923 vs,
1924 &[0., 0., 5., 6., 7., 8., 7., 6., 5., 4.][..],
1925 abs_all <= 0.
1926 );
1927 }
1928
1929 #[test]
1930 fn test_linear_ramp_arate_end_of_block() {
1931 let context = OfflineAudioContext::new(1, 1, 48000.);
1932
1933 let opts = AudioParamDescriptor {
1934 name: String::new(),
1935 automation_rate: AutomationRate::A,
1936 default_value: 0.,
1937 min_value: -10.,
1938 max_value: 10.,
1939 };
1940 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1941
1942 render.handle_incoming_event(param.set_value_at_time_raw(0., 0.));
1944 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(9.0, 9.0));
1946
1947 let vs = render.compute_intrinsic_values(0., 1., 10);
1948 assert_float_eq!(
1949 vs,
1950 &[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.][..],
1951 abs_all <= 0.
1952 );
1953 }
1954
1955 #[test]
1956 fn test_linear_ramp_arate_implicit_set_value() {
1961 let context = OfflineAudioContext::new(1, 1, 48000.);
1962
1963 let opts = AudioParamDescriptor {
1964 name: String::new(),
1965 automation_rate: AutomationRate::A,
1966 default_value: 0.,
1967 min_value: -10.,
1968 max_value: 10.,
1969 };
1970 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1971
1972 let vs = render.compute_intrinsic_values(0., 1., 10);
1977 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
1978
1979 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(10.0, 20.0));
1981
1982 let vs = render.compute_intrinsic_values(10., 1., 10);
1983 assert_float_eq!(
1984 vs,
1985 &[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.][..],
1986 abs_all <= 0.
1987 );
1988
1989 let vs = render.compute_intrinsic_values(20., 1., 10);
1991 assert_float_eq!(vs, &[10.; 10][..], abs_all <= 0.);
1992 }
1993
1994 #[test]
1995 fn test_linear_ramp_arate_multiple_blocks() {
1996 let context = OfflineAudioContext::new(1, 1, 48000.);
1998
1999 let opts = AudioParamDescriptor {
2000 name: String::new(),
2001 automation_rate: AutomationRate::A,
2002 default_value: 0.,
2003 min_value: -20.,
2004 max_value: 20.,
2005 };
2006 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2007
2008 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(20.0, 20.0));
2010
2011 let vs = render.compute_intrinsic_values(0., 1., 10);
2013 assert_float_eq!(
2014 vs,
2015 &[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.][..],
2016 abs_all <= 0.
2017 );
2018 assert_float_eq!(param.value(), 0., abs <= 0.);
2019
2020 let vs = render.compute_intrinsic_values(10., 1., 10);
2022 assert_float_eq!(
2023 vs,
2024 &[10., 11., 12., 13., 14., 15., 16., 17., 18., 19.][..],
2025 abs_all <= 0.
2026 );
2027 assert_float_eq!(param.value(), 10., abs <= 0.);
2028
2029 let vs = render.compute_intrinsic_values(20., 1., 10);
2031 assert_float_eq!(vs, &[20.0; 10][..], abs_all <= 0.);
2032 assert_float_eq!(param.value(), 20., abs <= 0.);
2033 }
2034
2035 #[test]
2036 fn test_linear_ramp_krate_multiple_blocks() {
2037 let context = OfflineAudioContext::new(1, 1, 48000.);
2039
2040 {
2041 let opts = AudioParamDescriptor {
2042 name: String::new(),
2043 automation_rate: AutomationRate::K,
2044 default_value: 0.,
2045 min_value: -20.,
2046 max_value: 20.,
2047 };
2048 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2049
2050 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(20.0, 20.0));
2052 let vs = render.compute_intrinsic_values(0., 1., 10);
2054 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
2055 assert_float_eq!(param.value(), 0., abs <= 0.);
2056 let vs = render.compute_intrinsic_values(10., 1., 10);
2058 assert_float_eq!(vs, &[10.; 1][..], abs_all <= 0.);
2059 assert_float_eq!(param.value(), 10., abs <= 0.);
2060 let vs = render.compute_intrinsic_values(20., 1., 10);
2062 assert_float_eq!(vs, &[20.0; 1][..], abs_all <= 0.);
2063 assert_float_eq!(param.value(), 20., abs <= 0.);
2064 }
2065
2066 {
2067 let opts = AudioParamDescriptor {
2069 name: String::new(),
2070 automation_rate: AutomationRate::K,
2071 default_value: 0.,
2072 min_value: -20.,
2073 max_value: 20.,
2074 };
2075 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2076
2077 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(15.0, 15.0));
2079 let vs = render.compute_intrinsic_values(0., 1., 10);
2081 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
2082 assert_float_eq!(param.value(), 0., abs <= 0.);
2083 let vs = render.compute_intrinsic_values(10., 1., 10);
2085 assert_float_eq!(vs, &[10.; 1][..], abs_all <= 0.);
2086 assert_float_eq!(param.value(), 10., abs <= 0.);
2087 let vs = render.compute_intrinsic_values(20., 1., 10);
2089 assert_float_eq!(vs, &[15.0; 1][..], abs_all <= 0.);
2090 assert_float_eq!(param.value(), 15., abs <= 0.);
2091 }
2092 }
2093
2094 #[test]
2095 fn test_linear_ramp_start_time() {
2096 let context = OfflineAudioContext::new(1, 1, 48000.);
2097
2098 let opts = AudioParamDescriptor {
2099 name: String::new(),
2100 automation_rate: AutomationRate::A,
2101 default_value: 0.,
2102 min_value: -10.,
2103 max_value: 10.,
2104 };
2105 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2106
2107 render.handle_incoming_event(param.set_value_at_time_raw(1., 0.));
2108 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(-1., 10.));
2109 let vs = render.compute_intrinsic_values(0., 1., 10);
2110 assert_float_eq!(
2111 vs,
2112 &[1., 0.8, 0.6, 0.4, 0.2, 0., -0.2, -0.4, -0.6, -0.8][..],
2113 abs_all <= 1e-7
2114 );
2115
2116 let vs = render.compute_intrinsic_values(10., 1., 10);
2117 assert_float_eq!(vs, &[-1.; 10][..], abs_all <= 0.);
2118
2119 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(1., 30.));
2121
2122 let vs = render.compute_intrinsic_values(20., 1., 10);
2123 assert_float_eq!(
2124 vs,
2125 &[0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9][..],
2126 abs_all <= 1e-7
2127 );
2128 }
2129
2130 #[test]
2131 fn test_exponential_ramp_a_rate() {
2132 let context = OfflineAudioContext::new(1, 1, 48000.);
2133
2134 let opts = AudioParamDescriptor {
2135 name: String::new(),
2136 automation_rate: AutomationRate::A,
2137 default_value: 0.,
2138 min_value: 0.,
2139 max_value: 1.,
2140 };
2141 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2142
2143 render.handle_incoming_event(param.set_value_at_time_raw(0.0001, 0.));
2145 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(1.0, 10.));
2147
2148 let mut res = Vec::<f32>::with_capacity(10);
2151 let start: f32 = 0.0001;
2152 let end: f32 = 1.;
2153
2154 for t in 0..10 {
2155 let value = start * (end / start).powf(t as f32 / 10.);
2156 res.push(value);
2157 }
2158
2159 let vs = render.compute_intrinsic_values(0., 1., 10);
2160 assert_float_eq!(vs, &res[..], abs_all <= 0.);
2161
2162 let vs = render.compute_intrinsic_values(10., 1., 10);
2163 assert_float_eq!(vs, &[1.0; 10][..], abs_all <= 0.);
2164 }
2165
2166 #[test]
2167 fn test_exponential_ramp_a_rate_multiple_blocks() {
2168 let context = OfflineAudioContext::new(1, 1, 48000.);
2169
2170 let opts = AudioParamDescriptor {
2171 name: String::new(),
2172 automation_rate: AutomationRate::A,
2173 default_value: 0.,
2174 min_value: 0.,
2175 max_value: 1.,
2176 };
2177 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2178
2179 let start: f32 = 0.0001; let end: f32 = 1.;
2181 render.handle_incoming_event(param.set_value_at_time_raw(start, 3.));
2182 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(end, 13.));
2184
2185 let mut res = vec![0.; 3];
2187 for t in 0..10 {
2190 let value = start * (end / start).powf(t as f32 / 10.);
2191 res.push(value);
2192 }
2193 res.append(&mut vec![1.; 7]);
2195
2196 let vs = render.compute_intrinsic_values(0., 1., 10);
2197 assert_float_eq!(vs, &res[0..10], abs_all <= 0.);
2198 assert_float_eq!(param.value(), res[0], abs <= 0.);
2199
2200 let vs = render.compute_intrinsic_values(10., 1., 10);
2201 assert_float_eq!(vs, &res[10..20], abs_all <= 0.);
2202 assert_float_eq!(param.value(), res[10], abs <= 0.);
2203 }
2204
2205 #[test]
2206 fn test_exponential_ramp_a_rate_zero_and_opposite_target() {
2207 let context = OfflineAudioContext::new(1, 1, 48000.);
2208
2209 {
2210 let opts = AudioParamDescriptor {
2212 name: String::new(),
2213 automation_rate: AutomationRate::A,
2214 default_value: 0.,
2215 min_value: 0.,
2216 max_value: 1.,
2217 };
2218 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2219
2220 render.handle_incoming_event(param.set_value_at_time_raw(0., 0.));
2222 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(1.0, 5.));
2224
2225 let vs = render.compute_intrinsic_values(0., 1., 10);
2226 assert_float_eq!(
2227 vs,
2228 &[0., 0., 0., 0., 0., 1., 1., 1., 1., 1.][..],
2229 abs_all <= 0.
2230 );
2231 }
2232
2233 {
2234 let opts = AudioParamDescriptor {
2236 name: String::new(),
2237 automation_rate: AutomationRate::A,
2238 default_value: 0.,
2239 min_value: -1.,
2240 max_value: 1.,
2241 };
2242 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2243
2244 render.handle_incoming_event(param.set_value_at_time_raw(-1., 0.));
2246 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(1.0, 5.));
2248
2249 let vs = render.compute_intrinsic_values(0., 1., 10);
2250 assert_float_eq!(
2251 vs,
2252 &[-1., -1., -1., -1., -1., 1., 1., 1., 1., 1.][..],
2253 abs_all <= 0.
2254 );
2255 }
2256 }
2257
2258 #[test]
2259 #[should_panic]
2260 fn test_exponential_ramp_to_zero() {
2261 let context = OfflineAudioContext::new(1, 1, 48000.);
2262
2263 let opts = AudioParamDescriptor {
2264 name: String::new(),
2265 automation_rate: AutomationRate::A,
2266 default_value: 1.,
2267 min_value: 0.,
2268 max_value: 1.,
2269 };
2270 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2271 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(0.0, 10.));
2272 }
2273
2274 #[test]
2275 fn test_exponential_ramp_k_rate_multiple_blocks() {
2276 let context = OfflineAudioContext::new(1, 1, 48000.);
2277
2278 let opts = AudioParamDescriptor {
2279 name: String::new(),
2280 automation_rate: AutomationRate::K,
2281 default_value: 0.,
2282 min_value: 0.,
2283 max_value: 1.,
2284 };
2285 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2286
2287 let start: f32 = 0.0001; let end: f32 = 1.;
2289 render.handle_incoming_event(param.set_value_at_time_raw(start, 3.));
2290 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(end, 13.));
2292
2293 let mut res = vec![0.; 3];
2295 for t in 0..10 {
2298 let value = start * (end / start).powf(t as f32 / 10.);
2299 res.push(value);
2300 }
2301 res.append(&mut vec![1.; 7]);
2303
2304 let vs = render.compute_intrinsic_values(0., 1., 10);
2306 assert_float_eq!(vs, &[res[0]; 1][..], abs_all <= 0.);
2307
2308 let vs = render.compute_intrinsic_values(10., 1., 10);
2309 assert_float_eq!(vs, &[res[10]; 1][..], abs_all <= 0.);
2310
2311 let vs = render.compute_intrinsic_values(20., 1., 10);
2312 assert_float_eq!(vs, &[1.; 1][..], abs_all <= 0.);
2313 }
2314
2315 #[test]
2316 fn test_exponential_ramp_k_rate_zero_and_opposite_target() {
2317 let context = OfflineAudioContext::new(1, 1, 48000.);
2318
2319 {
2320 let opts = AudioParamDescriptor {
2322 name: String::new(),
2323 automation_rate: AutomationRate::K,
2324 default_value: 0.,
2325 min_value: 0.,
2326 max_value: 1.,
2327 };
2328 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2329
2330 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(1.0, 5.));
2332
2333 let vs = render.compute_intrinsic_values(0., 1., 10);
2334 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
2335
2336 let vs = render.compute_intrinsic_values(10., 1., 10);
2337 assert_float_eq!(vs, &[1.; 1][..], abs_all <= 0.);
2338 }
2339
2340 {
2341 let opts = AudioParamDescriptor {
2343 name: String::new(),
2344 automation_rate: AutomationRate::K,
2345 default_value: -1.,
2346 min_value: -1.,
2347 max_value: 1.,
2348 };
2349 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2350
2351 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(1.0, 5.));
2353
2354 let vs = render.compute_intrinsic_values(0., 1., 10);
2355 assert_float_eq!(vs, &[-1.; 1][..], abs_all <= 0.);
2356
2357 let vs = render.compute_intrinsic_values(10., 1., 10);
2358 assert_float_eq!(vs, &[1.; 1][..], abs_all <= 0.);
2359 }
2360 }
2361
2362 #[test]
2363 fn test_exponential_ramp_start_time() {
2364 let context = OfflineAudioContext::new(1, 1, 48000.);
2365
2366 let opts = AudioParamDescriptor {
2367 name: String::new(),
2368 automation_rate: AutomationRate::A,
2369 default_value: 0.,
2370 min_value: -10.,
2371 max_value: 10.,
2372 };
2373 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2374
2375 render.handle_incoming_event(param.set_value_at_time_raw(0., 0.));
2376 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(1., 10.));
2377
2378 let vs = render.compute_intrinsic_values(0., 1., 10);
2379 assert_float_eq!(
2380 vs,
2381 &[0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9][..],
2382 abs_all <= 1e-7
2383 );
2384
2385 let vs = render.compute_intrinsic_values(10., 1., 10);
2386 assert_float_eq!(vs, &[1.; 10][..], abs_all <= 0.);
2387
2388 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(0.0001, 30.));
2390 let vs = render.compute_intrinsic_values(20., 1., 10);
2391 let start: f32 = 1.;
2393 let end: f32 = 0.0001;
2394 let mut res = [0.; 20];
2395 for (t, v) in res.iter_mut().enumerate() {
2396 *v = start * (end / start).powf(t as f32 / 20.);
2397 }
2398
2399 assert_float_eq!(vs, &res[10..], abs_all <= 1e-7);
2400 }
2401
2402 #[test]
2403 fn test_set_target_at_time_a_rate() {
2404 let context = OfflineAudioContext::new(1, 1, 48000.);
2405
2406 {
2407 let opts = AudioParamDescriptor {
2408 name: String::new(),
2409 automation_rate: AutomationRate::A,
2410 default_value: 0.,
2411 min_value: 0.,
2412 max_value: 1.,
2413 };
2414 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2415 let v0: f32 = 0.;
2417 let v1: f32 = 1.;
2418 let t0: f64 = 0.;
2419 let time_constant: f64 = 1.;
2420
2421 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2422 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2423 let vs = render.compute_intrinsic_values(0., 1., 10);
2424
2425 let mut res = Vec::<f32>::with_capacity(10);
2426 for t in 0..10 {
2427 let val = v1 + (v0 - v1) * (-((t as f64 - t0) / time_constant)).exp() as f32;
2428 res.push(val);
2429 }
2430
2431 assert_float_eq!(vs, &res[..], abs_all <= 0.);
2432 }
2433
2434 {
2435 let opts = AudioParamDescriptor {
2437 name: String::new(),
2438 automation_rate: AutomationRate::A,
2439 default_value: 0.,
2440 min_value: 0.,
2441 max_value: 1.,
2442 };
2443 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2444 let v0: f32 = 0.; let v1: f32 = 1.;
2447 let t0: f64 = 0.;
2448 let time_constant: f64 = 1.;
2449
2450 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2451 let vs = render.compute_intrinsic_values(0., 1., 10);
2452
2453 let mut res = Vec::<f32>::with_capacity(10);
2454 for t in 0..10 {
2455 let val = v1 + (v0 - v1) * (-((t as f64 - t0) / time_constant)).exp() as f32;
2456 res.push(val);
2457 }
2458
2459 assert_float_eq!(vs, &res[..], abs_all <= 0.);
2460 }
2461
2462 {
2463 let opts = AudioParamDescriptor {
2465 name: String::new(),
2466 automation_rate: AutomationRate::A,
2467 default_value: 0.,
2468 min_value: 0.,
2469 max_value: 100.,
2470 };
2471 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2472 let v0: f32 = 1.;
2474 let v1: f32 = 42.;
2475 let t0: f64 = 1.;
2476 let time_constant: f64 = 2.1;
2477
2478 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2479 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2480
2481 let mut res = Vec::<f32>::with_capacity(10);
2482 for t in 0..10 {
2483 let val = v1 + (v0 - v1) * (-((t as f64 - t0) / time_constant)).exp() as f32;
2484 res.push(val);
2485 }
2486 res[0] = 0.;
2488
2489 let vs = render.compute_intrinsic_values(0., 1., 10);
2490 assert_float_eq!(vs, &res[..], abs_all <= 0.);
2491 }
2492
2493 {
2494 let opts = AudioParamDescriptor {
2496 name: String::new(),
2497 automation_rate: AutomationRate::A,
2498 default_value: 0.,
2499 min_value: 0.,
2500 max_value: 100.,
2501 };
2502 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2503 render.handle_incoming_event(param.set_target_at_time_raw(1., 1., 0.));
2504
2505 let mut res = [1.; 10];
2506 res[0] = 0.; let vs = render.compute_intrinsic_values(0., 1., 10);
2509 assert_float_eq!(vs, &res[..], abs_all <= 0.);
2510 }
2511 }
2512
2513 #[test]
2514 fn test_set_target_at_time_a_rate_multiple_blocks() {
2515 let context = OfflineAudioContext::new(1, 1, 48000.);
2516
2517 {
2518 let opts = AudioParamDescriptor {
2519 name: String::new(),
2520 automation_rate: AutomationRate::A,
2521 default_value: 0.,
2522 min_value: 0.,
2523 max_value: 2.,
2524 };
2525 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2526 let v0: f32 = 0.;
2528 let v1: f32 = 2.;
2529 let t0: f64 = 0.;
2530 let time_constant: f64 = 1.;
2531 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2533 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2534
2535 let mut res = Vec::<f32>::with_capacity(20);
2536 for t in 0..20 {
2537 let val = v1 + (v0 - v1) * (-((t as f64 - t0) / time_constant)).exp() as f32;
2538 res.push(val);
2539 }
2540
2541 let vs = render.compute_intrinsic_values(0., 1., 10);
2542 assert_float_eq!(vs, &res[0..10], abs_all <= 0.);
2543
2544 let vs = render.compute_intrinsic_values(10., 1., 10);
2545 assert_float_eq!(vs, &res[10..20], abs_all <= 0.);
2546 }
2547 }
2548
2549 #[test]
2550 fn test_set_target_at_time_a_rate_followed_by_set_value() {
2551 let context = OfflineAudioContext::new(1, 1, 48000.);
2552
2553 {
2554 let opts = AudioParamDescriptor {
2555 name: String::new(),
2556 automation_rate: AutomationRate::A,
2557 default_value: 0.,
2558 min_value: 0.,
2559 max_value: 2.,
2560 };
2561 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2562 let v0: f32 = 0.;
2564 let v1: f32 = 2.;
2565 let t0: f64 = 0.;
2566 let time_constant: f64 = 1.;
2567
2568 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2569 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2570 render.handle_incoming_event(param.set_value_at_time_raw(0.5, 15.));
2571
2572 let mut res = Vec::<f32>::with_capacity(20);
2573
2574 for t in 0..15 {
2575 let val = v1 + (v0 - v1) * (-((t as f64 - t0) / time_constant)).exp() as f32;
2576 res.push(val);
2577 }
2578
2579 res.resize(20, 0.5);
2580
2581 let vs = render.compute_intrinsic_values(0., 1., 10);
2582 assert_float_eq!(vs, &res[0..10], abs_all <= 0.);
2583
2584 let vs = render.compute_intrinsic_values(10., 1., 10);
2585 assert_float_eq!(vs, &res[10..20], abs_all <= 0.);
2586 }
2587 }
2588
2589 #[test]
2590 fn test_set_target_at_time_ends_at_threshold() {
2591 let context = OfflineAudioContext::new(1, 1, 48000.);
2592 let opts = AudioParamDescriptor {
2593 name: String::new(),
2594 automation_rate: AutomationRate::A,
2595 default_value: 0.,
2596 min_value: 0.,
2597 max_value: 2.,
2598 };
2599 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2600
2601 render.handle_incoming_event(param.set_value_at_time_raw(1., 0.));
2602 render.handle_incoming_event(param.set_target_at_time_raw(0., 1., 0.2));
2603
2604 let vs = render.compute_intrinsic_values(0., 1., 128);
2605 for v in vs.iter() {
2606 assert!(!v.is_subnormal());
2607 }
2608
2609 let peek = render.event_timeline.peek();
2611 assert_eq!(
2612 peek.unwrap().event_type,
2613 AudioParamEventType::SetValueAtTime
2614 );
2615
2616 let vs = render.compute_intrinsic_values(10., 1., 128);
2618 assert_float_eq!(vs[..], [0.; 128], abs_all <= 0.);
2619 }
2620
2621 #[test]
2622 fn test_set_target_at_time_waits_for_start_time() {
2623 let context = OfflineAudioContext::new(1, 1, 48000.);
2624 let opts = AudioParamDescriptor {
2625 name: String::new(),
2626 automation_rate: AutomationRate::A,
2627 default_value: 0.,
2628 min_value: 0.,
2629 max_value: 2.,
2630 };
2631 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2632
2633 render.handle_incoming_event(param.set_value_at_time_raw(1., 0.));
2634 render.handle_incoming_event(param.set_target_at_time_raw(0., 5., 1.));
2635
2636 let vs = render.compute_intrinsic_values(0., 1., 10);
2637 assert_float_eq!(vs[0], 1., abs <= 0.);
2638 assert_float_eq!(vs[1], 1., abs <= 0.);
2639 assert_float_eq!(vs[2], 1., abs <= 0.);
2640 assert_float_eq!(vs[3], 1., abs <= 0.);
2641 assert_float_eq!(vs[4], 1., abs <= 0.);
2642 assert_float_eq!(vs[5], 1., abs <= 0.);
2643 }
2644
2645 #[test]
2646 fn test_set_target_at_time_a_rate_followed_by_ramp() {
2647 let context = OfflineAudioContext::new(1, 1, 48000.);
2648 {
2649 let opts = AudioParamDescriptor {
2650 name: String::new(),
2651 automation_rate: AutomationRate::A,
2652 default_value: 0.,
2653 min_value: 0.,
2654 max_value: 10.,
2655 };
2656 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2657 let v0: f32 = 0.;
2659 let v1: f32 = 2.;
2660 let t0: f64 = 0.;
2661 let time_constant: f64 = 10.;
2662
2663 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2664 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2665
2666 let mut res = Vec::<f32>::with_capacity(20);
2667
2668 for t in 0..11 {
2669 let val = v1 + (v0 - v1) * (-((t as f64 - t0) / time_constant)).exp() as f32;
2671 res.push(val);
2672 }
2673
2674 let vs = render.compute_intrinsic_values(0., 1., 10);
2675 assert_float_eq!(vs, &res[0..10], abs_all <= 0.);
2676
2677 let v0 = res.pop().unwrap(); let v1 = 10.;
2680 let t0 = 10.;
2681 let t1 = 20.;
2682
2683 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(v1, t1));
2684
2685 for t in 10..20 {
2686 let time = t as f64;
2687 let value = v0 + (v1 - v0) * (time - t0) as f32 / (t1 - t0) as f32;
2688 res.push(value);
2689 }
2690
2691 let vs = render.compute_intrinsic_values(10., 1., 10);
2692 assert_float_eq!(vs, &res[10..20], abs_all <= 1.0e-6);
2693 let vs = render.compute_intrinsic_values(20., 1., 10);
2695 assert_float_eq!(vs, &[v1; 10][..], abs_all <= 0.);
2696 }
2697 }
2698
2699 #[test]
2700 fn test_set_target_at_time_k_rate_multiple_blocks() {
2701 let context = OfflineAudioContext::new(1, 1, 48000.);
2702
2703 {
2704 let opts = AudioParamDescriptor {
2705 name: String::new(),
2706 automation_rate: AutomationRate::K,
2707 default_value: 0.,
2708 min_value: 0.,
2709 max_value: 2.,
2710 };
2711 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2712 let v0: f32 = 0.;
2714 let v1: f32 = 2.;
2715 let t0: f64 = 0.;
2716 let time_constant: f64 = 1.;
2717 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2719 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2720
2721 let mut res = Vec::<f32>::with_capacity(20);
2722 for t in 0..20 {
2723 let val = v1 + (v0 - v1) * (-((t as f64 - t0) / time_constant)).exp() as f32;
2724 res.push(val);
2725 }
2726
2727 let vs = render.compute_intrinsic_values(0., 1., 10);
2728 assert_float_eq!(vs, &[res[0]; 1][..], abs_all <= 0.);
2729
2730 let vs = render.compute_intrinsic_values(10., 1., 10);
2731 assert_float_eq!(vs, &[res[10]; 1][..], abs_all <= 0.);
2732 }
2733 }
2734
2735 #[test]
2736 fn test_set_target_at_time_snap_to_value() {
2738 let context = OfflineAudioContext::new(1, 1, 48000.);
2739 let opts = AudioParamDescriptor {
2740 name: String::new(),
2741 automation_rate: AutomationRate::A,
2742 default_value: 0.,
2743 min_value: 0.,
2744 max_value: 1.,
2745 };
2746 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2747 let v0: f32 = 1.;
2748 let v1: f32 = 0.;
2749 let t0: f64 = 0.;
2750 let time_constant: f64 = 1.;
2751
2752 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2753 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2754
2755 let mut res = [0.; 30];
2756 res.iter_mut().enumerate().for_each(|(t, r)| {
2758 *r = v1 + (v0 - v1) * (-((t as f64 - t0) / time_constant)).exp() as f32;
2759 });
2760
2761 let vs = render.compute_intrinsic_values(0., 1., 10);
2762 assert_float_eq!(vs, &res[..10], abs_all <= 0.);
2763
2764 let vs = render.compute_intrinsic_values(10., 1., 10);
2765 assert_float_eq!(vs, &res[10..20], abs_all <= 0.);
2766
2767 let vs = render.compute_intrinsic_values(20., 1., 10);
2770 assert_float_eq!(vs, &res[20..30], abs_all <= 0.);
2771
2772 let vs = render.compute_intrinsic_values(30., 1., 10);
2774 assert_float_eq!(vs, &[0.; 10][..], abs_all <= 0.);
2775 }
2776
2777 #[test]
2778 fn test_cancel_scheduled_values() {
2779 let context = OfflineAudioContext::new(1, 1, 48000.);
2780
2781 let opts = AudioParamDescriptor {
2782 name: String::new(),
2783 automation_rate: AutomationRate::A,
2784 default_value: 0.,
2785 min_value: 0.,
2786 max_value: 10.,
2787 };
2788 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2789 for t in 0..10 {
2790 render.handle_incoming_event(param.set_value_at_time_raw(t as f32, t as f64));
2791 }
2792
2793 render.handle_incoming_event(param.cancel_scheduled_values_raw(5.));
2794
2795 let vs = render.compute_intrinsic_values(0., 1., 10);
2796 assert_float_eq!(
2797 vs,
2798 &[0., 1., 2., 3., 4., 4., 4., 4., 4., 4.][..],
2799 abs_all <= 0.
2800 );
2801 }
2802
2803 #[test]
2804 fn test_cancel_scheduled_values_ramp() {
2805 let context = OfflineAudioContext::new(1, 1, 48000.);
2806
2807 {
2808 let opts = AudioParamDescriptor {
2809 name: String::new(),
2810 automation_rate: AutomationRate::A,
2811 default_value: 0.,
2812 min_value: 0.,
2813 max_value: 10.,
2814 };
2815 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2816
2817 render.handle_incoming_event(param.set_value_at_time_raw(0., 0.));
2818 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(10., 10.));
2819 render.handle_incoming_event(param.cancel_scheduled_values_raw(10.));
2821
2822 let vs = render.compute_intrinsic_values(0., 1., 10);
2823 assert_float_eq!(vs, &[0.; 10][..], abs_all <= 0.);
2824 }
2825
2826 {
2828 let opts = AudioParamDescriptor {
2829 name: String::new(),
2830 automation_rate: AutomationRate::A,
2831 default_value: 0.,
2832 min_value: 0.,
2833 max_value: 20.,
2834 };
2835 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2836
2837 render.handle_incoming_event(param.set_value_at_time_raw(0., 0.));
2838 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(20., 20.));
2839
2840 let vs = render.compute_intrinsic_values(0., 1., 10);
2841 assert_float_eq!(
2842 vs,
2843 &[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.][..],
2844 abs_all <= 0.
2845 );
2846
2847 render.handle_incoming_event(param.cancel_scheduled_values_raw(10.));
2850
2851 let vs = render.compute_intrinsic_values(10., 1., 10);
2852 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
2853 }
2854
2855 {
2859 let opts = AudioParamDescriptor {
2860 name: String::new(),
2861 automation_rate: AutomationRate::A,
2862 default_value: 0.,
2863 min_value: 0.,
2864 max_value: 10.,
2865 };
2866 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2867
2868 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(10., 10.));
2871 render.handle_incoming_event(param.cancel_scheduled_values_raw(10.)); let vs = render.compute_intrinsic_values(0., 1., 10);
2874 assert_float_eq!(vs, &[0.; 10][..], abs_all <= 0.);
2875 }
2876
2877 {
2878 let opts = AudioParamDescriptor {
2879 name: String::new(),
2880 automation_rate: AutomationRate::A,
2881 default_value: 0.,
2882 min_value: 0.,
2883 max_value: 20.,
2884 };
2885 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2886
2887 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(20., 20.));
2888
2889 let vs = render.compute_intrinsic_values(0., 1., 10);
2890 assert_float_eq!(
2891 vs,
2892 &[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.][..],
2893 abs_all <= 0.
2894 );
2895
2896 render.handle_incoming_event(param.cancel_scheduled_values_raw(10.));
2898
2899 let vs = render.compute_intrinsic_values(10., 1., 10);
2900 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
2901 }
2902 }
2903
2904 #[test]
2905 fn test_cancel_and_hold() {
2906 let context = OfflineAudioContext::new(1, 1, 48000.);
2907 {
2908 let opts = AudioParamDescriptor {
2909 name: String::new(),
2910 automation_rate: AutomationRate::A,
2911 default_value: 0.,
2912 min_value: 0.,
2913 max_value: 10.,
2914 };
2915 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2916
2917 render.handle_incoming_event(param.set_value_at_time_raw(1., 1.));
2918 render.handle_incoming_event(param.set_value_at_time_raw(2., 2.));
2919 render.handle_incoming_event(param.set_value_at_time_raw(3., 3.));
2920 render.handle_incoming_event(param.set_value_at_time_raw(4., 4.));
2921 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(2.5));
2922
2923 let vs = render.compute_intrinsic_values(0., 1., 10);
2924 assert_float_eq!(
2925 vs,
2926 &[0., 1., 2., 2., 2., 2., 2., 2., 2., 2.][0..10],
2927 abs_all <= 0.
2928 );
2929 }
2930 }
2931
2932 #[test]
2933 fn test_cancel_and_hold_during_set_target() {
2934 let context = OfflineAudioContext::new(1, 1, 48000.);
2935
2936 {
2937 let opts = AudioParamDescriptor {
2938 name: String::new(),
2939 automation_rate: AutomationRate::A,
2940 default_value: 0.,
2941 min_value: 0.,
2942 max_value: 2.,
2943 };
2944 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2945 let v0: f32 = 0.;
2947 let v1: f32 = 2.;
2948 let t0: f64 = 0.;
2949 let time_constant: f64 = 1.;
2950
2951 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2952 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2953 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(15.));
2954
2955 let mut res = Vec::<f32>::with_capacity(20);
2956
2957 for t in 0..16 {
2959 let val = v1 + (v0 - v1) * (-((t as f64 - t0) / time_constant)).exp() as f32;
2960 res.push(val);
2961 }
2962
2963 let hold_value = res.pop().unwrap();
2964 res.resize(20, hold_value);
2965
2966 let vs = render.compute_intrinsic_values(0., 1., 10);
2967 assert_float_eq!(vs, &res[0..10], abs_all <= 0.);
2968
2969 let vs = render.compute_intrinsic_values(10., 1., 10);
2970 assert_float_eq!(vs, &res[10..20], abs_all <= 0.);
2971 }
2972 }
2973
2974 #[test]
2975 fn test_cancel_and_hold_during_linear_ramp() {
2976 let context = OfflineAudioContext::new(1, 1, 48000.);
2977
2978 {
2979 let opts = AudioParamDescriptor {
2980 name: String::new(),
2981 automation_rate: AutomationRate::A,
2982 default_value: 0.,
2983 min_value: 0.,
2984 max_value: 10.,
2985 };
2986 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2987
2988 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(10., 10.));
2989 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(5.));
2990
2991 let vs = render.compute_intrinsic_values(0., 1., 10);
2992 assert_float_eq!(
2993 vs,
2994 &[0., 1., 2., 3., 4., 5., 5., 5., 5., 5.][0..10],
2995 abs_all <= 0.
2996 );
2997 }
2998
2999 {
3000 let opts = AudioParamDescriptor {
3002 name: String::new(),
3003 automation_rate: AutomationRate::A,
3004 default_value: 0.,
3005 min_value: 0.,
3006 max_value: 10.,
3007 };
3008 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3009
3010 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(10., 10.));
3011 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(4.5));
3012
3013 let vs = render.compute_intrinsic_values(0., 1., 10);
3014 assert_float_eq!(
3015 vs,
3016 &[0., 1., 2., 3., 4., 4.5, 4.5, 4.5, 4.5, 4.5][0..10],
3017 abs_all <= 0.
3018 );
3019 }
3020 }
3021
3022 #[test]
3023 fn test_cancel_and_hold_during_exponential_ramp() {
3024 let context = OfflineAudioContext::new(1, 1, 48000.);
3025
3026 {
3027 let opts = AudioParamDescriptor {
3028 name: String::new(),
3029 automation_rate: AutomationRate::A,
3030 default_value: 0.,
3031 min_value: 0.,
3032 max_value: 10.,
3033 };
3034 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3035
3036 render.handle_incoming_event(param.set_value_at_time_raw(0.0001, 0.));
3038 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(1.0, 10.));
3039 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(5.));
3040
3041 let mut res = Vec::<f32>::with_capacity(10);
3044 let start: f32 = 0.0001;
3045 let end: f32 = 1.;
3046
3047 for t in 0..6 {
3048 let value = start * (end / start).powf(t as f32 / 10.);
3049 res.push(value);
3050 }
3051
3052 let hold_value = res.pop().unwrap();
3053 res.resize(10, hold_value);
3054
3055 let vs = render.compute_intrinsic_values(0., 1., 10);
3056 assert_float_eq!(vs, &res[..], abs_all <= 0.);
3057 }
3058
3059 {
3060 let opts = AudioParamDescriptor {
3062 name: String::new(),
3063 automation_rate: AutomationRate::A,
3064 default_value: 0.,
3065 min_value: 0.,
3066 max_value: 10.,
3067 };
3068 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3069
3070 render.handle_incoming_event(param.set_value_at_time_raw(0.0001, 0.));
3072 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(1.0, 10.));
3073 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(4.5));
3074
3075 let mut res = Vec::<f32>::with_capacity(10);
3078 let start: f32 = 0.0001;
3079 let end: f32 = 1.;
3080
3081 for t in 0..5 {
3082 let value = start * (end / start).powf(t as f32 / 10.);
3083 res.push(value);
3084 }
3085
3086 let hold_value = start * (end / start).powf(4.5 / 10.);
3087 res.resize(10, hold_value);
3088
3089 let vs = render.compute_intrinsic_values(0., 1., 10);
3090 assert_float_eq!(vs, &res[..], abs_all <= 0.);
3091 }
3092 }
3093
3094 #[test]
3095 fn test_cancel_and_hold_during_set_value_curve() {
3096 let context = OfflineAudioContext::new(1, 1, 48000.);
3097
3098 {
3099 let opts = AudioParamDescriptor {
3100 name: String::new(),
3101 automation_rate: AutomationRate::A,
3102 default_value: 0.,
3103 min_value: 0.,
3104 max_value: 2.,
3105 };
3106 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3107
3108 let curve = [0., 0.5, 1., 0.5, 0.];
3109 render.handle_incoming_event(param.set_value_curve_at_time_raw(&curve[..], 0., 10.));
3110 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(5.));
3111
3112 let vs = render.compute_intrinsic_values(0., 1., 10);
3113 assert_float_eq!(
3114 vs,
3115 &[0., 0.2, 0.4, 0.6, 0.8, 1., 1., 1., 1., 1.][..],
3116 abs_all <= 1e-7
3117 );
3118 }
3119
3120 {
3121 let opts = AudioParamDescriptor {
3123 name: String::new(),
3124 automation_rate: AutomationRate::A,
3125 default_value: 0.,
3126 min_value: 0.,
3127 max_value: 2.,
3128 };
3129 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3130
3131 let curve = [0., 0.5, 1., 0.5, 0.];
3132 render.handle_incoming_event(param.set_value_curve_at_time_raw(&curve[..], 0., 10.));
3133 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(4.5));
3134
3135 let vs = render.compute_intrinsic_values(0., 1., 10);
3136 assert_float_eq!(
3137 vs,
3138 &[0., 0.2, 0.4, 0.6, 0.8, 0.9, 0.9, 0.9, 0.9, 0.9][..],
3139 abs_all <= 1e-7
3140 );
3141 }
3142 }
3143
3144 #[test]
3145 fn test_set_value_curve_at_time_a_rate() {
3146 let context = OfflineAudioContext::new(1, 1, 48000.);
3147
3148 let opts = AudioParamDescriptor {
3149 name: String::new(),
3150 automation_rate: AutomationRate::A,
3151 default_value: 0.,
3152 min_value: 0.,
3153 max_value: 10.,
3154 };
3155 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3156
3157 let curve = [0., 0.5, 1., 0.5, 0.];
3159 render.handle_incoming_event(param.set_value_curve_at_time_raw(&curve[..], 0., 10.));
3160
3161 let vs = render.compute_intrinsic_values(0., 1., 10);
3162 assert_float_eq!(
3163 vs,
3164 &[0., 0.2, 0.4, 0.6, 0.8, 1., 0.8, 0.6, 0.4, 0.2][..],
3165 abs_all <= 1e-7
3166 );
3167
3168 let vs = render.compute_intrinsic_values(10., 1., 10);
3169 assert_float_eq!(vs, &[0.; 10][..], abs_all <= 0.);
3170 }
3171
3172 #[test]
3173 fn test_set_value_curve_at_time_a_rate_multiple_frames() {
3174 let context = OfflineAudioContext::new(1, 1, 48000.);
3175
3176 let opts = AudioParamDescriptor {
3177 name: String::new(),
3178 automation_rate: AutomationRate::A,
3179 default_value: 0.,
3180 min_value: 0.,
3181 max_value: 10.,
3182 };
3183 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3184
3185 let curve = [0., 0.5, 1., 0.5, 0.];
3187 render.handle_incoming_event(param.set_value_curve_at_time_raw(&curve[..], 0., 20.));
3188
3189 let vs = render.compute_intrinsic_values(0., 1., 10);
3190 assert_float_eq!(
3191 vs,
3192 &[0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9][..],
3193 abs_all <= 1e-7
3194 );
3195
3196 let vs = render.compute_intrinsic_values(10., 1., 10);
3197 assert_float_eq!(
3198 vs,
3199 &[1., 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1][..],
3200 abs_all <= 1e-7
3201 );
3202
3203 let vs = render.compute_intrinsic_values(20., 1., 10);
3204 assert_float_eq!(vs, &[0.; 10][..], abs_all <= 0.);
3205 }
3206
3207 #[test]
3208 #[should_panic]
3209 fn test_set_value_curve_at_time_insert_while_another_event() {
3210 let context = OfflineAudioContext::new(1, 1, 48000.);
3211
3212 let opts = AudioParamDescriptor {
3213 name: String::new(),
3214 automation_rate: AutomationRate::A,
3215 default_value: 1.,
3216 min_value: 0.,
3217 max_value: 1.,
3218 };
3219 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3220
3221 render.handle_incoming_event(param.set_value_at_time_raw(0.0, 5.));
3222
3223 let curve = [0., 0.5, 1., 0.5, 0.];
3224 render.handle_incoming_event(param.set_value_curve_at_time_raw(&curve[..], 0., 10.));
3225 let _vs = render.compute_intrinsic_values(0., 1., 10);
3228 }
3229
3230 #[test]
3231 #[should_panic]
3232 fn test_set_value_curve_at_time_insert_another_event_inside() {
3233 let context = OfflineAudioContext::new(1, 1, 48000.);
3234
3235 let opts = AudioParamDescriptor {
3236 name: String::new(),
3237 automation_rate: AutomationRate::A,
3238 default_value: 1.,
3239 min_value: 0.,
3240 max_value: 1.,
3241 };
3242 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3243
3244 let curve = [0., 0.5, 1., 0.5, 0.];
3245 render.handle_incoming_event(param.set_value_curve_at_time_raw(&curve[..], 0., 10.));
3246 render.handle_incoming_event(param.set_value_at_time_raw(0.0, 5.));
3247 let _vs = render.compute_intrinsic_values(0., 1., 10);
3250 }
3251
3252 #[test]
3253 fn test_set_value_curve_waits_for_start_time() {
3254 let context = OfflineAudioContext::new(1, 1, 48000.);
3255
3256 let opts = AudioParamDescriptor {
3257 name: String::new(),
3258 automation_rate: AutomationRate::A,
3259 default_value: 0.,
3260 min_value: 0.,
3261 max_value: 10.,
3262 };
3263 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3264
3265 let curve = [0., 0.5, 1., 0.5, 0.];
3267 render.handle_incoming_event(param.set_value_curve_at_time_raw(&curve[..], 5., 10.));
3268
3269 let vs = render.compute_intrinsic_values(0., 1., 10);
3270 assert_float_eq!(
3271 vs,
3272 &[0., 0., 0., 0., 0., 0., 0.2, 0.4, 0.6, 0.8][..],
3273 abs_all <= 0.
3274 );
3275 }
3276
3277 #[test]
3278 fn test_update_automation_rate_to_k() {
3279 let context = OfflineAudioContext::new(1, 1, 48000.);
3280
3281 let opts = AudioParamDescriptor {
3282 name: String::new(),
3283 automation_rate: AutomationRate::A,
3284 default_value: 0.,
3285 min_value: -10.,
3286 max_value: 10.,
3287 };
3288 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3289
3290 render.onmessage(&mut AutomationRate::K);
3291 render.handle_incoming_event(param.set_value_at_time_raw(2., 0.000001));
3292
3293 let vs = render.compute_intrinsic_values(0., 1., 10);
3294 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
3295 }
3296
3297 #[test]
3298 fn test_update_automation_rate_to_a() {
3299 let context = OfflineAudioContext::new(1, 1, 48000.);
3300
3301 let opts = AudioParamDescriptor {
3302 name: String::new(),
3303 automation_rate: AutomationRate::K,
3304 default_value: 0.,
3305 min_value: -10.,
3306 max_value: 10.,
3307 };
3308 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3309
3310 render.onmessage(&mut AutomationRate::A);
3311 render.handle_incoming_event(param.set_value_at_time_raw(2., 0.000001));
3312
3313 let vs = render.compute_intrinsic_values(0., 1., 10);
3314 assert_float_eq!(vs, &[2.; 10][..], abs_all <= 0.);
3315 }
3316
3317 #[test]
3318 fn test_varying_param_size() {
3319 {
3321 let context = OfflineAudioContext::new(1, 1, 48000.);
3322
3323 let opts = AudioParamDescriptor {
3324 name: String::new(),
3325 automation_rate: AutomationRate::A,
3326 default_value: 0.,
3327 min_value: 0.,
3328 max_value: 10.,
3329 };
3330 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3331
3332 render.handle_incoming_event(param.set_value_at_time_raw(0., 0.));
3333 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(9., 9.));
3334
3335 let vs = render.compute_intrinsic_values(0., 1., 10);
3337 let expected = [0., 1., 2., 3., 4., 5., 6., 7., 8., 9.];
3338 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3339
3340 let vs = render.compute_intrinsic_values(10., 1., 10);
3342 let expected = [9.; 1];
3343 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3344
3345 render.handle_incoming_event(param.set_value_at_time_raw(1., 25.));
3347
3348 let vs = render.compute_intrinsic_values(20., 1., 10);
3349 let expected = [9., 9., 9., 9., 9., 1., 1., 1., 1., 1.];
3350 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3351
3352 let vs = render.compute_intrinsic_values(30., 1., 10);
3354 let expected = [1.; 1];
3355 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3356 }
3357
3358 {
3360 let context = OfflineAudioContext::new(1, 1, 48000.);
3361
3362 let opts = AudioParamDescriptor {
3363 name: String::new(),
3364 automation_rate: AutomationRate::A,
3365 default_value: 0.,
3366 min_value: 0.,
3367 max_value: 10.,
3368 };
3369 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3370
3371 render.handle_incoming_event(param.set_value_at_time_raw(0., 0.));
3372 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(9., 9.));
3373 render.handle_incoming_event(param.set_value_at_time_raw(1., 25.));
3374
3375 let vs = render.compute_intrinsic_values(0., 1., 10);
3377 let expected = [0., 1., 2., 3., 4., 5., 6., 7., 8., 9.];
3378 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3379
3380 let vs = render.compute_intrinsic_values(10., 1., 10);
3382 let expected = [9.; 1];
3383 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3384
3385 let vs = render.compute_intrinsic_values(20., 1., 10);
3387 let expected = [9., 9., 9., 9., 9., 1., 1., 1., 1., 1.];
3388 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3389
3390 let vs = render.compute_intrinsic_values(30., 1., 10);
3392 let expected = [1.; 1];
3393 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3394 }
3395 }
3396
3397 #[test]
3398 fn test_varying_param_size_modulated() {
3399 let alloc = Alloc::with_capacity(1);
3400
3401 {
3403 let context = OfflineAudioContext::new(1, 1, 48000.);
3404
3405 let opts = AudioParamDescriptor {
3406 name: String::new(),
3407 automation_rate: AutomationRate::A,
3408 default_value: 0.,
3409 min_value: 0.,
3410 max_value: 10.,
3411 };
3412 let (_param, mut render) = audio_param_pair(opts, context.mock_registration());
3413
3414 let vs = render.compute_intrinsic_values(0., 1., 128);
3416 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
3417
3418 let signal = alloc.silence();
3420 let input = AudioRenderQuantum::from(signal);
3421
3422 let signal = alloc.silence();
3423 let mut output = AudioRenderQuantum::from(signal);
3424
3425 render.mix_to_output(&input, &mut output);
3426
3427 assert!(output.single_valued());
3428 assert_float_eq!(output.channel_data(0)[0], 0., abs <= 0.);
3429 }
3430
3431 {
3433 let context = OfflineAudioContext::new(1, 1, 48000.);
3434
3435 let opts = AudioParamDescriptor {
3436 name: String::new(),
3437 automation_rate: AutomationRate::A,
3438 default_value: 0.,
3439 min_value: 0.,
3440 max_value: 10.,
3441 };
3442 let (_param, mut render) = audio_param_pair(opts, context.mock_registration());
3443
3444 let vs = render.compute_intrinsic_values(0., 1., 128);
3446 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
3447
3448 let signal = alloc.silence();
3450 let mut input = AudioRenderQuantum::from(signal);
3451 input.channel_data_mut(0)[0] = 1.;
3452
3453 let signal = alloc.silence();
3454 let mut output = AudioRenderQuantum::from(signal);
3455
3456 render.mix_to_output(&input, &mut output);
3457
3458 let mut expected = [0.; 128];
3459 expected[0] = 1.;
3460
3461 assert!(!output.single_valued());
3462 assert_float_eq!(output.channel_data(0)[..], &expected[..], abs_all <= 0.);
3463 }
3464 }
3465
3466 #[test]
3467 fn test_k_rate_makes_input_single_valued() {
3468 let alloc = Alloc::with_capacity(1);
3469 let context = OfflineAudioContext::new(1, 1, 48000.);
3470
3471 let opts = AudioParamDescriptor {
3472 name: String::new(),
3473 automation_rate: AutomationRate::K,
3474 default_value: 0.,
3475 min_value: 0.,
3476 max_value: 10.,
3477 };
3478 let (_param, mut render) = audio_param_pair(opts, context.mock_registration());
3479
3480 let vs = render.compute_intrinsic_values(0., 1., 128);
3482 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
3483
3484 let signal = alloc.silence();
3486 let mut input = AudioRenderQuantum::from(signal);
3487 input.channel_data_mut(0)[0] = 1.;
3488 input.channel_data_mut(0)[1] = 2.;
3489 input.channel_data_mut(0)[2] = 3.;
3490
3491 let signal = alloc.silence();
3492 let mut output = AudioRenderQuantum::from(signal);
3493
3494 render.mix_to_output(&input, &mut output);
3495
3496 assert!(output.single_valued());
3498 assert_float_eq!(output.channel_data(0)[0], 1., abs <= 0.);
3499 }
3500
3501 #[test]
3502 fn test_full_render_chain() {
3503 let alloc = Alloc::with_capacity(1);
3504 let context = OfflineAudioContext::new(1, 1, 48000.);
3506
3507 let min = 2.;
3508 let max = 42.;
3509 let default = 2.;
3510
3511 let opts = AudioParamDescriptor {
3512 name: String::new(),
3513 automation_rate: AutomationRate::A,
3514 default_value: default,
3515 min_value: min,
3516 max_value: max,
3517 };
3518 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3519
3520 render.handle_incoming_event(param.set_value_raw(128.));
3521 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(0., 128.));
3522
3523 let intrinsic_values = render.compute_intrinsic_values(0., 1., 128);
3524 let mut expected = [0.; 128];
3525 for (i, v) in expected.iter_mut().enumerate() {
3526 *v = 128. - i as f32;
3527 }
3528 assert_float_eq!(intrinsic_values, &expected[..], abs_all <= 0.);
3529
3530 let signal = alloc.silence();
3531 let mut input = AudioRenderQuantum::from(signal);
3532 input.channel_data_mut(0)[0] = f32::NAN;
3533 let signal = alloc.silence();
3534 let mut output = AudioRenderQuantum::from(signal);
3535
3536 render.mix_to_output(&input, &mut output);
3537
3538 expected.iter_mut().for_each(|v| *v = v.clamp(min, max));
3540 expected[0] = 2.;
3542
3543 assert_float_eq!(output.channel_data(0)[..], &expected[..], abs_all <= 0.);
3544 }
3545}