Skip to main content

melody_bay/webaudio/nodes/
sources.rs

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}