1#![allow(clippy::float_cmp)]
50
51use crate::{
52 buffer::{streaming::StreamingBuffer, SoundBuffer, SoundBufferResource},
53 bus::AudioBusGraph,
54 context::DistanceModel,
55 error::SoundError,
56 listener::Listener,
57};
58use fyrox_core::{
59 algebra::Vector3,
60 reflect::prelude::*,
61 uuid_provider,
62 visitor::{Visit, VisitResult, Visitor},
63};
64use std::time::Duration;
65
66#[derive(Eq, PartialEq, Copy, Clone, Debug, Reflect, Visit)]
68#[repr(u32)]
69pub enum Status {
70 Stopped = 0,
73
74 Playing = 1,
76
77 Paused = 2,
80}
81
82uuid_provider!(Status = "1980bded-86cd-4eff-a5db-bab729bdb3ad");
83
84#[derive(Debug, Clone, Reflect, Visit)]
86pub struct SoundSource {
87 name: String,
88 #[reflect(hidden)]
89 buffer: Option<SoundBufferResource>,
90 #[reflect(hidden)]
95 buf_read_pos: f64,
96 #[reflect(hidden)]
98 playback_pos: f64,
99 #[reflect(min_value = 0.0, step = 0.05)]
100 panning: f32,
101 #[reflect(min_value = 0.0, step = 0.05)]
102 pitch: f64,
103 #[reflect(min_value = 0.0, step = 0.05)]
104 gain: f32,
105 looping: bool,
106 #[reflect(min_value = 0.0, max_value = 1.0, step = 0.05)]
107 spatial_blend: f32,
108 #[reflect(read_only)]
117 resampling_multiplier: f64,
118 status: Status,
119 #[visit(optional)]
120 pub(crate) bus: String,
121 play_once: bool,
122 #[reflect(hidden)]
129 #[visit(skip)]
130 pub(crate) last_left_gain: Option<f32>,
131 #[reflect(hidden)]
132 #[visit(skip)]
133 pub(crate) last_right_gain: Option<f32>,
134 #[reflect(hidden)]
135 #[visit(skip)]
136 pub(crate) frame_samples: Vec<(f32, f32)>,
137 #[reflect(hidden)]
139 #[visit(skip)]
140 prev_buffer_sample: (f32, f32),
141 #[reflect(min_value = 0.0, step = 0.05)]
142 radius: f32,
143 position: Vector3<f32>,
144 #[reflect(min_value = 0.0, step = 0.05)]
145 max_distance: f32,
146 #[reflect(min_value = 0.0, step = 0.05)]
147 rolloff_factor: f32,
148 #[reflect(hidden)]
150 #[visit(skip)]
151 pub(crate) prev_left_samples: Vec<f32>,
152 #[reflect(hidden)]
153 #[visit(skip)]
154 pub(crate) prev_right_samples: Vec<f32>,
155 #[reflect(hidden)]
156 #[visit(skip)]
157 pub(crate) prev_sampling_vector: Vector3<f32>,
158 #[reflect(hidden)]
159 #[visit(skip)]
160 pub(crate) prev_distance_gain: Option<f32>,
161}
162
163impl Default for SoundSource {
164 fn default() -> Self {
165 Self {
166 name: Default::default(),
167 buffer: None,
168 buf_read_pos: 0.0,
169 playback_pos: 0.0,
170 panning: 0.0,
171 pitch: 1.0,
172 gain: 1.0,
173 spatial_blend: 1.0,
174 looping: false,
175 resampling_multiplier: 1.0,
176 status: Status::Stopped,
177 bus: "Master".to_string(),
178 play_once: false,
179 last_left_gain: None,
180 last_right_gain: None,
181 frame_samples: Default::default(),
182 prev_buffer_sample: (0.0, 0.0),
183 radius: 1.0,
184 position: Vector3::new(0.0, 0.0, 0.0),
185 max_distance: f32::MAX,
186 rolloff_factor: 1.0,
187 prev_left_samples: Default::default(),
188 prev_right_samples: Default::default(),
189 prev_sampling_vector: Vector3::new(0.0, 0.0, 1.0),
190 prev_distance_gain: None,
191 }
192 }
193}
194
195impl SoundSource {
196 pub fn set_name<N: AsRef<str>>(&mut self, name: N) {
198 name.as_ref().clone_into(&mut self.name);
199 }
200
201 pub fn name(&self) -> &str {
203 &self.name
204 }
205
206 pub fn name_owned(&self) -> String {
208 self.name.to_owned()
209 }
210
211 pub fn set_spatial_blend(&mut self, k: f32) {
215 self.spatial_blend = k.clamp(0.0, 1.0);
216 }
217
218 pub fn spatial_blend(&self) -> f32 {
220 self.spatial_blend
221 }
222
223 pub fn set_buffer(
226 &mut self,
227 buffer: Option<SoundBufferResource>,
228 ) -> Result<Option<SoundBufferResource>, SoundError> {
229 self.buf_read_pos = 0.0;
230 self.playback_pos = 0.0;
231
232 if let Some(buffer) = self.buffer.clone() {
235 if let Some(SoundBuffer::Streaming(streaming)) = buffer.state().data() {
236 streaming.use_count = streaming.use_count.saturating_sub(1);
237 }
238 }
239
240 if let Some(buffer) = buffer.clone() {
241 match buffer.state().data() {
242 None => return Err(SoundError::BufferFailedToLoad),
243 Some(locked_buffer) => {
244 if let SoundBuffer::Streaming(ref mut streaming) = *locked_buffer {
246 if streaming.use_count != 0 {
247 return Err(SoundError::StreamingBufferAlreadyInUse);
248 }
249 streaming.use_count += 1;
250 }
251
252 let device_sample_rate = f64::from(crate::context::SAMPLE_RATE);
254 let sample_rate = locked_buffer.sample_rate() as f64;
255 self.resampling_multiplier = sample_rate / device_sample_rate;
256 }
257 }
258 }
259
260 Ok(std::mem::replace(&mut self.buffer, buffer))
261 }
262
263 pub fn buffer(&self) -> Option<SoundBufferResource> {
265 self.buffer.clone()
266 }
267
268 pub fn set_play_once(&mut self, play_once: bool) {
276 self.play_once = play_once;
277 }
278
279 pub fn is_play_once(&self) -> bool {
281 self.play_once
282 }
283
284 pub fn set_gain(&mut self, gain: f32) -> &mut Self {
292 self.gain = gain;
293 self
294 }
295
296 pub fn gain(&self) -> f32 {
298 self.gain
299 }
300
301 pub fn set_panning(&mut self, panning: f32) -> &mut Self {
304 self.panning = panning.clamp(-1.0, 1.0);
305 self
306 }
307
308 pub fn panning(&self) -> f32 {
310 self.panning
311 }
312
313 pub fn status(&self) -> Status {
315 self.status
316 }
317
318 pub fn play(&mut self) -> &mut Self {
320 self.status = Status::Playing;
321 self
322 }
323
324 pub fn pause(&mut self) -> &mut Self {
326 self.status = Status::Paused;
327 self
328 }
329
330 pub fn set_looping(&mut self, looping: bool) -> &mut Self {
333 self.looping = looping;
334 self
335 }
336
337 pub fn is_looping(&self) -> bool {
339 self.looping
340 }
341
342 pub fn set_pitch(&mut self, pitch: f64) -> &mut Self {
344 self.pitch = pitch.abs();
345 self
346 }
347
348 pub fn pitch(&self) -> f64 {
350 self.pitch
351 }
352
353 pub fn stop(&mut self) -> Result<(), SoundError> {
355 self.status = Status::Stopped;
356
357 self.buf_read_pos = 0.0;
358 self.playback_pos = 0.0;
359
360 if let Some(buffer) = self.buffer.as_ref() {
361 if let Some(SoundBuffer::Streaming(streaming)) = buffer.state().data() {
362 streaming.rewind()?;
363 }
364 }
365
366 Ok(())
367 }
368 pub fn set_position(&mut self, position: Vector3<f32>) -> &mut Self {
370 self.position = position;
371 self
372 }
373
374 pub fn position(&self) -> Vector3<f32> {
376 self.position
377 }
378
379 pub fn set_radius(&mut self, radius: f32) -> &mut Self {
381 self.radius = radius;
382 self
383 }
384
385 pub fn radius(&self) -> f32 {
387 self.radius
388 }
389
390 pub fn set_rolloff_factor(&mut self, rolloff_factor: f32) -> &mut Self {
394 self.rolloff_factor = rolloff_factor;
395 self
396 }
397
398 pub fn rolloff_factor(&self) -> f32 {
400 self.rolloff_factor
401 }
402
403 pub fn set_max_distance(&mut self, max_distance: f32) -> &mut Self {
408 self.max_distance = max_distance;
409 self
410 }
411
412 pub fn max_distance(&self) -> f32 {
414 self.max_distance
415 }
416
417 pub fn set_bus<S: AsRef<str>>(&mut self, bus: S) {
420 bus.as_ref().clone_into(&mut self.bus);
421 }
422
423 pub fn bus(&self) -> &str {
425 &self.bus
426 }
427
428 pub(crate) fn calculate_distance_gain(
432 &self,
433 listener: &Listener,
434 distance_model: DistanceModel,
435 ) -> f32 {
436 let distance = self
437 .position
438 .metric_distance(&listener.position())
439 .clamp(self.radius, self.max_distance);
440 match distance_model {
441 DistanceModel::None => 1.0,
442 DistanceModel::InverseDistance => {
443 self.radius / (self.radius + self.rolloff_factor * (distance - self.radius))
444 }
445 DistanceModel::LinearDistance => {
446 1.0 - self.radius * (distance - self.radius) / (self.max_distance - self.radius)
447 }
448 DistanceModel::ExponentDistance => (distance / self.radius).powf(-self.rolloff_factor),
449 }
450 }
451
452 pub(crate) fn calculate_panning(&self, listener: &Listener) -> f32 {
453 (listener.position() - self.position)
454 .try_normalize(f32::EPSILON)
455 .unwrap_or_else(|| listener.look_axis())
458 .dot(&listener.ear_axis())
459 }
460
461 pub(crate) fn calculate_sampling_vector(&self, listener: &Listener) -> Vector3<f32> {
462 let to_self = listener.position() - self.position;
463
464 (listener.basis() * to_self)
465 .try_normalize(f32::EPSILON)
466 .unwrap_or_else(|| Vector3::new(0.0, 0.0, 1.0))
469 }
470
471 pub fn playback_time(&self) -> Duration {
473 if let Some(buffer) = self.buffer.as_ref() {
474 if let Some(buffer) = buffer.state().data() {
475 return Duration::from_secs_f64(self.playback_pos / (buffer.sample_rate() as f64));
476 }
477 }
478
479 Duration::from_secs(0)
480 }
481
482 pub fn set_playback_time(&mut self, time: Duration) {
484 if let Some(buffer) = self.buffer.as_ref() {
485 if let Some(buffer) = buffer.state().data() {
486 if let SoundBuffer::Streaming(ref mut streaming) = *buffer {
487 streaming.time_seek(time.clamp(Duration::from_secs(0), streaming.duration()));
489 }
490 self.playback_pos = (time.as_secs_f64() * buffer.sample_rate as f64)
492 .clamp(0.0, buffer.duration().as_secs_f64());
493 self.buf_read_pos = match *buffer {
495 SoundBuffer::Streaming(ref mut streaming) => {
496 streaming.read_next_block();
498 self.playback_pos % (StreamingBuffer::STREAM_SAMPLE_COUNT as f64)
501 }
502 SoundBuffer::Generic(_) => self.playback_pos,
503 };
504 assert!(
505 self.buf_read_pos * (buffer.channel_count() as f64)
506 < buffer.samples().len() as f64
507 );
508 }
509 }
510 }
511
512 pub(crate) fn render(&mut self, amount: usize) {
513 if self.frame_samples.capacity() < amount {
514 self.frame_samples = Vec::with_capacity(amount);
515 }
516
517 self.frame_samples.clear();
518
519 if let Some(buffer) = self.buffer.clone() {
520 let mut state = buffer.state();
521 if let Some(buffer) = state.data() {
522 if self.status == Status::Playing && !buffer.is_empty() {
523 self.render_playing(buffer, amount);
524 }
525 }
526 }
527 self.frame_samples.resize(amount, (0.0, 0.0));
529 }
530
531 fn render_playing(&mut self, buffer: &mut SoundBuffer, amount: usize) {
532 let mut count = 0;
533 loop {
534 count += self.render_until_block_end(buffer, amount - count);
535 if count == amount {
536 break;
537 }
538
539 let channel_count = buffer.channel_count();
540 let len = buffer.samples().len();
541 let mut end_reached = true;
542 if let SoundBuffer::Streaming(streaming) = buffer {
543 if len != channel_count * StreamingBuffer::STREAM_SAMPLE_COUNT {
545 let _ = streaming.rewind();
546 } else {
547 end_reached = false;
548 }
549 self.prev_buffer_sample = get_last_sample(streaming);
550 streaming.read_next_block();
551 }
552 if end_reached {
553 self.buf_read_pos = 0.0;
554 self.playback_pos = 0.0;
555 if !self.looping {
556 self.status = Status::Stopped;
557 return;
558 }
559 } else {
560 self.buf_read_pos -= len as f64 / channel_count as f64;
561 }
562 }
563 }
564
565 fn render_until_block_end(&mut self, buffer: &mut SoundBuffer, mut amount: usize) -> usize {
568 let step = self.pitch * self.resampling_multiplier;
569 if step == 1.0 {
570 if self.buf_read_pos < 0.0 {
571 self.frame_samples.push(self.prev_buffer_sample);
573 self.buf_read_pos = 0.0;
574 amount -= 1;
575 }
576 let from = self.buf_read_pos as usize;
578 let buffer_len = buffer.samples.len() / buffer.channel_count;
579 let rendered = (buffer_len - from).min(amount);
580 if buffer.channel_count == 2 {
581 for i in from..from + rendered {
582 self.frame_samples
583 .push((buffer.samples[i * 2], buffer.samples[i * 2 + 1]))
584 }
585 } else {
586 for i in from..from + rendered {
587 self.frame_samples
588 .push((buffer.samples[i], buffer.samples[i]))
589 }
590 }
591 self.buf_read_pos += rendered as f64;
592 self.playback_pos += rendered as f64;
593 rendered
594 } else {
595 self.render_until_block_end_resample(buffer, amount, step)
596 }
597 }
598
599 fn render_until_block_end_resample(
601 &mut self,
602 buffer: &mut SoundBuffer,
603 amount: usize,
604 step: f64,
605 ) -> usize {
606 let mut rendered = 0;
607
608 while self.buf_read_pos < 0.0 {
609 let w = (self.buf_read_pos - self.buf_read_pos.floor()) as f32;
613 let cur_first_sample = if buffer.channel_count == 2 {
614 (buffer.samples[0], buffer.samples[1])
615 } else {
616 (buffer.samples[0], buffer.samples[0])
617 };
618 let l = self.prev_buffer_sample.0 * (1.0 - w) + cur_first_sample.0 * w;
619 let r = self.prev_buffer_sample.1 * (1.0 - w) + cur_first_sample.1 * w;
620 self.frame_samples.push((l, r));
621 self.buf_read_pos += step;
622 self.playback_pos += step;
623 rendered += 1;
624 }
625
626 let buffer_base_idx = self.buf_read_pos as usize;
630 let mut buffer_rel_pos = (self.buf_read_pos - buffer_base_idx as f64) as f32;
631 let start_buffer_rel_pos = buffer_rel_pos;
632 let rel_step = step as f32;
633 let buffer_last = buffer.samples.len() / buffer.channel_count - 1;
636 if buffer.channel_count == 2 {
637 while rendered < amount {
638 let (idx, w) = {
639 let idx = buffer_rel_pos as usize;
640 (idx + buffer_base_idx, buffer_rel_pos - idx as f32)
643 };
644 if idx >= buffer_last {
645 break;
646 }
647 let l = buffer.samples[idx * 2] * (1.0 - w) + buffer.samples[idx * 2 + 2] * w;
648 let r = buffer.samples[idx * 2 + 1] * (1.0 - w) + buffer.samples[idx * 2 + 3] * w;
649 self.frame_samples.push((l, r));
650 buffer_rel_pos += rel_step;
651 rendered += 1;
652 }
653 } else {
654 while rendered < amount {
655 let (idx, w) = {
656 let idx = buffer_rel_pos as usize;
657 (idx + buffer_base_idx, buffer_rel_pos - idx as f32)
659 };
660 if idx >= buffer_last {
661 break;
662 }
663 let v = buffer.samples[idx] * (1.0 - w) + buffer.samples[idx + 1] * w;
664 self.frame_samples.push((v, v));
665 buffer_rel_pos += rel_step;
666 rendered += 1;
667 }
668 }
669
670 self.buf_read_pos += (buffer_rel_pos - start_buffer_rel_pos) as f64;
671 self.playback_pos += (buffer_rel_pos - start_buffer_rel_pos) as f64;
672 rendered
673 }
674
675 pub(crate) fn frame_samples(&self) -> &[(f32, f32)] {
676 &self.frame_samples
677 }
678}
679
680fn get_last_sample(buffer: &StreamingBuffer) -> (f32, f32) {
681 let len = buffer.samples.len();
682 if len == 0 {
683 return (0.0, 0.0);
684 }
685 if buffer.channel_count == 2 {
686 (buffer.samples[len - 2], buffer.samples[len - 1])
687 } else {
688 (buffer.samples[len - 1], buffer.samples[len - 1])
689 }
690}
691
692impl Drop for SoundSource {
693 fn drop(&mut self) {
694 if let Some(buffer) = self.buffer.as_ref() {
695 if let Some(SoundBuffer::Streaming(streaming)) = buffer.state().data() {
696 streaming.use_count = streaming.use_count.saturating_sub(1);
697 }
698 }
699 }
700}
701
702pub struct SoundSourceBuilder {
724 buffer: Option<SoundBufferResource>,
725 gain: f32,
726 pitch: f64,
727 name: String,
728 panning: f32,
729 looping: bool,
730 status: Status,
731 play_once: bool,
732 playback_time: Duration,
733 radius: f32,
734 position: Vector3<f32>,
735 max_distance: f32,
736 rolloff_factor: f32,
737 spatial_blend: f32,
738 bus: String,
739}
740
741impl Default for SoundSourceBuilder {
742 fn default() -> Self {
743 Self::new()
744 }
745}
746
747impl SoundSourceBuilder {
748 pub fn new() -> Self {
750 Self {
751 buffer: None,
752 gain: 1.0,
753 pitch: 1.0,
754 name: Default::default(),
755 panning: 0.0,
756 looping: false,
757 status: Status::Stopped,
758 play_once: false,
759 playback_time: Default::default(),
760 radius: 1.0,
761 position: Vector3::new(0.0, 0.0, 0.0),
762 max_distance: f32::MAX,
763 rolloff_factor: 1.0,
764 spatial_blend: 1.0,
765 bus: AudioBusGraph::PRIMARY_BUS.to_string(),
766 }
767 }
768
769 pub fn with_buffer(mut self, buffer: SoundBufferResource) -> Self {
771 self.buffer = Some(buffer);
772 self
773 }
774
775 pub fn with_opt_buffer(mut self, buffer: Option<SoundBufferResource>) -> Self {
777 self.buffer = buffer;
778 self
779 }
780
781 pub fn with_gain(mut self, gain: f32) -> Self {
783 self.gain = gain;
784 self
785 }
786
787 pub fn with_spatial_blend_factor(mut self, k: f32) -> Self {
789 self.spatial_blend = k.clamp(0.0, 1.0);
790 self
791 }
792
793 pub fn with_pitch(mut self, pitch: f64) -> Self {
795 self.pitch = pitch;
796 self
797 }
798
799 pub fn with_panning(mut self, panning: f32) -> Self {
801 self.panning = panning;
802 self
803 }
804
805 pub fn with_looping(mut self, looping: bool) -> Self {
807 self.looping = looping;
808 self
809 }
810
811 pub fn with_status(mut self, status: Status) -> Self {
813 self.status = status;
814 self
815 }
816
817 pub fn with_play_once(mut self, play_once: bool) -> Self {
819 self.play_once = play_once;
820 self
821 }
822
823 pub fn with_name<N: AsRef<str>>(mut self, name: N) -> Self {
825 name.as_ref().clone_into(&mut self.name);
826 self
827 }
828
829 pub fn with_playback_time(mut self, time: Duration) -> Self {
831 self.playback_time = time;
832 self
833 }
834
835 pub fn with_position(mut self, position: Vector3<f32>) -> Self {
837 self.position = position;
838 self
839 }
840
841 pub fn with_radius(mut self, radius: f32) -> Self {
843 self.radius = radius;
844 self
845 }
846
847 pub fn with_max_distance(mut self, max_distance: f32) -> Self {
849 self.max_distance = max_distance;
850 self
851 }
852
853 pub fn with_rolloff_factor(mut self, rolloff_factor: f32) -> Self {
855 self.rolloff_factor = rolloff_factor;
856 self
857 }
858
859 pub fn with_bus<S: AsRef<str>>(mut self, bus: S) -> Self {
861 self.bus = bus.as_ref().to_string();
862 self
863 }
864
865 pub fn build(self) -> Result<SoundSource, SoundError> {
867 let mut source = SoundSource {
868 buffer: self.buffer.clone(),
869 gain: self.gain,
870 pitch: self.pitch,
871 play_once: self.play_once,
872 panning: self.panning,
873 status: self.status,
874 looping: self.looping,
875 name: self.name,
876 frame_samples: Default::default(),
877 radius: self.radius,
878 position: self.position,
879 max_distance: self.max_distance,
880 rolloff_factor: self.rolloff_factor,
881 spatial_blend: self.spatial_blend,
882 prev_left_samples: Default::default(),
883 prev_right_samples: Default::default(),
884 bus: self.bus,
885 ..Default::default()
886 };
887
888 source.set_buffer(self.buffer)?;
889 source.set_playback_time(self.playback_time);
890
891 Ok(source)
892 }
893}