1#[derive(Debug, Clone)]
2pub struct OscillatorNode {
3 id: NodeId,
4 graph: Arc<Mutex<GraphInner>>,
5}
6
7#[derive(Debug, Clone, PartialEq)]
8pub enum OscillatorType {
9 Basic(Waveform),
10 Custom(PeriodicWave),
11}
12
13impl Default for OscillatorType {
14 fn default() -> Self {
15 Self::Basic(Waveform::Sine)
16 }
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum OscillatorTypeValue {
21 Sine,
22 Square,
23 Sawtooth,
24 Triangle,
25 Custom,
26}
27
28impl From<Waveform> for OscillatorTypeValue {
29 fn from(value: Waveform) -> Self {
30 match value {
31 Waveform::Sine => Self::Sine,
32 Waveform::Square => Self::Square,
33 Waveform::Sawtooth => Self::Sawtooth,
34 Waveform::Triangle => Self::Triangle,
35 }
36 }
37}
38
39#[derive(Debug, Clone, PartialEq)]
40pub struct OscillatorOptions {
41 pub oscillator_type: OscillatorType,
42 pub frequency: f32,
43 pub detune: f32,
44}
45
46impl Default for OscillatorOptions {
47 fn default() -> Self {
48 Self {
49 oscillator_type: OscillatorType::default(),
50 frequency: 440.0,
51 detune: 0.0,
52 }
53 }
54}
55
56impl OscillatorNode {
57 #[must_use]
58 pub fn type_value(&self) -> Waveform {
59 let inner = self.graph.lock().expect("graph mutex poisoned");
60 if let NodeKind::Oscillator { waveform, .. } = &inner.nodes[self.id.0].kind {
61 *waveform
62 } else {
63 Waveform::Sine
64 }
65 }
66
67 #[must_use]
68 pub fn oscillator_type(&self) -> OscillatorTypeValue {
69 let inner = self.graph.lock().expect("graph mutex poisoned");
70 if let NodeKind::Oscillator {
71 waveform,
72 periodic_wave,
73 ..
74 } = &inner.nodes[self.id.0].kind
75 {
76 if periodic_wave.is_some() {
77 OscillatorTypeValue::Custom
78 } else {
79 (*waveform).into()
80 }
81 } else {
82 OscillatorTypeValue::Sine
83 }
84 }
85
86 #[must_use]
87 pub fn frequency_value(&self) -> f32 {
88 let inner = self.graph.lock().expect("graph mutex poisoned");
89 if let NodeKind::Oscillator { frequency, .. } = &inner.nodes[self.id.0].kind {
90 frequency.value()
91 } else {
92 0.0
93 }
94 }
95
96 pub fn set_type(&self, waveform: Waveform) {
97 let mut inner = self.graph.lock().expect("graph mutex poisoned");
98 if let NodeKind::Oscillator {
99 waveform: node_waveform,
100 periodic_wave,
101 ..
102 } = &mut inner.nodes[self.id.0].kind
103 {
104 *node_waveform = waveform;
105 *periodic_wave = None;
106 }
107 }
108
109 #[must_use]
110 pub fn frequency(&self) -> AudioParamHandle {
111 AudioParamHandle {
112 graph: Arc::clone(&self.graph),
113 id: self.frequency_param(),
114 }
115 }
116
117 #[must_use]
118 fn frequency_param(&self) -> ParamId {
119 ParamId {
120 node: self.id,
121 param: ParamKind::Frequency,
122 }
123 }
124
125 #[must_use]
126 pub fn detune(&self) -> AudioParamHandle {
127 AudioParamHandle {
128 graph: Arc::clone(&self.graph),
129 id: self.detune_param(),
130 }
131 }
132
133 #[must_use]
134 fn detune_param(&self) -> ParamId {
135 ParamId {
136 node: self.id,
137 param: ParamKind::Detune,
138 }
139 }
140
141 #[must_use]
142 pub fn param(&self, name: &str) -> Option<AudioParamHandle> {
143 self.parameter(name)
144 }
145
146 #[must_use]
147 pub fn parameter(&self, name: &str) -> Option<AudioParamHandle> {
148 match name {
149 "frequency" => Some(self.frequency()),
150 "detune" => Some(self.detune()),
151 _ => None,
152 }
153 }
154
155 pub fn set_periodic_wave(&self, wave: PeriodicWave) {
156 let mut inner = self.graph.lock().expect("graph mutex poisoned");
157 if let NodeKind::Oscillator { periodic_wave, .. } = &mut inner.nodes[self.id.0].kind {
158 *periodic_wave = Some(wave);
159 }
160 }
161
162 #[must_use]
163 pub fn ended(&self) -> bool {
164 let inner = self.graph.lock().expect("graph mutex poisoned");
165 if let NodeKind::Oscillator { ended, .. } = &inner.nodes[self.id.0].kind {
166 ended.load(Ordering::SeqCst)
167 } else {
168 false
169 }
170 }
171
172 pub fn try_start(&self, time: f64) -> Result<(), GraphError> {
173 validate_source_time(time)?;
174 let mut inner = self.graph.lock().expect("graph mutex poisoned");
175 if let NodeKind::Oscillator {
176 start_time,
177 start_scheduled,
178 ended,
179 ..
180 } = &mut inner.nodes[self.id.0].kind
181 {
182 if *start_scheduled {
183 return Err(GraphError::SourceAlreadyStarted);
184 }
185 *start_time = time.max(0.0);
186 *start_scheduled = true;
187 ended.store(false, Ordering::SeqCst);
188 }
189 Ok(())
190 }
191
192 pub fn try_stop(&self, time: f64) -> Result<(), GraphError> {
193 validate_source_time(time)?;
194 let mut inner = self.graph.lock().expect("graph mutex poisoned");
195 if let NodeKind::Oscillator {
196 stop_time,
197 start_scheduled,
198 stop_scheduled,
199 ended,
200 ..
201 } = &mut inner.nodes[self.id.0].kind
202 {
203 if !*start_scheduled {
204 return Err(GraphError::SourceNotStarted);
205 }
206 if ended.load(Ordering::SeqCst) {
207 return Ok(());
208 }
209 let time = time.max(0.0);
210 *stop_time = Some(time);
211 *stop_scheduled = true;
212 }
213 Ok(())
214 }
215}
216
217impl From<OscillatorNode> for NodeId {
218 fn from(value: OscillatorNode) -> Self {
219 value.id
220 }
221}
222
223impl From<&OscillatorNode> for NodeId {
224 fn from(value: &OscillatorNode) -> Self {
225 value.id
226 }
227}
228
229#[derive(Debug, Clone)]
230pub struct ConstantSourceNode {
231 id: NodeId,
232 graph: Arc<Mutex<GraphInner>>,
233}
234
235#[derive(Debug, Clone, Copy, PartialEq)]
236pub struct ConstantSourceOptions {
237 pub offset: f32,
238}
239
240impl Default for ConstantSourceOptions {
241 fn default() -> Self {
242 Self { offset: 1.0 }
243 }
244}
245
246impl ConstantSourceNode {
247 #[must_use]
248 pub fn offset(&self) -> AudioParamHandle {
249 AudioParamHandle {
250 graph: Arc::clone(&self.graph),
251 id: self.offset_param(),
252 }
253 }
254
255 #[must_use]
256 fn offset_param(&self) -> ParamId {
257 ParamId {
258 node: self.id,
259 param: ParamKind::Offset,
260 }
261 }
262
263 #[must_use]
264 pub fn param(&self, name: &str) -> Option<AudioParamHandle> {
265 self.parameter(name)
266 }
267
268 #[must_use]
269 pub fn parameter(&self, name: &str) -> Option<AudioParamHandle> {
270 match name {
271 "offset" => Some(self.offset()),
272 _ => None,
273 }
274 }
275
276 #[must_use]
277 pub fn ended(&self) -> bool {
278 let inner = self.graph.lock().expect("graph mutex poisoned");
279 if let NodeKind::Constant { ended, .. } = &inner.nodes[self.id.0].kind {
280 ended.load(Ordering::SeqCst)
281 } else {
282 false
283 }
284 }
285
286 pub fn try_start(&self, time: f64) -> Result<(), GraphError> {
287 validate_source_time(time)?;
288 let mut inner = self.graph.lock().expect("graph mutex poisoned");
289 if let NodeKind::Constant {
290 start_time,
291 start_scheduled,
292 ended,
293 ..
294 } = &mut inner.nodes[self.id.0].kind
295 {
296 if *start_scheduled {
297 return Err(GraphError::SourceAlreadyStarted);
298 }
299 *start_time = time.max(0.0);
300 *start_scheduled = true;
301 ended.store(false, Ordering::SeqCst);
302 }
303 Ok(())
304 }
305
306 pub fn try_stop(&self, time: f64) -> Result<(), GraphError> {
307 validate_source_time(time)?;
308 let mut inner = self.graph.lock().expect("graph mutex poisoned");
309 if let NodeKind::Constant {
310 stop_time,
311 start_scheduled,
312 stop_scheduled,
313 ended,
314 ..
315 } = &mut inner.nodes[self.id.0].kind
316 {
317 if !*start_scheduled {
318 return Err(GraphError::SourceNotStarted);
319 }
320 if ended.load(Ordering::SeqCst) {
321 return Ok(());
322 }
323 let time = time.max(0.0);
324 *stop_time = Some(time);
325 *stop_scheduled = true;
326 }
327 Ok(())
328 }
329}
330
331impl From<ConstantSourceNode> for NodeId {
332 fn from(value: ConstantSourceNode) -> Self {
333 value.id
334 }
335}
336
337impl From<&ConstantSourceNode> for NodeId {
338 fn from(value: &ConstantSourceNode) -> Self {
339 value.id
340 }
341}
342
343#[derive(Debug, Clone)]
344pub struct AudioBufferSourceNode {
345 id: NodeId,
346 graph: Arc<Mutex<GraphInner>>,
347}
348
349#[derive(Debug, Clone, PartialEq)]
350pub struct AudioBufferSourceOptions {
351 pub buffer: Option<AudioBuffer>,
352 pub playback_rate: f32,
353 pub detune: f32,
354 pub looping: bool,
355 pub loop_start: f64,
356 pub loop_end: f64,
357}
358
359impl Default for AudioBufferSourceOptions {
360 fn default() -> Self {
361 Self {
362 buffer: None,
363 playback_rate: 1.0,
364 detune: 0.0,
365 looping: false,
366 loop_start: 0.0,
367 loop_end: 0.0,
368 }
369 }
370}
371
372impl AudioBufferSourceNode {
373 pub fn try_set_buffer(&self, buffer: AudioBuffer) -> Result<(), GraphError> {
374 let mut inner = self.graph.lock().expect("graph mutex poisoned");
375 if let NodeKind::AudioBufferSource {
376 buffer: node_buffer,
377 buffer_assigned,
378 acquired_buffer,
379 start_scheduled,
380 ..
381 } = &mut inner.nodes[self.id.0].kind
382 {
383 if *buffer_assigned {
384 return Err(GraphError::InvalidState);
385 }
386 *buffer_assigned = true;
387 *node_buffer = Some(buffer.clone());
388 if *start_scheduled {
389 *acquired_buffer = Some(buffer);
390 }
391 }
392 Ok(())
393 }
394
395 pub fn clear_buffer(&self) {
396 let mut inner = self.graph.lock().expect("graph mutex poisoned");
397 if let NodeKind::AudioBufferSource {
398 buffer: node_buffer,
399 ..
400 } = &mut inner.nodes[self.id.0].kind
401 {
402 *node_buffer = None;
403 }
404 }
405
406 #[must_use]
407 pub fn buffer_value(&self) -> Option<AudioBuffer> {
408 let inner = self.graph.lock().expect("graph mutex poisoned");
409 if let NodeKind::AudioBufferSource { buffer, .. } = &inner.nodes[self.id.0].kind {
410 buffer.clone()
411 } else {
412 None
413 }
414 }
415
416 #[must_use]
417 pub fn playback_rate(&self) -> AudioParamHandle {
418 AudioParamHandle {
419 graph: Arc::clone(&self.graph),
420 id: self.playback_rate_param(),
421 }
422 }
423
424 #[must_use]
425 fn playback_rate_param(&self) -> ParamId {
426 ParamId {
427 node: self.id,
428 param: ParamKind::PlaybackRate,
429 }
430 }
431
432 #[must_use]
433 pub fn detune(&self) -> AudioParamHandle {
434 AudioParamHandle {
435 graph: Arc::clone(&self.graph),
436 id: self.detune_param(),
437 }
438 }
439
440 #[must_use]
441 fn detune_param(&self) -> ParamId {
442 ParamId {
443 node: self.id,
444 param: ParamKind::Detune,
445 }
446 }
447
448 #[must_use]
449 pub fn param(&self, name: &str) -> Option<AudioParamHandle> {
450 self.parameter(name)
451 }
452
453 #[must_use]
454 pub fn parameter(&self, name: &str) -> Option<AudioParamHandle> {
455 match name {
456 "playbackRate" | "playback_rate" => Some(self.playback_rate()),
457 "detune" => Some(self.detune()),
458 _ => None,
459 }
460 }
461
462 pub fn try_loop_range(&self, start_seconds: f64, end_seconds: f64) -> Result<(), GraphError> {
463 if !start_seconds.is_finite() || !end_seconds.is_finite() {
464 return Err(GraphError::InvalidLoopRange);
465 }
466 let mut inner = self.graph.lock().expect("graph mutex poisoned");
467 if let NodeKind::AudioBufferSource { loop_range, .. } = &mut inner.nodes[self.id.0].kind {
468 *loop_range = Some((start_seconds, end_seconds));
469 }
470 Ok(())
471 }
472
473 pub fn try_loop_start(&self, start_seconds: f64) -> Result<(), GraphError> {
474 if !start_seconds.is_finite() {
475 return Err(GraphError::InvalidLoopRange);
476 }
477 let mut inner = self.graph.lock().expect("graph mutex poisoned");
478 if let NodeKind::AudioBufferSource { loop_range, .. } = &mut inner.nodes[self.id.0].kind {
479 let end_seconds = loop_range.map(|(_, end)| end).unwrap_or(0.0);
480 *loop_range = Some((start_seconds, end_seconds));
481 }
482 Ok(())
483 }
484
485 pub fn try_loop_end(&self, end_seconds: f64) -> Result<(), GraphError> {
486 if !end_seconds.is_finite() {
487 return Err(GraphError::InvalidLoopRange);
488 }
489 let mut inner = self.graph.lock().expect("graph mutex poisoned");
490 if let NodeKind::AudioBufferSource { loop_range, .. } = &mut inner.nodes[self.id.0].kind {
491 let start_seconds = loop_range.map(|(start, _)| start).unwrap_or(0.0);
492 *loop_range = Some((start_seconds, end_seconds));
493 }
494 Ok(())
495 }
496
497 pub fn set_looping(&self, enabled: bool) {
498 let mut inner = self.graph.lock().expect("graph mutex poisoned");
499 if let NodeKind::AudioBufferSource { looping, .. } = &mut inner.nodes[self.id.0].kind {
500 *looping = enabled;
501 }
502 }
503
504 #[must_use]
505 pub fn looping_value(&self) -> bool {
506 let inner = self.graph.lock().expect("graph mutex poisoned");
507 if let NodeKind::AudioBufferSource { looping, .. } = &inner.nodes[self.id.0].kind {
508 *looping
509 } else {
510 false
511 }
512 }
513
514 #[must_use]
515 pub fn loop_range_value(&self) -> Option<(f64, f64)> {
516 let inner = self.graph.lock().expect("graph mutex poisoned");
517 if let NodeKind::AudioBufferSource { loop_range, .. } = &inner.nodes[self.id.0].kind {
518 *loop_range
519 } else {
520 None
521 }
522 }
523
524 #[must_use]
525 pub fn loop_start_value(&self) -> f64 {
526 self.loop_range_value()
527 .map(|(start_seconds, _)| start_seconds)
528 .unwrap_or(0.0)
529 }
530
531 #[must_use]
532 pub fn loop_end_value(&self) -> f64 {
533 self.loop_range_value()
534 .map(|(_, end_seconds)| end_seconds)
535 .unwrap_or(0.0)
536 }
537
538 #[must_use]
539 pub fn ended(&self) -> bool {
540 let inner = self.graph.lock().expect("graph mutex poisoned");
541 if let NodeKind::AudioBufferSource { ended, .. } = &inner.nodes[self.id.0].kind {
542 ended.load(Ordering::SeqCst)
543 } else {
544 false
545 }
546 }
547
548 pub fn try_start(&self, time: f64) -> Result<(), GraphError> {
549 self.try_start_with_offset(time, 0.0)
550 }
551
552 pub fn try_start_with_offset(&self, time: f64, offset: f64) -> Result<(), GraphError> {
553 self.try_set_start(time, offset, None)
554 }
555
556 pub fn try_start_with_offset_and_duration(
557 &self,
558 time: f64,
559 offset: f64,
560 duration: f64,
561 ) -> Result<(), GraphError> {
562 self.try_set_start(time, offset, Some(duration))
563 }
564
565 fn try_set_start(
566 &self,
567 time: f64,
568 source_offset: f64,
569 source_duration: Option<f64>,
570 ) -> Result<(), GraphError> {
571 validate_source_time(time)?;
572 validate_source_time(source_offset)?;
573 if let Some(duration) = source_duration {
574 validate_source_time(duration)?;
575 }
576 let mut inner = self.graph.lock().expect("graph mutex poisoned");
577 if let NodeKind::AudioBufferSource {
578 buffer,
579 acquired_buffer,
580 start_time,
581 start_scheduled,
582 ended,
583 offset,
584 duration,
585 ..
586 } = &mut inner.nodes[self.id.0].kind
587 {
588 if *start_scheduled {
589 return Err(GraphError::SourceAlreadyStarted);
590 }
591 *start_time = time.max(0.0);
592 *start_scheduled = true;
593 *acquired_buffer = buffer.clone();
594 ended.store(false, Ordering::SeqCst);
595 *offset = source_offset.max(0.0);
596 *duration = source_duration;
597 }
598 Ok(())
599 }
600
601 pub fn try_stop(&self, time: f64) -> Result<(), GraphError> {
602 validate_source_time(time)?;
603 let mut inner = self.graph.lock().expect("graph mutex poisoned");
604 if let NodeKind::AudioBufferSource {
605 stop_time,
606 start_scheduled,
607 stop_scheduled,
608 ended,
609 ..
610 } = &mut inner.nodes[self.id.0].kind
611 {
612 if !*start_scheduled {
613 return Err(GraphError::SourceNotStarted);
614 }
615 if ended.load(Ordering::SeqCst) {
616 return Ok(());
617 }
618 let time = time.max(0.0);
619 *stop_time = Some(time);
620 *stop_scheduled = true;
621 }
622 Ok(())
623 }
624}
625
626impl From<AudioBufferSourceNode> for NodeId {
627 fn from(value: AudioBufferSourceNode) -> Self {
628 value.id
629 }
630}
631
632impl From<&AudioBufferSourceNode> for NodeId {
633 fn from(value: &AudioBufferSourceNode) -> Self {
634 value.id
635 }
636}
637
638#[derive(Debug, Clone)]
639pub struct SoundDataSourceNode {
640 id: NodeId,
641 graph: Arc<Mutex<GraphInner>>,
642}
643
644impl SoundDataSourceNode {
645 #[must_use]
646 pub fn ended(&self) -> bool {
647 let inner = self.graph.lock().expect("graph mutex poisoned");
648 if let NodeKind::ExternalSound { ended, .. } = &inner.nodes[self.id.0].kind {
649 ended.load(Ordering::SeqCst)
650 } else {
651 false
652 }
653 }
654
655 pub fn try_start(&self, time: f64) -> Result<(), GraphError> {
656 validate_source_time(time)?;
657 let mut inner = self.graph.lock().expect("graph mutex poisoned");
658 if let NodeKind::ExternalSound {
659 start_time,
660 start_scheduled,
661 ended,
662 ..
663 } = &mut inner.nodes[self.id.0].kind
664 {
665 if *start_scheduled {
666 return Err(GraphError::SourceAlreadyStarted);
667 }
668 *start_time = time.max(0.0);
669 *start_scheduled = true;
670 ended.store(false, Ordering::SeqCst);
671 }
672 Ok(())
673 }
674
675 pub fn try_stop(&self, time: f64) -> Result<(), GraphError> {
676 validate_source_time(time)?;
677 let mut inner = self.graph.lock().expect("graph mutex poisoned");
678 if let NodeKind::ExternalSound {
679 stop_time,
680 start_scheduled,
681 stop_scheduled,
682 ended,
683 ..
684 } = &mut inner.nodes[self.id.0].kind
685 {
686 if !*start_scheduled {
687 return Err(GraphError::SourceNotStarted);
688 }
689 if ended.load(Ordering::SeqCst) {
690 return Ok(());
691 }
692 *stop_time = Some(time.max(0.0));
693 *stop_scheduled = true;
694 }
695 Ok(())
696 }
697}
698
699impl From<SoundDataSourceNode> for NodeId {
700 fn from(value: SoundDataSourceNode) -> Self {
701 value.id
702 }
703}
704
705impl From<&SoundDataSourceNode> for NodeId {
706 fn from(value: &SoundDataSourceNode) -> Self {
707 value.id
708 }
709}