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 = -1. * ((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
863 self.event_timeline
866 .retain(|queued| queued.time < event.time);
867 return; }
869
870 if event.event_type == AudioParamEventType::CancelAndHoldAtTime {
871 let mut e1: Option<&mut AudioParamEvent> = None;
876 let mut e2: Option<&mut AudioParamEvent> = None;
877 let mut t1 = f64::MIN;
878 let mut t2 = f64::MAX;
879 self.event_timeline.sort();
881
882 for queued in self.event_timeline.iter_mut() {
883 if queued.time >= t1 && queued.time <= event.time {
886 t1 = queued.time;
887 e1 = Some(queued);
888 } else if queued.time < t2 && queued.time > event.time {
891 t2 = queued.time;
892 e2 = Some(queued);
893 }
894 }
895
896 if let Some(matched) = e2 {
898 if matched.event_type == AudioParamEventType::LinearRampToValueAtTime
905 || matched.event_type == AudioParamEventType::ExponentialRampToValueAtTime
906 {
907 matched.cancel_time = Some(event.time);
908 }
909 } else if let Some(matched) = e1 {
910 if matched.event_type == AudioParamEventType::SetTargetAtTime {
911 matched.cancel_time = Some(event.time);
915 } else if matched.event_type == AudioParamEventType::SetValueCurveAtTime {
916 let start_time = matched.time;
926 let duration = matched.duration.unwrap();
927
928 if event.time <= start_time + duration {
929 matched.cancel_time = Some(event.time);
930 }
931 }
932 }
933
934 self.event_timeline.retain(|queued| {
936 let mut time = queued.time;
937 if let Some(cancel_time) = queued.cancel_time {
939 time = cancel_time;
940 }
941
942 time <= event.time
943 });
944 return; }
946
947 if event.event_type == AudioParamEventType::SetValueCurveAtTime {
958 let start_time = event.time;
960 let end_time = start_time + event.duration.unwrap();
961
962 for queued in self.event_timeline.iter() {
963 assert!(
964 queued.time <= start_time || queued.time >= end_time,
965 "NotSupportedError - scheduling SetValueCurveAtTime ({:?}) at time of another automation event ({:?})",
966 event, queued,
967 );
968 }
969 }
970
971 if event.event_type == AudioParamEventType::SetValueAtTime
976 || event.event_type == AudioParamEventType::SetValue
977 || event.event_type == AudioParamEventType::LinearRampToValueAtTime
978 || event.event_type == AudioParamEventType::ExponentialRampToValueAtTime
979 || event.event_type == AudioParamEventType::SetTargetAtTime
980 {
981 for queued in self.event_timeline.iter() {
982 if queued.event_type == AudioParamEventType::SetValueCurveAtTime {
983 let start_time = queued.time;
984 let end_time = start_time + queued.duration.unwrap();
985
986 assert!(
987 event.time <= start_time || event.time >= end_time,
988 "NotSupportedError - scheduling automation event ({:?}) during SetValueCurveAtTime ({:?})",
989 event, queued,
990 );
991 }
992 }
993 }
994
995 if event.event_type == AudioParamEventType::SetValue {
997 self.intrinsic_value = event.value;
998 }
999
1000 if self.event_timeline.is_empty()
1006 && self.last_event.is_none()
1007 && (event.event_type == AudioParamEventType::LinearRampToValueAtTime
1008 || event.event_type == AudioParamEventType::ExponentialRampToValueAtTime)
1009 {
1010 let set_value_event = AudioParamEvent {
1011 event_type: AudioParamEventType::SetValue,
1012 value: self.intrinsic_value,
1013 time: 0.,
1016 time_constant: None,
1017 cancel_time: None,
1018 duration: None,
1019 values: None,
1020 };
1021
1022 self.event_timeline.push(set_value_event);
1023 }
1024
1025 if self.event_timeline.is_empty()
1029 && event.event_type == AudioParamEventType::SetTargetAtTime
1030 {
1031 let set_value_event = AudioParamEvent {
1032 event_type: AudioParamEventType::SetValue,
1033 value: self.intrinsic_value,
1034 time: 0.,
1037 time_constant: None,
1038 cancel_time: None,
1039 duration: None,
1040 values: None,
1041 };
1042
1043 self.event_timeline.push(set_value_event);
1044 }
1045
1046 self.event_timeline.push(event);
1047 self.event_timeline.sort();
1048 }
1049
1050 fn compute_set_value_automation(&mut self, infos: &BlockInfos) -> bool {
1052 let event = self.event_timeline.peek().unwrap();
1053 let mut time = event.time;
1054
1055 if time == 0. {
1062 time = infos.block_time;
1063 }
1064
1065 if infos.is_a_rate {
1067 let end_index = ((time - infos.block_time).max(0.) / infos.dt).round() as usize;
1068 let end_index_clipped = end_index.min(infos.count);
1069
1070 for _ in self.buffer.len()..end_index_clipped {
1071 self.buffer.push(self.intrinsic_value);
1072 }
1073 }
1074
1075 if time > infos.next_block_time {
1077 return true;
1078 }
1079
1080 self.intrinsic_value = event.value;
1082
1083 #[allow(clippy::float_cmp)]
1085 if time != event.time {
1086 let mut event = self.event_timeline.pop().unwrap();
1087 event.time = time;
1088 self.last_event = Some(event);
1089 } else {
1090 self.last_event = self.event_timeline.pop();
1091 }
1092
1093 false
1094 }
1095
1096 fn compute_linear_ramp_automation(&mut self, infos: &BlockInfos) -> bool {
1099 let event = self.event_timeline.peek().unwrap();
1100 let last_event = self.last_event.as_ref().unwrap();
1101
1102 let start_time = last_event.time;
1103 let mut end_time = event.time;
1104 let duration = end_time - start_time;
1107 if let Some(cancel_time) = event.cancel_time {
1108 end_time = cancel_time;
1109 }
1110
1111 let start_value = last_event.value;
1112 let end_value = event.value;
1113 let diff = end_value - start_value;
1114
1115 if infos.is_a_rate {
1116 let start_index = self.buffer.len();
1117 let end_index = ((end_time - infos.block_time).max(0.) / infos.dt).round() as usize;
1120 let end_index_clipped = end_index.min(infos.count);
1121
1122 if end_index_clipped > start_index {
1125 let mut time = (start_index as f64).mul_add(infos.dt, infos.block_time);
1126
1127 let mut value = 0.;
1128 for _ in start_index..end_index_clipped {
1129 value =
1130 compute_linear_ramp_sample(start_time, duration, start_value, diff, time);
1131 self.buffer.push(value);
1132 time += infos.dt;
1133 }
1134 self.intrinsic_value = value;
1135 }
1136 }
1137
1138 if end_time >= infos.next_block_time {
1143 let value = compute_linear_ramp_sample(
1144 start_time,
1145 duration,
1146 start_value,
1147 diff,
1148 infos.next_block_time,
1149 );
1150 self.intrinsic_value = value;
1151
1152 return true;
1153 }
1154
1155 if event.cancel_time.is_some() {
1157 let value =
1158 compute_linear_ramp_sample(start_time, duration, start_value, diff, end_time);
1159
1160 self.intrinsic_value = value;
1161
1162 let mut last_event = self.event_timeline.pop().unwrap();
1163 last_event.time = end_time;
1164 last_event.value = value;
1165 self.last_event = Some(last_event);
1166 } else {
1168 self.intrinsic_value = end_value;
1169 self.last_event = self.event_timeline.pop();
1170 }
1171
1172 false
1173 }
1174
1175 fn compute_exponential_ramp_automation(&mut self, infos: &BlockInfos) -> bool {
1178 let event = self.event_timeline.peek().unwrap();
1179 let last_event = self.last_event.as_ref().unwrap();
1180
1181 let start_time = last_event.time;
1182 let mut end_time = event.time;
1183 let duration = end_time - start_time;
1186 if let Some(cancel_time) = event.cancel_time {
1187 end_time = cancel_time;
1188 }
1189
1190 let start_value = last_event.value;
1191 let end_value = event.value;
1192 let ratio = end_value / start_value;
1193
1194 if start_value == 0. || start_value * end_value < 0. {
1202 let event = AudioParamEvent {
1203 event_type: AudioParamEventType::SetValueAtTime,
1204 time: end_time,
1205 value: end_value,
1206 time_constant: None,
1207 cancel_time: None,
1208 duration: None,
1209 values: None,
1210 };
1211
1212 self.event_timeline.replace_peek(event);
1213 return false;
1214 }
1215
1216 if infos.is_a_rate {
1217 let start_index = self.buffer.len();
1218 let end_index = ((end_time - infos.block_time).max(0.) / infos.dt).round() as usize;
1221 let end_index_clipped = end_index.min(infos.count);
1222
1223 if end_index_clipped > start_index {
1224 let mut time = (start_index as f64).mul_add(infos.dt, infos.block_time);
1225
1226 let mut value = 0.;
1227 for _ in start_index..end_index_clipped {
1228 value = compute_exponential_ramp_sample(
1229 start_time,
1230 duration,
1231 start_value,
1232 ratio,
1233 time,
1234 );
1235
1236 self.buffer.push(value);
1237
1238 time += infos.dt;
1239 }
1240 self.intrinsic_value = value;
1241 }
1242 }
1243
1244 if end_time >= infos.next_block_time {
1249 let value = compute_exponential_ramp_sample(
1250 start_time,
1251 duration,
1252 start_value,
1253 ratio,
1254 infos.next_block_time,
1255 );
1256 self.intrinsic_value = value;
1257
1258 return true;
1259 }
1260
1261 if event.cancel_time.is_some() {
1263 let value =
1264 compute_exponential_ramp_sample(start_time, duration, start_value, ratio, end_time);
1265
1266 self.intrinsic_value = value;
1267
1268 let mut last_event = self.event_timeline.pop().unwrap();
1269 last_event.time = end_time;
1270 last_event.value = value;
1271 self.last_event = Some(last_event);
1272
1273 } else {
1275 self.intrinsic_value = end_value;
1276 self.last_event = self.event_timeline.pop();
1277 }
1278
1279 false
1280 }
1281
1282 fn compute_set_target_automation(&mut self, infos: &BlockInfos) -> bool {
1288 let event = self.event_timeline.peek().unwrap();
1289 let mut end_time = infos.next_block_time;
1290 let mut ended = false;
1291
1292 let some_next_event = self.event_timeline.next();
1294
1295 if let Some(next_event) = some_next_event {
1296 match next_event.event_type {
1297 AudioParamEventType::LinearRampToValueAtTime
1298 | AudioParamEventType::ExponentialRampToValueAtTime => {
1299 end_time = infos.block_time;
1312 ended = true;
1313 }
1314 _ => {
1315 if next_event.time < infos.next_block_time {
1318 end_time = next_event.time;
1319 ended = true;
1320 }
1321 }
1322 }
1323 }
1324
1325 if let Some(cancel_time) = event.cancel_time {
1327 if cancel_time < infos.next_block_time {
1328 end_time = cancel_time;
1329 ended = true;
1330 }
1331 }
1332
1333 let start_time = event.time;
1334 let start_value = self.last_event.as_ref().unwrap().value;
1338 let end_value = event.value;
1339 let diff = start_value - end_value;
1340 let time_constant = event.time_constant.unwrap();
1341
1342 if infos.is_a_rate {
1343 let start_index = self.buffer.len();
1344 let end_index = ((end_time - infos.block_time).max(0.) / infos.dt).round() as usize;
1347 let end_index_clipped = end_index.min(infos.count);
1348
1349 if end_index_clipped > start_index {
1350 let mut time = (start_index as f64).mul_add(infos.dt, infos.block_time);
1351
1352 let mut value = 0.;
1353 for _ in start_index..end_index_clipped {
1354 value = if time - start_time < 0. {
1356 self.intrinsic_value
1357 } else {
1358 compute_set_target_sample(start_time, time_constant, end_value, diff, time)
1359 };
1360
1361 self.buffer.push(value);
1362 time += infos.dt;
1363 }
1364 self.intrinsic_value = value;
1365 }
1366 }
1367
1368 if !ended {
1369 let value = compute_set_target_sample(
1373 start_time,
1374 time_constant,
1375 end_value,
1376 diff,
1377 infos.next_block_time,
1378 );
1379
1380 let diff = (end_value - value).abs();
1381
1382 if diff < SNAP_TO_TARGET {
1384 self.intrinsic_value = end_value;
1385
1386 if end_value == 0. {
1389 for v in self.buffer.iter_mut() {
1390 if v.is_subnormal() {
1391 *v = 0.;
1392 }
1393 }
1394 }
1395
1396 let event = AudioParamEvent {
1397 event_type: AudioParamEventType::SetValueAtTime,
1398 time: infos.next_block_time,
1399 value: end_value,
1400 time_constant: None,
1401 cancel_time: None,
1402 duration: None,
1403 values: None,
1404 };
1405
1406 self.event_timeline.replace_peek(event);
1407 } else {
1408 self.intrinsic_value = value;
1409 }
1410
1411 return true;
1412 }
1413
1414 let value = compute_set_target_sample(start_time, time_constant, end_value, diff, end_time);
1417
1418 self.intrinsic_value = value;
1419 let mut event = self.event_timeline.pop().unwrap();
1422 event.time = end_time;
1423 event.value = value;
1424 self.last_event = Some(event);
1425
1426 false
1427 }
1428
1429 fn compute_set_value_curve_automation(&mut self, infos: &BlockInfos) -> bool {
1430 let event = self.event_timeline.peek().unwrap();
1431 let start_time = event.time;
1432 let duration = event.duration.unwrap();
1433 let values = event.values.as_ref().unwrap();
1434 let mut end_time = start_time + duration;
1435
1436 if let Some(cancel_time) = event.cancel_time {
1440 end_time = cancel_time;
1441 }
1442
1443 if infos.is_a_rate {
1444 let start_index = self.buffer.len();
1445 let end_index = ((end_time - infos.block_time).max(0.) / infos.dt).round() as usize;
1448 let end_index_clipped = end_index.min(infos.count);
1449
1450 if end_index_clipped > start_index {
1451 let mut time = (start_index as f64).mul_add(infos.dt, infos.block_time);
1452
1453 let mut value = 0.;
1454 for _ in start_index..end_index_clipped {
1455 value = if time < start_time {
1457 self.intrinsic_value
1458 } else {
1459 compute_set_value_curve_sample(start_time, duration, values, time)
1460 };
1461
1462 self.buffer.push(value);
1463
1464 time += infos.dt;
1465 }
1466 self.intrinsic_value = value;
1467 }
1468 }
1469
1470 if end_time >= infos.next_block_time {
1472 let value =
1476 compute_set_value_curve_sample(start_time, duration, values, infos.next_block_time);
1477 self.intrinsic_value = value;
1478
1479 return true;
1480 }
1481
1482 if event.cancel_time.is_some() {
1484 let value = compute_set_value_curve_sample(start_time, duration, values, end_time);
1485
1486 self.intrinsic_value = value;
1487
1488 let mut last_event = self.event_timeline.pop().unwrap();
1489 last_event.time = end_time;
1490 last_event.value = value;
1491 self.last_event = Some(last_event);
1492 } else {
1494 let value = values[values.len() - 1];
1495
1496 let mut last_event = self.event_timeline.pop().unwrap();
1497 last_event.time = end_time;
1498 last_event.value = value;
1499
1500 self.intrinsic_value = value;
1501 self.last_event = Some(last_event);
1502 }
1503
1504 false
1505 }
1506
1507 fn compute_buffer(&mut self, block_time: f64, dt: f64, count: usize) {
1508 let clamped = self.intrinsic_value.clamp(self.min_value, self.max_value);
1511 self.current_value.store(clamped, Ordering::Release);
1512
1513 self.buffer.clear();
1515
1516 let is_a_rate = self.automation_rate.is_a_rate();
1517 let next_block_time = dt.mul_add(count as f64, block_time);
1518
1519 let is_constant_block = match self.event_timeline.peek() {
1532 None => true,
1533 Some(event) => {
1534 if event.event_type != AudioParamEventType::LinearRampToValueAtTime
1535 && event.event_type != AudioParamEventType::ExponentialRampToValueAtTime
1536 {
1537 event.time >= next_block_time
1538 } else {
1539 false
1540 }
1541 }
1542 };
1543
1544 if !is_a_rate || is_constant_block {
1545 self.buffer.push(self.intrinsic_value);
1546 if is_constant_block {
1548 return;
1549 }
1550 }
1551
1552 let block_infos = BlockInfos {
1554 block_time,
1555 dt,
1556 count,
1557 is_a_rate,
1558 next_block_time,
1559 };
1560
1561 loop {
1562 let next_event_type = self.event_timeline.peek().map(|e| e.event_type);
1563
1564 let exit_loop = match next_event_type {
1565 None => {
1566 if is_a_rate {
1567 for _ in self.buffer.len()..count {
1571 self.buffer.push(self.intrinsic_value);
1572 }
1573 }
1574 true
1575 }
1576 Some(AudioParamEventType::SetValue) | Some(AudioParamEventType::SetValueAtTime) => {
1577 self.compute_set_value_automation(&block_infos)
1578 }
1579 Some(AudioParamEventType::LinearRampToValueAtTime) => {
1580 self.compute_linear_ramp_automation(&block_infos)
1581 }
1582 Some(AudioParamEventType::ExponentialRampToValueAtTime) => {
1583 self.compute_exponential_ramp_automation(&block_infos)
1584 }
1585 Some(AudioParamEventType::SetTargetAtTime) => {
1586 self.compute_set_target_automation(&block_infos)
1587 }
1588 Some(AudioParamEventType::SetValueCurveAtTime) => {
1589 self.compute_set_value_curve_automation(&block_infos)
1590 }
1591 _ => panic!(
1592 "AudioParamEvent {:?} should not appear in AudioParamEventTimeline",
1593 next_event_type.unwrap()
1594 ),
1595 };
1596
1597 if exit_loop {
1598 break;
1599 }
1600 }
1601 }
1602}
1603
1604pub(crate) fn audio_param_pair(
1605 descriptor: AudioParamDescriptor,
1606 registration: AudioContextRegistration,
1607) -> (AudioParam, AudioParamProcessor) {
1608 let AudioParamDescriptor {
1609 automation_rate,
1610 default_value,
1611 max_value,
1612 min_value,
1613 ..
1614 } = descriptor;
1615
1616 assert_is_finite(default_value);
1617 assert_is_finite(min_value);
1618 assert_is_finite(max_value);
1619 assert!(
1620 min_value <= default_value,
1621 "InvalidStateError - AudioParam minValue should be <= defaultValue"
1622 );
1623 assert!(
1624 default_value <= max_value,
1625 "InvalidStateError - AudioParam defaultValue should be <= maxValue"
1626 );
1627
1628 let current_value = Arc::new(AtomicF32::new(default_value));
1629
1630 let param = AudioParam {
1631 registration: registration.into(),
1632 raw_parts: AudioParamInner {
1633 default_value,
1634 max_value,
1635 min_value,
1636 automation_rate_constrained: false,
1637 automation_rate: Arc::new(Mutex::new(automation_rate)),
1638 current_value: Arc::clone(¤t_value),
1639 },
1640 };
1641
1642 let processor = AudioParamProcessor {
1643 intrinsic_value: default_value,
1644 current_value,
1645 default_value,
1646 min_value,
1647 max_value,
1648 automation_rate,
1649 event_timeline: AudioParamEventTimeline::new(),
1650 last_event: None,
1651 buffer: ArrayVec::new(),
1652 };
1653
1654 (param, processor)
1655}
1656
1657#[cfg(test)]
1658mod tests {
1659 use float_eq::assert_float_eq;
1660
1661 use crate::context::{BaseAudioContext, OfflineAudioContext};
1662 use crate::render::Alloc;
1663
1664 use super::*;
1665
1666 #[test]
1667 #[should_panic]
1668 fn test_assert_strictly_positive_fail() {
1669 assert_strictly_positive(0.);
1670 }
1671
1672 #[test]
1673 fn test_assert_strictly_positive() {
1674 assert_strictly_positive(0.1);
1675 }
1676
1677 #[test]
1678 #[should_panic]
1679 fn test_assert_not_zero_fail() {
1680 assert_not_zero(0.);
1681 }
1682
1683 #[test]
1684 fn test_assert_not_zero() {
1685 assert_not_zero(-0.1);
1686 assert_not_zero(0.1);
1687 }
1688
1689 #[test]
1690 #[should_panic]
1691 fn test_assert_sequence_length_fail() {
1692 assert_sequence_length(&[0.; 1]);
1693 }
1694
1695 #[test]
1696 fn test_assert_sequence_length() {
1697 assert_sequence_length(&[0.; 2]);
1698 }
1699
1700 #[test]
1701 fn test_default_and_accessors() {
1702 let context = OfflineAudioContext::new(1, 1, 48000.);
1703
1704 let opts = AudioParamDescriptor {
1705 name: String::new(),
1706 automation_rate: AutomationRate::A,
1707 default_value: 0.,
1708 min_value: -10.,
1709 max_value: 10.,
1710 };
1711 let (param, _render) = audio_param_pair(opts, context.mock_registration());
1712
1713 assert_eq!(param.automation_rate(), AutomationRate::A);
1714 assert_float_eq!(param.default_value(), 0., abs_all <= 0.);
1715 assert_float_eq!(param.min_value(), -10., abs_all <= 0.);
1716 assert_float_eq!(param.max_value(), 10., abs_all <= 0.);
1717 assert_float_eq!(param.value(), 0., abs_all <= 0.);
1718 }
1719
1720 #[test]
1721 fn test_automation_rate_synchronicity_on_control_thread() {
1722 let context = OfflineAudioContext::new(1, 1, 48000.);
1723
1724 let opts = AudioParamDescriptor {
1725 name: String::new(),
1726 automation_rate: AutomationRate::A,
1727 default_value: 0.,
1728 min_value: 0.,
1729 max_value: 1.,
1730 };
1731 let (param, _render) = audio_param_pair(opts, context.mock_registration());
1732
1733 param.set_automation_rate(AutomationRate::K);
1734 assert_eq!(param.automation_rate(), AutomationRate::K);
1735 }
1736
1737 #[test]
1738 fn test_audioparam_clones_in_sync() {
1739 let context = OfflineAudioContext::new(1, 1, 48000.);
1740
1741 let opts = AudioParamDescriptor {
1742 name: String::new(),
1743 automation_rate: AutomationRate::A,
1744 default_value: 0.,
1745 min_value: -10.,
1746 max_value: 10.,
1747 };
1748 let (param1, mut render) = audio_param_pair(opts, context.mock_registration());
1749 let param2 = param1.clone();
1750
1751 param1.set_automation_rate(AutomationRate::K);
1753 assert_eq!(param2.automation_rate(), AutomationRate::K);
1754
1755 render.handle_incoming_event(param1.set_value_raw(2.));
1757 assert_float_eq!(param1.value(), 2., abs_all <= 0.);
1758 assert_float_eq!(param2.value(), 2., abs_all <= 0.);
1759
1760 render.handle_incoming_event(param2.set_value_raw(3.));
1762 assert_float_eq!(param1.value(), 3., abs_all <= 0.);
1763 assert_float_eq!(param2.value(), 3., abs_all <= 0.);
1764 }
1765
1766 #[test]
1767 fn test_set_value() {
1768 {
1769 let context = OfflineAudioContext::new(1, 1, 48000.);
1770
1771 let opts = AudioParamDescriptor {
1772 name: String::new(),
1773 automation_rate: AutomationRate::A,
1774 default_value: 0.,
1775 min_value: -10.,
1776 max_value: 10.,
1777 };
1778 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1779
1780 render.handle_incoming_event(param.set_value_raw(2.));
1781
1782 assert_float_eq!(param.value(), 2., abs_all <= 0.);
1783
1784 let vs = render.compute_intrinsic_values(0., 1., 10);
1785
1786 assert_float_eq!(param.value(), 2., abs_all <= 0.);
1787 assert_float_eq!(vs, &[2.; 10][..], abs_all <= 0.);
1788 }
1789
1790 {
1792 let context = OfflineAudioContext::new(1, 1, 48000.);
1793
1794 let opts = AudioParamDescriptor {
1795 name: String::new(),
1796 automation_rate: AutomationRate::A,
1797 default_value: 0.,
1798 min_value: 0.,
1799 max_value: 1.,
1800 };
1801 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1802
1803 render.handle_incoming_event(param.set_value_raw(2.));
1804
1805 assert_float_eq!(param.value(), 1., abs_all <= 0.);
1806
1807 let vs = render.compute_intrinsic_values(0., 1., 10);
1808
1809 assert_float_eq!(param.value(), 1., abs_all <= 0.);
1811 assert_float_eq!(vs, &[2.; 10][..], abs_all <= 0.);
1812 }
1813 }
1814
1815 #[test]
1816 fn test_steps_a_rate() {
1817 let context = OfflineAudioContext::new(1, 1, 48000.);
1818
1819 {
1820 let opts = AudioParamDescriptor {
1821 name: String::new(),
1822 automation_rate: AutomationRate::A,
1823 default_value: 0.,
1824 min_value: -10.,
1825 max_value: 10.,
1826 };
1827 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1828
1829 render.handle_incoming_event(param.set_value_at_time_raw(5., 2.0));
1830 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);
1834 assert_float_eq!(
1835 vs,
1836 &[0., 0., 5., 5., 5., 5., 5., 5., 12., 12.][..],
1837 abs_all <= 0.
1838 );
1839
1840 let vs = render.compute_intrinsic_values(10., 1., 10);
1842 assert_float_eq!(vs, &[8.; 1][..], abs_all <= 0.);
1843 }
1844
1845 {
1846 let opts = AudioParamDescriptor {
1848 name: String::new(),
1849 automation_rate: AutomationRate::A,
1850 default_value: 0.,
1851 min_value: -10.,
1852 max_value: 10.,
1853 };
1854 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1855
1856 render.handle_incoming_event(param.set_value_at_time_raw(5., 2.0));
1857 render.handle_incoming_event(param.set_value_at_time_raw(8., 12.0));
1858
1859 let vs = render.compute_intrinsic_values(0., 1., 10);
1860 assert_float_eq!(
1861 vs,
1862 &[0., 0., 5., 5., 5., 5., 5., 5., 5., 5.][..],
1863 abs_all <= 0.
1864 );
1865
1866 let vs = render.compute_intrinsic_values(10., 1., 10);
1867 assert_float_eq!(
1868 vs,
1869 &[5., 5., 8., 8., 8., 8., 8., 8., 8., 8.][..],
1870 abs_all <= 0.
1871 );
1872 }
1873 }
1874
1875 #[test]
1876 fn test_steps_k_rate() {
1877 let context = OfflineAudioContext::new(1, 1, 48000.);
1878 let opts = AudioParamDescriptor {
1879 name: String::new(),
1880 automation_rate: AutomationRate::K,
1881 default_value: 0.,
1882 min_value: -10.,
1883 max_value: 10.,
1884 };
1885 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1886
1887 render.handle_incoming_event(param.set_value_at_time_raw(5., 2.0));
1888 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);
1893 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
1894
1895 let vs = render.compute_intrinsic_values(10., 1., 10);
1896 assert_float_eq!(vs, &[8.; 1][..], abs_all <= 0.);
1897
1898 let vs = render.compute_intrinsic_values(20., 1., 10);
1899 assert_float_eq!(vs, &[3.; 1][..], abs_all <= 0.);
1900 }
1901
1902 #[test]
1903 fn test_linear_ramp_arate() {
1904 let context = OfflineAudioContext::new(1, 1, 48000.);
1905
1906 let opts = AudioParamDescriptor {
1907 name: String::new(),
1908 automation_rate: AutomationRate::A,
1909 default_value: 0.,
1910 min_value: -10.,
1911 max_value: 10.,
1912 };
1913 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1914
1915 render.handle_incoming_event(param.set_value_at_time_raw(5., 2.0));
1917 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(8.0, 5.0));
1919 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(0., 13.0));
1921
1922 let vs = render.compute_intrinsic_values(0., 1., 10);
1923 assert_float_eq!(
1924 vs,
1925 &[0., 0., 5., 6., 7., 8., 7., 6., 5., 4.][..],
1926 abs_all <= 0.
1927 );
1928 }
1929
1930 #[test]
1931 fn test_linear_ramp_arate_end_of_block() {
1932 let context = OfflineAudioContext::new(1, 1, 48000.);
1933
1934 let opts = AudioParamDescriptor {
1935 name: String::new(),
1936 automation_rate: AutomationRate::A,
1937 default_value: 0.,
1938 min_value: -10.,
1939 max_value: 10.,
1940 };
1941 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1942
1943 render.handle_incoming_event(param.set_value_at_time_raw(0., 0.));
1945 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(9.0, 9.0));
1947
1948 let vs = render.compute_intrinsic_values(0., 1., 10);
1949 assert_float_eq!(
1950 vs,
1951 &[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.][..],
1952 abs_all <= 0.
1953 );
1954 }
1955
1956 #[test]
1957 fn test_linear_ramp_arate_implicit_set_value() {
1962 let context = OfflineAudioContext::new(1, 1, 48000.);
1963
1964 let opts = AudioParamDescriptor {
1965 name: String::new(),
1966 automation_rate: AutomationRate::A,
1967 default_value: 0.,
1968 min_value: -10.,
1969 max_value: 10.,
1970 };
1971 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
1972
1973 let vs = render.compute_intrinsic_values(0., 1., 10);
1978 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
1979
1980 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(10.0, 20.0));
1982
1983 let vs = render.compute_intrinsic_values(10., 1., 10);
1984 assert_float_eq!(
1985 vs,
1986 &[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.][..],
1987 abs_all <= 0.
1988 );
1989
1990 let vs = render.compute_intrinsic_values(20., 1., 10);
1992 assert_float_eq!(vs, &[10.; 10][..], abs_all <= 0.);
1993 }
1994
1995 #[test]
1996 fn test_linear_ramp_arate_multiple_blocks() {
1997 let context = OfflineAudioContext::new(1, 1, 48000.);
1999
2000 let opts = AudioParamDescriptor {
2001 name: String::new(),
2002 automation_rate: AutomationRate::A,
2003 default_value: 0.,
2004 min_value: -20.,
2005 max_value: 20.,
2006 };
2007 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2008
2009 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(20.0, 20.0));
2011
2012 let vs = render.compute_intrinsic_values(0., 1., 10);
2014 assert_float_eq!(
2015 vs,
2016 &[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.][..],
2017 abs_all <= 0.
2018 );
2019 assert_float_eq!(param.value(), 0., abs <= 0.);
2020
2021 let vs = render.compute_intrinsic_values(10., 1., 10);
2023 assert_float_eq!(
2024 vs,
2025 &[10., 11., 12., 13., 14., 15., 16., 17., 18., 19.][..],
2026 abs_all <= 0.
2027 );
2028 assert_float_eq!(param.value(), 10., abs <= 0.);
2029
2030 let vs = render.compute_intrinsic_values(20., 1., 10);
2032 assert_float_eq!(vs, &[20.0; 10][..], abs_all <= 0.);
2033 assert_float_eq!(param.value(), 20., abs <= 0.);
2034 }
2035
2036 #[test]
2037 fn test_linear_ramp_krate_multiple_blocks() {
2038 let context = OfflineAudioContext::new(1, 1, 48000.);
2040
2041 {
2042 let opts = AudioParamDescriptor {
2043 name: String::new(),
2044 automation_rate: AutomationRate::K,
2045 default_value: 0.,
2046 min_value: -20.,
2047 max_value: 20.,
2048 };
2049 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2050
2051 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(20.0, 20.0));
2053 let vs = render.compute_intrinsic_values(0., 1., 10);
2055 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
2056 assert_float_eq!(param.value(), 0., abs <= 0.);
2057 let vs = render.compute_intrinsic_values(10., 1., 10);
2059 assert_float_eq!(vs, &[10.; 1][..], abs_all <= 0.);
2060 assert_float_eq!(param.value(), 10., abs <= 0.);
2061 let vs = render.compute_intrinsic_values(20., 1., 10);
2063 assert_float_eq!(vs, &[20.0; 1][..], abs_all <= 0.);
2064 assert_float_eq!(param.value(), 20., abs <= 0.);
2065 }
2066
2067 {
2068 let opts = AudioParamDescriptor {
2070 name: String::new(),
2071 automation_rate: AutomationRate::K,
2072 default_value: 0.,
2073 min_value: -20.,
2074 max_value: 20.,
2075 };
2076 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2077
2078 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(15.0, 15.0));
2080 let vs = render.compute_intrinsic_values(0., 1., 10);
2082 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
2083 assert_float_eq!(param.value(), 0., abs <= 0.);
2084 let vs = render.compute_intrinsic_values(10., 1., 10);
2086 assert_float_eq!(vs, &[10.; 1][..], abs_all <= 0.);
2087 assert_float_eq!(param.value(), 10., abs <= 0.);
2088 let vs = render.compute_intrinsic_values(20., 1., 10);
2090 assert_float_eq!(vs, &[15.0; 1][..], abs_all <= 0.);
2091 assert_float_eq!(param.value(), 15., abs <= 0.);
2092 }
2093 }
2094
2095 #[test]
2096 fn test_linear_ramp_start_time() {
2097 let context = OfflineAudioContext::new(1, 1, 48000.);
2098
2099 let opts = AudioParamDescriptor {
2100 name: String::new(),
2101 automation_rate: AutomationRate::A,
2102 default_value: 0.,
2103 min_value: -10.,
2104 max_value: 10.,
2105 };
2106 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2107
2108 render.handle_incoming_event(param.set_value_at_time_raw(1., 0.));
2109 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(-1., 10.));
2110 let vs = render.compute_intrinsic_values(0., 1., 10);
2111 assert_float_eq!(
2112 vs,
2113 &[1., 0.8, 0.6, 0.4, 0.2, 0., -0.2, -0.4, -0.6, -0.8][..],
2114 abs_all <= 1e-7
2115 );
2116
2117 let vs = render.compute_intrinsic_values(10., 1., 10);
2118 assert_float_eq!(vs, &[-1.; 10][..], abs_all <= 0.);
2119
2120 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(1., 30.));
2122
2123 let vs = render.compute_intrinsic_values(20., 1., 10);
2124 assert_float_eq!(
2125 vs,
2126 &[0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9][..],
2127 abs_all <= 1e-7
2128 );
2129 }
2130
2131 #[test]
2132 fn test_exponential_ramp_a_rate() {
2133 let context = OfflineAudioContext::new(1, 1, 48000.);
2134
2135 let opts = AudioParamDescriptor {
2136 name: String::new(),
2137 automation_rate: AutomationRate::A,
2138 default_value: 0.,
2139 min_value: 0.,
2140 max_value: 1.,
2141 };
2142 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2143
2144 render.handle_incoming_event(param.set_value_at_time_raw(0.0001, 0.));
2146 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(1.0, 10.));
2148
2149 let mut res = Vec::<f32>::with_capacity(10);
2152 let start: f32 = 0.0001;
2153 let end: f32 = 1.;
2154
2155 for t in 0..10 {
2156 let value = start * (end / start).powf(t as f32 / 10.);
2157 res.push(value);
2158 }
2159
2160 let vs = render.compute_intrinsic_values(0., 1., 10);
2161 assert_float_eq!(vs, &res[..], abs_all <= 0.);
2162
2163 let vs = render.compute_intrinsic_values(10., 1., 10);
2164 assert_float_eq!(vs, &[1.0; 10][..], abs_all <= 0.);
2165 }
2166
2167 #[test]
2168 fn test_exponential_ramp_a_rate_multiple_blocks() {
2169 let context = OfflineAudioContext::new(1, 1, 48000.);
2170
2171 let opts = AudioParamDescriptor {
2172 name: String::new(),
2173 automation_rate: AutomationRate::A,
2174 default_value: 0.,
2175 min_value: 0.,
2176 max_value: 1.,
2177 };
2178 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2179
2180 let start: f32 = 0.0001; let end: f32 = 1.;
2182 render.handle_incoming_event(param.set_value_at_time_raw(start, 3.));
2183 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(end, 13.));
2185
2186 let mut res = vec![0.; 3];
2188 for t in 0..10 {
2191 let value = start * (end / start).powf(t as f32 / 10.);
2192 res.push(value);
2193 }
2194 res.append(&mut vec![1.; 7]);
2196
2197 let vs = render.compute_intrinsic_values(0., 1., 10);
2198 assert_float_eq!(vs, &res[0..10], abs_all <= 0.);
2199 assert_float_eq!(param.value(), res[0], abs <= 0.);
2200
2201 let vs = render.compute_intrinsic_values(10., 1., 10);
2202 assert_float_eq!(vs, &res[10..20], abs_all <= 0.);
2203 assert_float_eq!(param.value(), res[10], abs <= 0.);
2204 }
2205
2206 #[test]
2207 fn test_exponential_ramp_a_rate_zero_and_opposite_target() {
2208 let context = OfflineAudioContext::new(1, 1, 48000.);
2209
2210 {
2211 let opts = AudioParamDescriptor {
2213 name: String::new(),
2214 automation_rate: AutomationRate::A,
2215 default_value: 0.,
2216 min_value: 0.,
2217 max_value: 1.,
2218 };
2219 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2220
2221 render.handle_incoming_event(param.set_value_at_time_raw(0., 0.));
2223 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(1.0, 5.));
2225
2226 let vs = render.compute_intrinsic_values(0., 1., 10);
2227 assert_float_eq!(
2228 vs,
2229 &[0., 0., 0., 0., 0., 1., 1., 1., 1., 1.][..],
2230 abs_all <= 0.
2231 );
2232 }
2233
2234 {
2235 let opts = AudioParamDescriptor {
2237 name: String::new(),
2238 automation_rate: AutomationRate::A,
2239 default_value: 0.,
2240 min_value: -1.,
2241 max_value: 1.,
2242 };
2243 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2244
2245 render.handle_incoming_event(param.set_value_at_time_raw(-1., 0.));
2247 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(1.0, 5.));
2249
2250 let vs = render.compute_intrinsic_values(0., 1., 10);
2251 assert_float_eq!(
2252 vs,
2253 &[-1., -1., -1., -1., -1., 1., 1., 1., 1., 1.][..],
2254 abs_all <= 0.
2255 );
2256 }
2257 }
2258
2259 #[test]
2260 #[should_panic]
2261 fn test_exponential_ramp_to_zero() {
2262 let context = OfflineAudioContext::new(1, 1, 48000.);
2263
2264 let opts = AudioParamDescriptor {
2265 name: String::new(),
2266 automation_rate: AutomationRate::A,
2267 default_value: 1.,
2268 min_value: 0.,
2269 max_value: 1.,
2270 };
2271 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2272 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(0.0, 10.));
2273 }
2274
2275 #[test]
2276 fn test_exponential_ramp_k_rate_multiple_blocks() {
2277 let context = OfflineAudioContext::new(1, 1, 48000.);
2278
2279 let opts = AudioParamDescriptor {
2280 name: String::new(),
2281 automation_rate: AutomationRate::K,
2282 default_value: 0.,
2283 min_value: 0.,
2284 max_value: 1.,
2285 };
2286 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2287
2288 let start: f32 = 0.0001; let end: f32 = 1.;
2290 render.handle_incoming_event(param.set_value_at_time_raw(start, 3.));
2291 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(end, 13.));
2293
2294 let mut res = vec![0.; 3];
2296 for t in 0..10 {
2299 let value = start * (end / start).powf(t as f32 / 10.);
2300 res.push(value);
2301 }
2302 res.append(&mut vec![1.; 7]);
2304
2305 let vs = render.compute_intrinsic_values(0., 1., 10);
2307 assert_float_eq!(vs, &[res[0]; 1][..], abs_all <= 0.);
2308
2309 let vs = render.compute_intrinsic_values(10., 1., 10);
2310 assert_float_eq!(vs, &[res[10]; 1][..], abs_all <= 0.);
2311
2312 let vs = render.compute_intrinsic_values(20., 1., 10);
2313 assert_float_eq!(vs, &[1.; 1][..], abs_all <= 0.);
2314 }
2315
2316 #[test]
2317 fn test_exponential_ramp_k_rate_zero_and_opposite_target() {
2318 let context = OfflineAudioContext::new(1, 1, 48000.);
2319
2320 {
2321 let opts = AudioParamDescriptor {
2323 name: String::new(),
2324 automation_rate: AutomationRate::K,
2325 default_value: 0.,
2326 min_value: 0.,
2327 max_value: 1.,
2328 };
2329 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2330
2331 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(1.0, 5.));
2333
2334 let vs = render.compute_intrinsic_values(0., 1., 10);
2335 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
2336
2337 let vs = render.compute_intrinsic_values(10., 1., 10);
2338 assert_float_eq!(vs, &[1.; 1][..], abs_all <= 0.);
2339 }
2340
2341 {
2342 let opts = AudioParamDescriptor {
2344 name: String::new(),
2345 automation_rate: AutomationRate::K,
2346 default_value: -1.,
2347 min_value: -1.,
2348 max_value: 1.,
2349 };
2350 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2351
2352 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(1.0, 5.));
2354
2355 let vs = render.compute_intrinsic_values(0., 1., 10);
2356 assert_float_eq!(vs, &[-1.; 1][..], abs_all <= 0.);
2357
2358 let vs = render.compute_intrinsic_values(10., 1., 10);
2359 assert_float_eq!(vs, &[1.; 1][..], abs_all <= 0.);
2360 }
2361 }
2362
2363 #[test]
2364 fn test_exponential_ramp_start_time() {
2365 let context = OfflineAudioContext::new(1, 1, 48000.);
2366
2367 let opts = AudioParamDescriptor {
2368 name: String::new(),
2369 automation_rate: AutomationRate::A,
2370 default_value: 0.,
2371 min_value: -10.,
2372 max_value: 10.,
2373 };
2374 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2375
2376 render.handle_incoming_event(param.set_value_at_time_raw(0., 0.));
2377 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(1., 10.));
2378
2379 let vs = render.compute_intrinsic_values(0., 1., 10);
2380 assert_float_eq!(
2381 vs,
2382 &[0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9][..],
2383 abs_all <= 1e-7
2384 );
2385
2386 let vs = render.compute_intrinsic_values(10., 1., 10);
2387 assert_float_eq!(vs, &[1.; 10][..], abs_all <= 0.);
2388
2389 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(0.0001, 30.));
2391 let vs = render.compute_intrinsic_values(20., 1., 10);
2392 let start: f32 = 1.;
2394 let end: f32 = 0.0001;
2395 let mut res = [0.; 20];
2396 for (t, v) in res.iter_mut().enumerate() {
2397 *v = start * (end / start).powf(t as f32 / 20.);
2398 }
2399
2400 assert_float_eq!(vs, &res[10..], abs_all <= 1e-7);
2401 }
2402
2403 #[test]
2404 fn test_set_target_at_time_a_rate() {
2405 let context = OfflineAudioContext::new(1, 1, 48000.);
2406
2407 {
2408 let opts = AudioParamDescriptor {
2409 name: String::new(),
2410 automation_rate: AutomationRate::A,
2411 default_value: 0.,
2412 min_value: 0.,
2413 max_value: 1.,
2414 };
2415 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2416 let v0: f32 = 0.;
2418 let v1: f32 = 1.;
2419 let t0: f64 = 0.;
2420 let time_constant: f64 = 1.;
2421
2422 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2423 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2424 let vs = render.compute_intrinsic_values(0., 1., 10);
2425
2426 let mut res = Vec::<f32>::with_capacity(10);
2427 for t in 0..10 {
2428 let val = v1 + (v0 - v1) * (-1. * ((t as f64 - t0) / time_constant)).exp() as f32;
2429 res.push(val);
2430 }
2431
2432 assert_float_eq!(vs, &res[..], abs_all <= 0.);
2433 }
2434
2435 {
2436 let opts = AudioParamDescriptor {
2438 name: String::new(),
2439 automation_rate: AutomationRate::A,
2440 default_value: 0.,
2441 min_value: 0.,
2442 max_value: 1.,
2443 };
2444 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2445 let v0: f32 = 0.; let v1: f32 = 1.;
2448 let t0: f64 = 0.;
2449 let time_constant: f64 = 1.;
2450
2451 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2452 let vs = render.compute_intrinsic_values(0., 1., 10);
2453
2454 let mut res = Vec::<f32>::with_capacity(10);
2455 for t in 0..10 {
2456 let val = v1 + (v0 - v1) * (-1. * ((t as f64 - t0) / time_constant)).exp() as f32;
2457 res.push(val);
2458 }
2459
2460 assert_float_eq!(vs, &res[..], abs_all <= 0.);
2461 }
2462
2463 {
2464 let opts = AudioParamDescriptor {
2466 name: String::new(),
2467 automation_rate: AutomationRate::A,
2468 default_value: 0.,
2469 min_value: 0.,
2470 max_value: 100.,
2471 };
2472 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2473 let v0: f32 = 1.;
2475 let v1: f32 = 42.;
2476 let t0: f64 = 1.;
2477 let time_constant: f64 = 2.1;
2478
2479 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2480 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2481
2482 let mut res = Vec::<f32>::with_capacity(10);
2483 for t in 0..10 {
2484 let val = v1 + (v0 - v1) * (-1. * ((t as f64 - t0) / time_constant)).exp() as f32;
2485 res.push(val);
2486 }
2487 res[0] = 0.;
2489
2490 let vs = render.compute_intrinsic_values(0., 1., 10);
2491 assert_float_eq!(vs, &res[..], abs_all <= 0.);
2492 }
2493
2494 {
2495 let opts = AudioParamDescriptor {
2497 name: String::new(),
2498 automation_rate: AutomationRate::A,
2499 default_value: 0.,
2500 min_value: 0.,
2501 max_value: 100.,
2502 };
2503 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2504 render.handle_incoming_event(param.set_target_at_time_raw(1., 1., 0.));
2505
2506 let mut res = [1.; 10];
2507 res[0] = 0.; let vs = render.compute_intrinsic_values(0., 1., 10);
2510 assert_float_eq!(vs, &res[..], abs_all <= 0.);
2511 }
2512 }
2513
2514 #[test]
2515 fn test_set_target_at_time_a_rate_multiple_blocks() {
2516 let context = OfflineAudioContext::new(1, 1, 48000.);
2517
2518 {
2519 let opts = AudioParamDescriptor {
2520 name: String::new(),
2521 automation_rate: AutomationRate::A,
2522 default_value: 0.,
2523 min_value: 0.,
2524 max_value: 2.,
2525 };
2526 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2527 let v0: f32 = 0.;
2529 let v1: f32 = 2.;
2530 let t0: f64 = 0.;
2531 let time_constant: f64 = 1.;
2532 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2534 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2535
2536 let mut res = Vec::<f32>::with_capacity(20);
2537 for t in 0..20 {
2538 let val = v1 + (v0 - v1) * (-1. * ((t as f64 - t0) / time_constant)).exp() as f32;
2539 res.push(val);
2540 }
2541
2542 let vs = render.compute_intrinsic_values(0., 1., 10);
2543 assert_float_eq!(vs, &res[0..10], abs_all <= 0.);
2544
2545 let vs = render.compute_intrinsic_values(10., 1., 10);
2546 assert_float_eq!(vs, &res[10..20], abs_all <= 0.);
2547 }
2548 }
2549
2550 #[test]
2551 fn test_set_target_at_time_a_rate_followed_by_set_value() {
2552 let context = OfflineAudioContext::new(1, 1, 48000.);
2553
2554 {
2555 let opts = AudioParamDescriptor {
2556 name: String::new(),
2557 automation_rate: AutomationRate::A,
2558 default_value: 0.,
2559 min_value: 0.,
2560 max_value: 2.,
2561 };
2562 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2563 let v0: f32 = 0.;
2565 let v1: f32 = 2.;
2566 let t0: f64 = 0.;
2567 let time_constant: f64 = 1.;
2568
2569 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2570 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2571 render.handle_incoming_event(param.set_value_at_time_raw(0.5, 15.));
2572
2573 let mut res = Vec::<f32>::with_capacity(20);
2574
2575 for t in 0..15 {
2576 let val = v1 + (v0 - v1) * (-1. * ((t as f64 - t0) / time_constant)).exp() as f32;
2577 res.push(val);
2578 }
2579
2580 res.resize(20, 0.5);
2581
2582 let vs = render.compute_intrinsic_values(0., 1., 10);
2583 assert_float_eq!(vs, &res[0..10], abs_all <= 0.);
2584
2585 let vs = render.compute_intrinsic_values(10., 1., 10);
2586 assert_float_eq!(vs, &res[10..20], abs_all <= 0.);
2587 }
2588 }
2589
2590 #[test]
2591 fn test_set_target_at_time_ends_at_threshold() {
2592 let context = OfflineAudioContext::new(1, 1, 48000.);
2593 let opts = AudioParamDescriptor {
2594 name: String::new(),
2595 automation_rate: AutomationRate::A,
2596 default_value: 0.,
2597 min_value: 0.,
2598 max_value: 2.,
2599 };
2600 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2601
2602 render.handle_incoming_event(param.set_value_at_time_raw(1., 0.));
2603 render.handle_incoming_event(param.set_target_at_time_raw(0., 1., 0.2));
2604
2605 let vs = render.compute_intrinsic_values(0., 1., 128);
2606 for v in vs.iter() {
2607 assert!(!v.is_subnormal());
2608 }
2609
2610 let peek = render.event_timeline.peek();
2612 assert_eq!(
2613 peek.unwrap().event_type,
2614 AudioParamEventType::SetValueAtTime
2615 );
2616
2617 let vs = render.compute_intrinsic_values(10., 1., 128);
2619 assert_float_eq!(vs[..], [0.; 128], abs_all <= 0.);
2620 }
2621
2622 #[test]
2623 fn test_set_target_at_time_waits_for_start_time() {
2624 let context = OfflineAudioContext::new(1, 1, 48000.);
2625 let opts = AudioParamDescriptor {
2626 name: String::new(),
2627 automation_rate: AutomationRate::A,
2628 default_value: 0.,
2629 min_value: 0.,
2630 max_value: 2.,
2631 };
2632 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2633
2634 render.handle_incoming_event(param.set_value_at_time_raw(1., 0.));
2635 render.handle_incoming_event(param.set_target_at_time_raw(0., 5., 1.));
2636
2637 let vs = render.compute_intrinsic_values(0., 1., 10);
2638 assert_float_eq!(vs[0], 1., abs <= 0.);
2639 assert_float_eq!(vs[1], 1., abs <= 0.);
2640 assert_float_eq!(vs[2], 1., abs <= 0.);
2641 assert_float_eq!(vs[3], 1., abs <= 0.);
2642 assert_float_eq!(vs[4], 1., abs <= 0.);
2643 assert_float_eq!(vs[5], 1., abs <= 0.);
2644 }
2645
2646 #[test]
2647 fn test_set_target_at_time_a_rate_followed_by_ramp() {
2648 let context = OfflineAudioContext::new(1, 1, 48000.);
2649 {
2650 let opts = AudioParamDescriptor {
2651 name: String::new(),
2652 automation_rate: AutomationRate::A,
2653 default_value: 0.,
2654 min_value: 0.,
2655 max_value: 10.,
2656 };
2657 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2658 let v0: f32 = 0.;
2660 let v1: f32 = 2.;
2661 let t0: f64 = 0.;
2662 let time_constant: f64 = 10.;
2663
2664 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2665 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2666
2667 let mut res = Vec::<f32>::with_capacity(20);
2668
2669 for t in 0..11 {
2670 let val = v1 + (v0 - v1) * (-1. * ((t as f64 - t0) / time_constant)).exp() as f32;
2672 res.push(val);
2673 }
2674
2675 let vs = render.compute_intrinsic_values(0., 1., 10);
2676 assert_float_eq!(vs, &res[0..10], abs_all <= 0.);
2677
2678 let v0 = res.pop().unwrap(); let v1 = 10.;
2681 let t0 = 10.;
2682 let t1 = 20.;
2683
2684 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(v1, t1));
2685
2686 for t in 10..20 {
2687 let time = t as f64;
2688 let value = v0 + (v1 - v0) * (time - t0) as f32 / (t1 - t0) as f32;
2689 res.push(value);
2690 }
2691
2692 let vs = render.compute_intrinsic_values(10., 1., 10);
2693 assert_float_eq!(vs, &res[10..20], abs_all <= 1.0e-6);
2694 let vs = render.compute_intrinsic_values(20., 1., 10);
2696 assert_float_eq!(vs, &[v1; 10][..], abs_all <= 0.);
2697 }
2698 }
2699
2700 #[test]
2701 fn test_set_target_at_time_k_rate_multiple_blocks() {
2702 let context = OfflineAudioContext::new(1, 1, 48000.);
2703
2704 {
2705 let opts = AudioParamDescriptor {
2706 name: String::new(),
2707 automation_rate: AutomationRate::K,
2708 default_value: 0.,
2709 min_value: 0.,
2710 max_value: 2.,
2711 };
2712 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2713 let v0: f32 = 0.;
2715 let v1: f32 = 2.;
2716 let t0: f64 = 0.;
2717 let time_constant: f64 = 1.;
2718 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2720 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2721
2722 let mut res = Vec::<f32>::with_capacity(20);
2723 for t in 0..20 {
2724 let val = v1 + (v0 - v1) * (-1. * ((t as f64 - t0) / time_constant)).exp() as f32;
2725 res.push(val);
2726 }
2727
2728 let vs = render.compute_intrinsic_values(0., 1., 10);
2729 assert_float_eq!(vs, &[res[0]; 1][..], abs_all <= 0.);
2730
2731 let vs = render.compute_intrinsic_values(10., 1., 10);
2732 assert_float_eq!(vs, &[res[10]; 1][..], abs_all <= 0.);
2733 }
2734 }
2735
2736 #[test]
2737 fn test_set_target_at_time_snap_to_value() {
2739 let context = OfflineAudioContext::new(1, 1, 48000.);
2740 let opts = AudioParamDescriptor {
2741 name: String::new(),
2742 automation_rate: AutomationRate::A,
2743 default_value: 0.,
2744 min_value: 0.,
2745 max_value: 1.,
2746 };
2747 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2748 let v0: f32 = 1.;
2749 let v1: f32 = 0.;
2750 let t0: f64 = 0.;
2751 let time_constant: f64 = 1.;
2752
2753 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2754 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2755
2756 let mut res = [0.; 30];
2757 res.iter_mut().enumerate().for_each(|(t, r)| {
2759 *r = v1 + (v0 - v1) * (-1. * ((t as f64 - t0) / time_constant)).exp() as f32;
2760 });
2761
2762 let vs = render.compute_intrinsic_values(0., 1., 10);
2763 assert_float_eq!(vs, &res[..10], abs_all <= 0.);
2764
2765 let vs = render.compute_intrinsic_values(10., 1., 10);
2766 assert_float_eq!(vs, &res[10..20], abs_all <= 0.);
2767
2768 let vs = render.compute_intrinsic_values(20., 1., 10);
2771 assert_float_eq!(vs, &res[20..30], abs_all <= 0.);
2772
2773 let vs = render.compute_intrinsic_values(30., 1., 10);
2775 assert_float_eq!(vs, &[0.; 10][..], abs_all <= 0.);
2776 }
2777
2778 #[test]
2779 fn test_cancel_scheduled_values() {
2780 let context = OfflineAudioContext::new(1, 1, 48000.);
2781
2782 let opts = AudioParamDescriptor {
2783 name: String::new(),
2784 automation_rate: AutomationRate::A,
2785 default_value: 0.,
2786 min_value: 0.,
2787 max_value: 10.,
2788 };
2789 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2790 for t in 0..10 {
2791 render.handle_incoming_event(param.set_value_at_time_raw(t as f32, t as f64));
2792 }
2793
2794 render.handle_incoming_event(param.cancel_scheduled_values_raw(5.));
2795
2796 let vs = render.compute_intrinsic_values(0., 1., 10);
2797 assert_float_eq!(
2798 vs,
2799 &[0., 1., 2., 3., 4., 4., 4., 4., 4., 4.][..],
2800 abs_all <= 0.
2801 );
2802 }
2803
2804 #[test]
2805 fn test_cancel_scheduled_values_ramp() {
2806 let context = OfflineAudioContext::new(1, 1, 48000.);
2807
2808 {
2809 let opts = AudioParamDescriptor {
2810 name: String::new(),
2811 automation_rate: AutomationRate::A,
2812 default_value: 0.,
2813 min_value: 0.,
2814 max_value: 10.,
2815 };
2816 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2817
2818 render.handle_incoming_event(param.set_value_at_time_raw(0., 0.));
2819 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(10., 10.));
2820 render.handle_incoming_event(param.cancel_scheduled_values_raw(10.));
2822
2823 let vs = render.compute_intrinsic_values(0., 1., 10);
2824 assert_float_eq!(vs, &[0.; 10][..], abs_all <= 0.);
2825 }
2826
2827 {
2829 let opts = AudioParamDescriptor {
2830 name: String::new(),
2831 automation_rate: AutomationRate::A,
2832 default_value: 0.,
2833 min_value: 0.,
2834 max_value: 20.,
2835 };
2836 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2837
2838 render.handle_incoming_event(param.set_value_at_time_raw(0., 0.));
2839 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(20., 20.));
2840
2841 let vs = render.compute_intrinsic_values(0., 1., 10);
2842 assert_float_eq!(
2843 vs,
2844 &[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.][..],
2845 abs_all <= 0.
2846 );
2847
2848 render.handle_incoming_event(param.cancel_scheduled_values_raw(10.));
2851
2852 let vs = render.compute_intrinsic_values(10., 1., 10);
2853 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
2854 }
2855
2856 {
2860 let opts = AudioParamDescriptor {
2861 name: String::new(),
2862 automation_rate: AutomationRate::A,
2863 default_value: 0.,
2864 min_value: 0.,
2865 max_value: 10.,
2866 };
2867 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2868
2869 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(10., 10.));
2872 render.handle_incoming_event(param.cancel_scheduled_values_raw(10.)); let vs = render.compute_intrinsic_values(0., 1., 10);
2875 assert_float_eq!(vs, &[0.; 10][..], abs_all <= 0.);
2876 }
2877
2878 {
2879 let opts = AudioParamDescriptor {
2880 name: String::new(),
2881 automation_rate: AutomationRate::A,
2882 default_value: 0.,
2883 min_value: 0.,
2884 max_value: 20.,
2885 };
2886 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2887
2888 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(20., 20.));
2889
2890 let vs = render.compute_intrinsic_values(0., 1., 10);
2891 assert_float_eq!(
2892 vs,
2893 &[0., 1., 2., 3., 4., 5., 6., 7., 8., 9.][..],
2894 abs_all <= 0.
2895 );
2896
2897 render.handle_incoming_event(param.cancel_scheduled_values_raw(10.));
2899
2900 let vs = render.compute_intrinsic_values(10., 1., 10);
2901 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
2902 }
2903 }
2904
2905 #[test]
2906 fn test_cancel_and_hold() {
2907 let context = OfflineAudioContext::new(1, 1, 48000.);
2908 {
2909 let opts = AudioParamDescriptor {
2910 name: String::new(),
2911 automation_rate: AutomationRate::A,
2912 default_value: 0.,
2913 min_value: 0.,
2914 max_value: 10.,
2915 };
2916 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2917
2918 render.handle_incoming_event(param.set_value_at_time_raw(1., 1.));
2919 render.handle_incoming_event(param.set_value_at_time_raw(2., 2.));
2920 render.handle_incoming_event(param.set_value_at_time_raw(3., 3.));
2921 render.handle_incoming_event(param.set_value_at_time_raw(4., 4.));
2922 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(2.5));
2923
2924 let vs = render.compute_intrinsic_values(0., 1., 10);
2925 assert_float_eq!(
2926 vs,
2927 &[0., 1., 2., 2., 2., 2., 2., 2., 2., 2.][0..10],
2928 abs_all <= 0.
2929 );
2930 }
2931 }
2932
2933 #[test]
2934 fn test_cancel_and_hold_during_set_target() {
2935 let context = OfflineAudioContext::new(1, 1, 48000.);
2936
2937 {
2938 let opts = AudioParamDescriptor {
2939 name: String::new(),
2940 automation_rate: AutomationRate::A,
2941 default_value: 0.,
2942 min_value: 0.,
2943 max_value: 2.,
2944 };
2945 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2946 let v0: f32 = 0.;
2948 let v1: f32 = 2.;
2949 let t0: f64 = 0.;
2950 let time_constant: f64 = 1.;
2951
2952 render.handle_incoming_event(param.set_value_at_time_raw(v0, t0));
2953 render.handle_incoming_event(param.set_target_at_time_raw(v1, t0, time_constant));
2954 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(15.));
2955
2956 let mut res = Vec::<f32>::with_capacity(20);
2957
2958 for t in 0..16 {
2960 let val = v1 + (v0 - v1) * (-1. * ((t as f64 - t0) / time_constant)).exp() as f32;
2961 res.push(val);
2962 }
2963
2964 let hold_value = res.pop().unwrap();
2965 res.resize(20, hold_value);
2966
2967 let vs = render.compute_intrinsic_values(0., 1., 10);
2968 assert_float_eq!(vs, &res[0..10], abs_all <= 0.);
2969
2970 let vs = render.compute_intrinsic_values(10., 1., 10);
2971 assert_float_eq!(vs, &res[10..20], abs_all <= 0.);
2972 }
2973 }
2974
2975 #[test]
2976 fn test_cancel_and_hold_during_linear_ramp() {
2977 let context = OfflineAudioContext::new(1, 1, 48000.);
2978
2979 {
2980 let opts = AudioParamDescriptor {
2981 name: String::new(),
2982 automation_rate: AutomationRate::A,
2983 default_value: 0.,
2984 min_value: 0.,
2985 max_value: 10.,
2986 };
2987 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
2988
2989 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(10., 10.));
2990 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(5.));
2991
2992 let vs = render.compute_intrinsic_values(0., 1., 10);
2993 assert_float_eq!(
2994 vs,
2995 &[0., 1., 2., 3., 4., 5., 5., 5., 5., 5.][0..10],
2996 abs_all <= 0.
2997 );
2998 }
2999
3000 {
3001 let opts = AudioParamDescriptor {
3003 name: String::new(),
3004 automation_rate: AutomationRate::A,
3005 default_value: 0.,
3006 min_value: 0.,
3007 max_value: 10.,
3008 };
3009 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3010
3011 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(10., 10.));
3012 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(4.5));
3013
3014 let vs = render.compute_intrinsic_values(0., 1., 10);
3015 assert_float_eq!(
3016 vs,
3017 &[0., 1., 2., 3., 4., 4.5, 4.5, 4.5, 4.5, 4.5][0..10],
3018 abs_all <= 0.
3019 );
3020 }
3021 }
3022
3023 #[test]
3024 fn test_cancel_and_hold_during_exponential_ramp() {
3025 let context = OfflineAudioContext::new(1, 1, 48000.);
3026
3027 {
3028 let opts = AudioParamDescriptor {
3029 name: String::new(),
3030 automation_rate: AutomationRate::A,
3031 default_value: 0.,
3032 min_value: 0.,
3033 max_value: 10.,
3034 };
3035 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3036
3037 render.handle_incoming_event(param.set_value_at_time_raw(0.0001, 0.));
3039 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(1.0, 10.));
3040 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(5.));
3041
3042 let mut res = Vec::<f32>::with_capacity(10);
3045 let start: f32 = 0.0001;
3046 let end: f32 = 1.;
3047
3048 for t in 0..6 {
3049 let value = start * (end / start).powf(t as f32 / 10.);
3050 res.push(value);
3051 }
3052
3053 let hold_value = res.pop().unwrap();
3054 res.resize(10, hold_value);
3055
3056 let vs = render.compute_intrinsic_values(0., 1., 10);
3057 assert_float_eq!(vs, &res[..], abs_all <= 0.);
3058 }
3059
3060 {
3061 let opts = AudioParamDescriptor {
3063 name: String::new(),
3064 automation_rate: AutomationRate::A,
3065 default_value: 0.,
3066 min_value: 0.,
3067 max_value: 10.,
3068 };
3069 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3070
3071 render.handle_incoming_event(param.set_value_at_time_raw(0.0001, 0.));
3073 render.handle_incoming_event(param.exponential_ramp_to_value_at_time_raw(1.0, 10.));
3074 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(4.5));
3075
3076 let mut res = Vec::<f32>::with_capacity(10);
3079 let start: f32 = 0.0001;
3080 let end: f32 = 1.;
3081
3082 for t in 0..5 {
3083 let value = start * (end / start).powf(t as f32 / 10.);
3084 res.push(value);
3085 }
3086
3087 let hold_value = start * (end / start).powf(4.5 / 10.);
3088 res.resize(10, hold_value);
3089
3090 let vs = render.compute_intrinsic_values(0., 1., 10);
3091 assert_float_eq!(vs, &res[..], abs_all <= 0.);
3092 }
3093 }
3094
3095 #[test]
3096 fn test_cancel_and_hold_during_set_value_curve() {
3097 let context = OfflineAudioContext::new(1, 1, 48000.);
3098
3099 {
3100 let opts = AudioParamDescriptor {
3101 name: String::new(),
3102 automation_rate: AutomationRate::A,
3103 default_value: 0.,
3104 min_value: 0.,
3105 max_value: 2.,
3106 };
3107 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3108
3109 let curve = [0., 0.5, 1., 0.5, 0.];
3110 render.handle_incoming_event(param.set_value_curve_at_time_raw(&curve[..], 0., 10.));
3111 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(5.));
3112
3113 let vs = render.compute_intrinsic_values(0., 1., 10);
3114 assert_float_eq!(
3115 vs,
3116 &[0., 0.2, 0.4, 0.6, 0.8, 1., 1., 1., 1., 1.][..],
3117 abs_all <= 1e-7
3118 );
3119 }
3120
3121 {
3122 let opts = AudioParamDescriptor {
3124 name: String::new(),
3125 automation_rate: AutomationRate::A,
3126 default_value: 0.,
3127 min_value: 0.,
3128 max_value: 2.,
3129 };
3130 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3131
3132 let curve = [0., 0.5, 1., 0.5, 0.];
3133 render.handle_incoming_event(param.set_value_curve_at_time_raw(&curve[..], 0., 10.));
3134 render.handle_incoming_event(param.cancel_and_hold_at_time_raw(4.5));
3135
3136 let vs = render.compute_intrinsic_values(0., 1., 10);
3137 assert_float_eq!(
3138 vs,
3139 &[0., 0.2, 0.4, 0.6, 0.8, 0.9, 0.9, 0.9, 0.9, 0.9][..],
3140 abs_all <= 1e-7
3141 );
3142 }
3143 }
3144
3145 #[test]
3146 fn test_set_value_curve_at_time_a_rate() {
3147 let context = OfflineAudioContext::new(1, 1, 48000.);
3148
3149 let opts = AudioParamDescriptor {
3150 name: String::new(),
3151 automation_rate: AutomationRate::A,
3152 default_value: 0.,
3153 min_value: 0.,
3154 max_value: 10.,
3155 };
3156 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3157
3158 let curve = [0., 0.5, 1., 0.5, 0.];
3160 render.handle_incoming_event(param.set_value_curve_at_time_raw(&curve[..], 0., 10.));
3161
3162 let vs = render.compute_intrinsic_values(0., 1., 10);
3163 assert_float_eq!(
3164 vs,
3165 &[0., 0.2, 0.4, 0.6, 0.8, 1., 0.8, 0.6, 0.4, 0.2][..],
3166 abs_all <= 1e-7
3167 );
3168
3169 let vs = render.compute_intrinsic_values(10., 1., 10);
3170 assert_float_eq!(vs, &[0.; 10][..], abs_all <= 0.);
3171 }
3172
3173 #[test]
3174 fn test_set_value_curve_at_time_a_rate_multiple_frames() {
3175 let context = OfflineAudioContext::new(1, 1, 48000.);
3176
3177 let opts = AudioParamDescriptor {
3178 name: String::new(),
3179 automation_rate: AutomationRate::A,
3180 default_value: 0.,
3181 min_value: 0.,
3182 max_value: 10.,
3183 };
3184 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3185
3186 let curve = [0., 0.5, 1., 0.5, 0.];
3188 render.handle_incoming_event(param.set_value_curve_at_time_raw(&curve[..], 0., 20.));
3189
3190 let vs = render.compute_intrinsic_values(0., 1., 10);
3191 assert_float_eq!(
3192 vs,
3193 &[0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9][..],
3194 abs_all <= 1e-7
3195 );
3196
3197 let vs = render.compute_intrinsic_values(10., 1., 10);
3198 assert_float_eq!(
3199 vs,
3200 &[1., 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1][..],
3201 abs_all <= 1e-7
3202 );
3203
3204 let vs = render.compute_intrinsic_values(20., 1., 10);
3205 assert_float_eq!(vs, &[0.; 10][..], abs_all <= 0.);
3206 }
3207
3208 #[test]
3209 #[should_panic]
3210 fn test_set_value_curve_at_time_insert_while_another_event() {
3211 let context = OfflineAudioContext::new(1, 1, 48000.);
3212
3213 let opts = AudioParamDescriptor {
3214 name: String::new(),
3215 automation_rate: AutomationRate::A,
3216 default_value: 1.,
3217 min_value: 0.,
3218 max_value: 1.,
3219 };
3220 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3221
3222 render.handle_incoming_event(param.set_value_at_time_raw(0.0, 5.));
3223
3224 let curve = [0., 0.5, 1., 0.5, 0.];
3225 render.handle_incoming_event(param.set_value_curve_at_time_raw(&curve[..], 0., 10.));
3226 let _vs = render.compute_intrinsic_values(0., 1., 10);
3229 }
3230
3231 #[test]
3232 #[should_panic]
3233 fn test_set_value_curve_at_time_insert_another_event_inside() {
3234 let context = OfflineAudioContext::new(1, 1, 48000.);
3235
3236 let opts = AudioParamDescriptor {
3237 name: String::new(),
3238 automation_rate: AutomationRate::A,
3239 default_value: 1.,
3240 min_value: 0.,
3241 max_value: 1.,
3242 };
3243 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3244
3245 let curve = [0., 0.5, 1., 0.5, 0.];
3246 render.handle_incoming_event(param.set_value_curve_at_time_raw(&curve[..], 0., 10.));
3247 render.handle_incoming_event(param.set_value_at_time_raw(0.0, 5.));
3248 let _vs = render.compute_intrinsic_values(0., 1., 10);
3251 }
3252
3253 #[test]
3254 fn test_set_value_curve_waits_for_start_time() {
3255 let context = OfflineAudioContext::new(1, 1, 48000.);
3256
3257 let opts = AudioParamDescriptor {
3258 name: String::new(),
3259 automation_rate: AutomationRate::A,
3260 default_value: 0.,
3261 min_value: 0.,
3262 max_value: 10.,
3263 };
3264 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3265
3266 let curve = [0., 0.5, 1., 0.5, 0.];
3268 render.handle_incoming_event(param.set_value_curve_at_time_raw(&curve[..], 5., 10.));
3269
3270 let vs = render.compute_intrinsic_values(0., 1., 10);
3271 assert_float_eq!(
3272 vs,
3273 &[0., 0., 0., 0., 0., 0., 0.2, 0.4, 0.6, 0.8][..],
3274 abs_all <= 0.
3275 );
3276 }
3277
3278 #[test]
3279 fn test_update_automation_rate_to_k() {
3280 let context = OfflineAudioContext::new(1, 1, 48000.);
3281
3282 let opts = AudioParamDescriptor {
3283 name: String::new(),
3284 automation_rate: AutomationRate::A,
3285 default_value: 0.,
3286 min_value: -10.,
3287 max_value: 10.,
3288 };
3289 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3290
3291 render.onmessage(&mut AutomationRate::K);
3292 render.handle_incoming_event(param.set_value_at_time_raw(2., 0.000001));
3293
3294 let vs = render.compute_intrinsic_values(0., 1., 10);
3295 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
3296 }
3297
3298 #[test]
3299 fn test_update_automation_rate_to_a() {
3300 let context = OfflineAudioContext::new(1, 1, 48000.);
3301
3302 let opts = AudioParamDescriptor {
3303 name: String::new(),
3304 automation_rate: AutomationRate::K,
3305 default_value: 0.,
3306 min_value: -10.,
3307 max_value: 10.,
3308 };
3309 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3310
3311 render.onmessage(&mut AutomationRate::A);
3312 render.handle_incoming_event(param.set_value_at_time_raw(2., 0.000001));
3313
3314 let vs = render.compute_intrinsic_values(0., 1., 10);
3315 assert_float_eq!(vs, &[2.; 10][..], abs_all <= 0.);
3316 }
3317
3318 #[test]
3319 fn test_varying_param_size() {
3320 {
3322 let context = OfflineAudioContext::new(1, 1, 48000.);
3323
3324 let opts = AudioParamDescriptor {
3325 name: String::new(),
3326 automation_rate: AutomationRate::A,
3327 default_value: 0.,
3328 min_value: 0.,
3329 max_value: 10.,
3330 };
3331 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3332
3333 render.handle_incoming_event(param.set_value_at_time_raw(0., 0.));
3334 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(9., 9.));
3335
3336 let vs = render.compute_intrinsic_values(0., 1., 10);
3338 let expected = [0., 1., 2., 3., 4., 5., 6., 7., 8., 9.];
3339 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3340
3341 let vs = render.compute_intrinsic_values(10., 1., 10);
3343 let expected = [9.; 1];
3344 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3345
3346 render.handle_incoming_event(param.set_value_at_time_raw(1., 25.));
3348
3349 let vs = render.compute_intrinsic_values(20., 1., 10);
3350 let expected = [9., 9., 9., 9., 9., 1., 1., 1., 1., 1.];
3351 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3352
3353 let vs = render.compute_intrinsic_values(30., 1., 10);
3355 let expected = [1.; 1];
3356 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3357 }
3358
3359 {
3361 let context = OfflineAudioContext::new(1, 1, 48000.);
3362
3363 let opts = AudioParamDescriptor {
3364 name: String::new(),
3365 automation_rate: AutomationRate::A,
3366 default_value: 0.,
3367 min_value: 0.,
3368 max_value: 10.,
3369 };
3370 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3371
3372 render.handle_incoming_event(param.set_value_at_time_raw(0., 0.));
3373 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(9., 9.));
3374 render.handle_incoming_event(param.set_value_at_time_raw(1., 25.));
3375
3376 let vs = render.compute_intrinsic_values(0., 1., 10);
3378 let expected = [0., 1., 2., 3., 4., 5., 6., 7., 8., 9.];
3379 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3380
3381 let vs = render.compute_intrinsic_values(10., 1., 10);
3383 let expected = [9.; 1];
3384 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3385
3386 let vs = render.compute_intrinsic_values(20., 1., 10);
3388 let expected = [9., 9., 9., 9., 9., 1., 1., 1., 1., 1.];
3389 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3390
3391 let vs = render.compute_intrinsic_values(30., 1., 10);
3393 let expected = [1.; 1];
3394 assert_float_eq!(vs, &expected[..], abs_all <= 0.);
3395 }
3396 }
3397
3398 #[test]
3399 fn test_varying_param_size_modulated() {
3400 let alloc = Alloc::with_capacity(1);
3401
3402 {
3404 let context = OfflineAudioContext::new(1, 1, 48000.);
3405
3406 let opts = AudioParamDescriptor {
3407 name: String::new(),
3408 automation_rate: AutomationRate::A,
3409 default_value: 0.,
3410 min_value: 0.,
3411 max_value: 10.,
3412 };
3413 let (_param, mut render) = audio_param_pair(opts, context.mock_registration());
3414
3415 let vs = render.compute_intrinsic_values(0., 1., 128);
3417 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
3418
3419 let signal = alloc.silence();
3421 let input = AudioRenderQuantum::from(signal);
3422
3423 let signal = alloc.silence();
3424 let mut output = AudioRenderQuantum::from(signal);
3425
3426 render.mix_to_output(&input, &mut output);
3427
3428 assert!(output.single_valued());
3429 assert_float_eq!(output.channel_data(0)[0], 0., abs <= 0.);
3430 }
3431
3432 {
3434 let context = OfflineAudioContext::new(1, 1, 48000.);
3435
3436 let opts = AudioParamDescriptor {
3437 name: String::new(),
3438 automation_rate: AutomationRate::A,
3439 default_value: 0.,
3440 min_value: 0.,
3441 max_value: 10.,
3442 };
3443 let (_param, mut render) = audio_param_pair(opts, context.mock_registration());
3444
3445 let vs = render.compute_intrinsic_values(0., 1., 128);
3447 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
3448
3449 let signal = alloc.silence();
3451 let mut input = AudioRenderQuantum::from(signal);
3452 input.channel_data_mut(0)[0] = 1.;
3453
3454 let signal = alloc.silence();
3455 let mut output = AudioRenderQuantum::from(signal);
3456
3457 render.mix_to_output(&input, &mut output);
3458
3459 let mut expected = [0.; 128];
3460 expected[0] = 1.;
3461
3462 assert!(!output.single_valued());
3463 assert_float_eq!(output.channel_data(0)[..], &expected[..], abs_all <= 0.);
3464 }
3465 }
3466
3467 #[test]
3468 fn test_k_rate_makes_input_single_valued() {
3469 let alloc = Alloc::with_capacity(1);
3470 let context = OfflineAudioContext::new(1, 1, 48000.);
3471
3472 let opts = AudioParamDescriptor {
3473 name: String::new(),
3474 automation_rate: AutomationRate::K,
3475 default_value: 0.,
3476 min_value: 0.,
3477 max_value: 10.,
3478 };
3479 let (_param, mut render) = audio_param_pair(opts, context.mock_registration());
3480
3481 let vs = render.compute_intrinsic_values(0., 1., 128);
3483 assert_float_eq!(vs, &[0.; 1][..], abs_all <= 0.);
3484
3485 let signal = alloc.silence();
3487 let mut input = AudioRenderQuantum::from(signal);
3488 input.channel_data_mut(0)[0] = 1.;
3489 input.channel_data_mut(0)[1] = 2.;
3490 input.channel_data_mut(0)[2] = 3.;
3491
3492 let signal = alloc.silence();
3493 let mut output = AudioRenderQuantum::from(signal);
3494
3495 render.mix_to_output(&input, &mut output);
3496
3497 assert!(output.single_valued());
3499 assert_float_eq!(output.channel_data(0)[0], 1., abs <= 0.);
3500 }
3501
3502 #[test]
3503 fn test_full_render_chain() {
3504 let alloc = Alloc::with_capacity(1);
3505 let context = OfflineAudioContext::new(1, 1, 48000.);
3507
3508 let min = 2.;
3509 let max = 42.;
3510 let default = 2.;
3511
3512 let opts = AudioParamDescriptor {
3513 name: String::new(),
3514 automation_rate: AutomationRate::A,
3515 default_value: default,
3516 min_value: min,
3517 max_value: max,
3518 };
3519 let (param, mut render) = audio_param_pair(opts, context.mock_registration());
3520
3521 render.handle_incoming_event(param.set_value_raw(128.));
3522 render.handle_incoming_event(param.linear_ramp_to_value_at_time_raw(0., 128.));
3523
3524 let intrinsic_values = render.compute_intrinsic_values(0., 1., 128);
3525 let mut expected = [0.; 128];
3526 for (i, v) in expected.iter_mut().enumerate() {
3527 *v = 128. - i as f32;
3528 }
3529 assert_float_eq!(intrinsic_values, &expected[..], abs_all <= 0.);
3530
3531 let signal = alloc.silence();
3532 let mut input = AudioRenderQuantum::from(signal);
3533 input.channel_data_mut(0)[0] = f32::NAN;
3534 let signal = alloc.silence();
3535 let mut output = AudioRenderQuantum::from(signal);
3536
3537 render.mix_to_output(&input, &mut output);
3538
3539 expected.iter_mut().for_each(|v| *v = v.clamp(min, max));
3541 expected[0] = 2.;
3543
3544 assert_float_eq!(output.channel_data(0)[..], &expected[..], abs_all <= 0.);
3545 }
3546}