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 log::Log,
61 reflect::prelude::*,
62 uuid_provider,
63 visitor::{Visit, VisitResult, Visitor},
64};
65use std::time::Duration;
66
67#[derive(Eq, PartialEq, Copy, Clone, Debug, Reflect, Visit)]
69#[repr(u32)]
70pub enum Status {
71 Stopped = 0,
74
75 Playing = 1,
77
78 Paused = 2,
81}
82
83uuid_provider!(Status = "1980bded-86cd-4eff-a5db-bab729bdb3ad");
84
85#[derive(Debug, Clone, Reflect, Visit)]
87pub struct SoundSource {
88 name: String,
89 #[reflect(hidden)]
90 buffer: Option<SoundBufferResource>,
91 #[reflect(hidden)]
96 buf_read_pos: f64,
97 #[reflect(hidden)]
99 playback_pos: f64,
100 #[reflect(min_value = 0.0, step = 0.05)]
101 panning: f32,
102 #[reflect(min_value = 0.0, step = 0.05)]
103 pitch: f64,
104 #[reflect(min_value = 0.0, step = 0.05)]
105 gain: f32,
106 looping: bool,
107 #[reflect(min_value = 0.0, max_value = 1.0, step = 0.05)]
108 spatial_blend: f32,
109 #[reflect(read_only)]
118 resampling_multiplier: f64,
119 status: Status,
120 #[visit(optional)]
121 pub(crate) bus: String,
122 play_once: bool,
123 #[reflect(hidden)]
130 #[visit(skip)]
131 pub(crate) last_left_gain: Option<f32>,
132 #[reflect(hidden)]
133 #[visit(skip)]
134 pub(crate) last_right_gain: Option<f32>,
135 #[reflect(hidden)]
136 #[visit(skip)]
137 pub(crate) frame_samples: Vec<(f32, f32)>,
138 #[reflect(hidden)]
140 #[visit(skip)]
141 prev_buffer_sample: (f32, f32),
142 #[reflect(min_value = 0.0, step = 0.05)]
143 radius: f32,
144 position: Vector3<f32>,
145 #[reflect(min_value = 0.0, step = 0.05)]
146 max_distance: f32,
147 #[reflect(min_value = 0.0, step = 0.05)]
148 rolloff_factor: f32,
149 #[reflect(hidden)]
151 #[visit(skip)]
152 pub(crate) prev_left_samples: Vec<f32>,
153 #[reflect(hidden)]
154 #[visit(skip)]
155 pub(crate) prev_right_samples: Vec<f32>,
156 #[reflect(hidden)]
157 #[visit(skip)]
158 pub(crate) prev_sampling_vector: Vector3<f32>,
159 #[reflect(hidden)]
160 #[visit(skip)]
161 pub(crate) prev_distance_gain: Option<f32>,
162}
163
164impl Default for SoundSource {
165 fn default() -> Self {
166 Self {
167 name: Default::default(),
168 buffer: None,
169 buf_read_pos: 0.0,
170 playback_pos: 0.0,
171 panning: 0.0,
172 pitch: 1.0,
173 gain: 1.0,
174 spatial_blend: 1.0,
175 looping: false,
176 resampling_multiplier: 1.0,
177 status: Status::Stopped,
178 bus: "Master".to_string(),
179 play_once: false,
180 last_left_gain: None,
181 last_right_gain: None,
182 frame_samples: Default::default(),
183 prev_buffer_sample: (0.0, 0.0),
184 radius: 1.0,
185 position: Vector3::new(0.0, 0.0, 0.0),
186 max_distance: f32::MAX,
187 rolloff_factor: 1.0,
188 prev_left_samples: Default::default(),
189 prev_right_samples: Default::default(),
190 prev_sampling_vector: Vector3::new(0.0, 0.0, 1.0),
191 prev_distance_gain: None,
192 }
193 }
194}
195
196impl SoundSource {
197 pub fn set_name<N: AsRef<str>>(&mut self, name: N) {
199 name.as_ref().clone_into(&mut self.name);
200 }
201
202 pub fn name(&self) -> &str {
204 &self.name
205 }
206
207 pub fn name_owned(&self) -> String {
209 self.name.to_owned()
210 }
211
212 pub fn set_spatial_blend(&mut self, k: f32) {
216 self.spatial_blend = k.clamp(0.0, 1.0);
217 }
218
219 pub fn spatial_blend(&self) -> f32 {
221 self.spatial_blend
222 }
223
224 pub fn set_buffer(
227 &mut self,
228 buffer: Option<SoundBufferResource>,
229 ) -> Result<Option<SoundBufferResource>, SoundError> {
230 self.buf_read_pos = 0.0;
231 self.playback_pos = 0.0;
232
233 if let Some(buffer) = self.buffer.clone() {
236 if let Some(SoundBuffer::Streaming(streaming)) = buffer.state().data() {
237 streaming.use_count = streaming.use_count.saturating_sub(1);
238 }
239 }
240
241 if let Some(buffer) = buffer.clone() {
242 match buffer.state().data() {
243 None => return Err(SoundError::BufferFailedToLoad),
244 Some(locked_buffer) => {
245 if locked_buffer.duration() == Duration::ZERO {
246 panic!("Zero duration buffer: {:?}", locked_buffer);
247 }
248 if let SoundBuffer::Streaming(ref mut streaming) = *locked_buffer {
250 if streaming.use_count != 0 {
251 return Err(SoundError::StreamingBufferAlreadyInUse);
252 }
253 streaming.use_count += 1;
254 }
255
256 let device_sample_rate = f64::from(crate::context::SAMPLE_RATE);
258 let sample_rate = locked_buffer.sample_rate() as f64;
259 self.resampling_multiplier = sample_rate / device_sample_rate;
260 }
261 }
262 }
263
264 Ok(std::mem::replace(&mut self.buffer, buffer))
265 }
266
267 pub fn buffer(&self) -> Option<SoundBufferResource> {
269 self.buffer.clone()
270 }
271
272 pub fn set_play_once(&mut self, play_once: bool) {
280 self.play_once = play_once;
281 }
282
283 pub fn is_play_once(&self) -> bool {
285 self.play_once
286 }
287
288 pub fn set_gain(&mut self, gain: f32) -> &mut Self {
296 self.gain = gain;
297 self
298 }
299
300 pub fn gain(&self) -> f32 {
302 self.gain
303 }
304
305 pub fn set_panning(&mut self, panning: f32) -> &mut Self {
308 self.panning = panning.clamp(-1.0, 1.0);
309 self
310 }
311
312 pub fn panning(&self) -> f32 {
314 self.panning
315 }
316
317 pub fn status(&self) -> Status {
319 self.status
320 }
321
322 pub fn play(&mut self) -> &mut Self {
324 self.status = Status::Playing;
325 self
326 }
327
328 pub fn pause(&mut self) -> &mut Self {
330 self.status = Status::Paused;
331 self
332 }
333
334 pub fn set_looping(&mut self, looping: bool) -> &mut Self {
337 self.looping = looping;
338 self
339 }
340
341 pub fn is_looping(&self) -> bool {
343 self.looping
344 }
345
346 pub fn set_pitch(&mut self, pitch: f64) -> &mut Self {
348 self.pitch = pitch.abs();
349 self
350 }
351
352 pub fn pitch(&self) -> f64 {
354 self.pitch
355 }
356
357 pub fn stop(&mut self) -> Result<(), SoundError> {
359 self.status = Status::Stopped;
360
361 self.buf_read_pos = 0.0;
362 self.playback_pos = 0.0;
363
364 if let Some(buffer) = self.buffer.as_ref() {
365 if let Some(SoundBuffer::Streaming(streaming)) = buffer.state().data() {
366 streaming.rewind()?;
367 }
368 }
369
370 Ok(())
371 }
372 pub fn set_position(&mut self, position: Vector3<f32>) -> &mut Self {
374 self.position = position;
375 self
376 }
377
378 pub fn position(&self) -> Vector3<f32> {
380 self.position
381 }
382
383 pub fn set_radius(&mut self, radius: f32) -> &mut Self {
385 self.radius = radius;
386 self
387 }
388
389 pub fn radius(&self) -> f32 {
391 self.radius
392 }
393
394 pub fn set_rolloff_factor(&mut self, rolloff_factor: f32) -> &mut Self {
398 self.rolloff_factor = rolloff_factor;
399 self
400 }
401
402 pub fn rolloff_factor(&self) -> f32 {
404 self.rolloff_factor
405 }
406
407 pub fn set_max_distance(&mut self, max_distance: f32) -> &mut Self {
412 self.max_distance = max_distance;
413 self
414 }
415
416 pub fn max_distance(&self) -> f32 {
418 self.max_distance
419 }
420
421 pub fn set_bus<S: AsRef<str>>(&mut self, bus: S) {
424 bus.as_ref().clone_into(&mut self.bus);
425 }
426
427 pub fn bus(&self) -> &str {
429 &self.bus
430 }
431
432 pub(crate) fn calculate_distance_gain(
436 &self,
437 listener: &Listener,
438 distance_model: DistanceModel,
439 ) -> f32 {
440 let distance = self
441 .position
442 .metric_distance(&listener.position())
443 .clamp(self.radius, self.max_distance);
444 match distance_model {
445 DistanceModel::None => 1.0,
446 DistanceModel::InverseDistance => {
447 self.radius / (self.radius + self.rolloff_factor * (distance - self.radius))
448 }
449 DistanceModel::LinearDistance => {
450 1.0 - self.radius * (distance - self.radius) / (self.max_distance - self.radius)
451 }
452 DistanceModel::ExponentDistance => (distance / self.radius).powf(-self.rolloff_factor),
453 }
454 }
455
456 pub(crate) fn calculate_panning(&self, listener: &Listener) -> f32 {
457 (listener.position() - self.position)
458 .try_normalize(f32::EPSILON)
459 .unwrap_or_else(|| listener.look_axis())
462 .dot(&listener.ear_axis())
463 }
464
465 pub(crate) fn calculate_sampling_vector(&self, listener: &Listener) -> Vector3<f32> {
466 let to_self = listener.position() - self.position;
467
468 (listener.basis() * to_self)
469 .try_normalize(f32::EPSILON)
470 .unwrap_or_else(|| Vector3::new(0.0, 0.0, 1.0))
473 }
474
475 pub fn playback_time(&self) -> Duration {
477 if let Some(buffer) = self.buffer.as_ref() {
478 if let Some(buffer) = buffer.state().data() {
479 return Duration::from_secs_f64(self.playback_pos / (buffer.sample_rate() as f64));
480 }
481 }
482
483 Duration::from_secs(0)
484 }
485
486 pub fn set_playback_time(&mut self, time: Duration) {
488 if let Some(buffer) = self.buffer.as_ref() {
489 if let Some(buffer) = buffer.state().data() {
490 if let SoundBuffer::Streaming(ref mut streaming) = *buffer {
491 if streaming
493 .time_seek(time.clamp(Duration::from_secs(0), streaming.duration()))
494 .is_err()
495 {
496 Log::warn("error while setting decoder position");
497 }
498 }
499 self.playback_pos = (time.as_secs_f64() * buffer.sample_rate as f64)
501 .clamp(0.0, buffer.duration().as_secs_f64());
502 self.buf_read_pos = match *buffer {
504 SoundBuffer::Streaming(ref mut streaming) => {
505 streaming.read_next_block();
507 self.playback_pos % (StreamingBuffer::STREAM_SAMPLE_COUNT as f64)
510 }
511 SoundBuffer::Generic(_) => self.playback_pos,
512 };
513 assert!(
514 self.buf_read_pos * (buffer.channel_count() as f64)
515 < buffer.samples().len() as f64
516 );
517 }
518 }
519 }
520
521 pub(crate) fn render(&mut self, amount: usize) {
522 if self.frame_samples.capacity() < amount {
523 self.frame_samples = Vec::with_capacity(amount);
524 }
525
526 self.frame_samples.clear();
527
528 if let Some(buffer) = self.buffer.clone() {
529 let mut state = buffer.state();
530 if let Some(buffer) = state.data() {
531 if self.status == Status::Playing && !buffer.is_empty() {
532 self.render_playing(buffer, amount);
533 }
534 }
535 }
536 self.frame_samples.resize(amount, (0.0, 0.0));
538 }
539
540 fn render_playing(&mut self, buffer: &mut SoundBuffer, amount: usize) {
541 let mut count = 0;
542 loop {
543 count += self.render_until_block_end(buffer, amount - count);
544 if count == amount {
545 break;
546 }
547
548 let channel_count = buffer.channel_count();
549 let len = buffer.samples().len();
550 let mut end_reached = true;
551 if let SoundBuffer::Streaming(streaming) = buffer {
552 if len != channel_count * StreamingBuffer::STREAM_SAMPLE_COUNT {
554 let _ = streaming.rewind();
555 } else {
556 end_reached = false;
557 }
558 self.prev_buffer_sample = get_last_sample(streaming);
559 streaming.read_next_block();
560 }
561 if end_reached {
562 self.buf_read_pos = 0.0;
563 self.playback_pos = 0.0;
564 if !self.looping {
565 self.status = Status::Stopped;
566 return;
567 }
568 } else {
569 self.buf_read_pos -= len as f64 / channel_count as f64;
570 }
571 }
572 }
573
574 fn render_until_block_end(&mut self, buffer: &mut SoundBuffer, mut amount: usize) -> usize {
577 let step = self.pitch * self.resampling_multiplier;
578 if step == 1.0 {
579 if self.buf_read_pos < 0.0 {
580 self.frame_samples.push(self.prev_buffer_sample);
582 self.buf_read_pos = 0.0;
583 amount -= 1;
584 }
585 let from = self.buf_read_pos as usize;
587 let buffer_len = buffer.samples.len() / buffer.channel_count;
588 let rendered = (buffer_len - from).min(amount);
589 if buffer.channel_count == 2 {
590 for i in from..from + rendered {
591 self.frame_samples
592 .push((buffer.samples[i * 2], buffer.samples[i * 2 + 1]))
593 }
594 } else {
595 for i in from..from + rendered {
596 self.frame_samples
597 .push((buffer.samples[i], buffer.samples[i]))
598 }
599 }
600 self.buf_read_pos += rendered as f64;
601 self.playback_pos += rendered as f64;
602 rendered
603 } else {
604 self.render_until_block_end_resample(buffer, amount, step)
605 }
606 }
607
608 fn render_until_block_end_resample(
610 &mut self,
611 buffer: &mut SoundBuffer,
612 amount: usize,
613 step: f64,
614 ) -> usize {
615 let mut rendered = 0;
616
617 while self.buf_read_pos < 0.0 {
618 let w = (self.buf_read_pos - self.buf_read_pos.floor()) as f32;
622 let cur_first_sample = if buffer.channel_count == 2 {
623 (buffer.samples[0], buffer.samples[1])
624 } else {
625 (buffer.samples[0], buffer.samples[0])
626 };
627 let l = self.prev_buffer_sample.0 * (1.0 - w) + cur_first_sample.0 * w;
628 let r = self.prev_buffer_sample.1 * (1.0 - w) + cur_first_sample.1 * w;
629 self.frame_samples.push((l, r));
630 self.buf_read_pos += step;
631 self.playback_pos += step;
632 rendered += 1;
633 }
634
635 let buffer_base_idx = self.buf_read_pos as usize;
639 let mut buffer_rel_pos = (self.buf_read_pos - buffer_base_idx as f64) as f32;
640 let start_buffer_rel_pos = buffer_rel_pos;
641 let rel_step = step as f32;
642 let buffer_last = buffer.samples.len() / buffer.channel_count - 1;
645 if buffer.channel_count == 2 {
646 while rendered < amount {
647 let (idx, w) = {
648 let idx = buffer_rel_pos as usize;
649 (idx + buffer_base_idx, buffer_rel_pos - idx as f32)
652 };
653 if idx >= buffer_last {
654 break;
655 }
656 let l = buffer.samples[idx * 2] * (1.0 - w) + buffer.samples[idx * 2 + 2] * w;
657 let r = buffer.samples[idx * 2 + 1] * (1.0 - w) + buffer.samples[idx * 2 + 3] * w;
658 self.frame_samples.push((l, r));
659 buffer_rel_pos += rel_step;
660 rendered += 1;
661 }
662 } else {
663 while rendered < amount {
664 let (idx, w) = {
665 let idx = buffer_rel_pos as usize;
666 (idx + buffer_base_idx, buffer_rel_pos - idx as f32)
668 };
669 if idx >= buffer_last {
670 break;
671 }
672 let v = buffer.samples[idx] * (1.0 - w) + buffer.samples[idx + 1] * w;
673 self.frame_samples.push((v, v));
674 buffer_rel_pos += rel_step;
675 rendered += 1;
676 }
677 }
678
679 self.buf_read_pos += (buffer_rel_pos - start_buffer_rel_pos) as f64;
680 self.playback_pos += (buffer_rel_pos - start_buffer_rel_pos) as f64;
681 rendered
682 }
683
684 pub(crate) fn frame_samples(&self) -> &[(f32, f32)] {
685 &self.frame_samples
686 }
687}
688
689fn get_last_sample(buffer: &StreamingBuffer) -> (f32, f32) {
690 let len = buffer.samples.len();
691 if len == 0 {
692 return (0.0, 0.0);
693 }
694 if buffer.channel_count == 2 {
695 (buffer.samples[len - 2], buffer.samples[len - 1])
696 } else {
697 (buffer.samples[len - 1], buffer.samples[len - 1])
698 }
699}
700
701impl Drop for SoundSource {
702 fn drop(&mut self) {
703 if let Some(buffer) = self.buffer.as_ref() {
704 if let Some(SoundBuffer::Streaming(streaming)) = buffer.state().data() {
705 streaming.use_count = streaming.use_count.saturating_sub(1);
706 }
707 }
708 }
709}
710
711pub struct SoundSourceBuilder {
733 buffer: Option<SoundBufferResource>,
734 gain: f32,
735 pitch: f64,
736 name: String,
737 panning: f32,
738 looping: bool,
739 status: Status,
740 play_once: bool,
741 playback_time: Duration,
742 radius: f32,
743 position: Vector3<f32>,
744 max_distance: f32,
745 rolloff_factor: f32,
746 spatial_blend: f32,
747 bus: String,
748}
749
750impl Default for SoundSourceBuilder {
751 fn default() -> Self {
752 Self::new()
753 }
754}
755
756impl SoundSourceBuilder {
757 pub fn new() -> Self {
759 Self {
760 buffer: None,
761 gain: 1.0,
762 pitch: 1.0,
763 name: Default::default(),
764 panning: 0.0,
765 looping: false,
766 status: Status::Stopped,
767 play_once: false,
768 playback_time: Default::default(),
769 radius: 1.0,
770 position: Vector3::new(0.0, 0.0, 0.0),
771 max_distance: f32::MAX,
772 rolloff_factor: 1.0,
773 spatial_blend: 1.0,
774 bus: AudioBusGraph::PRIMARY_BUS.to_string(),
775 }
776 }
777
778 pub fn with_buffer(mut self, buffer: SoundBufferResource) -> Self {
780 self.buffer = Some(buffer);
781 self
782 }
783
784 pub fn with_opt_buffer(mut self, buffer: Option<SoundBufferResource>) -> Self {
786 self.buffer = buffer;
787 self
788 }
789
790 pub fn with_gain(mut self, gain: f32) -> Self {
792 self.gain = gain;
793 self
794 }
795
796 pub fn with_spatial_blend_factor(mut self, k: f32) -> Self {
798 self.spatial_blend = k.clamp(0.0, 1.0);
799 self
800 }
801
802 pub fn with_pitch(mut self, pitch: f64) -> Self {
804 self.pitch = pitch;
805 self
806 }
807
808 pub fn with_panning(mut self, panning: f32) -> Self {
810 self.panning = panning;
811 self
812 }
813
814 pub fn with_looping(mut self, looping: bool) -> Self {
816 self.looping = looping;
817 self
818 }
819
820 pub fn with_status(mut self, status: Status) -> Self {
822 self.status = status;
823 self
824 }
825
826 pub fn with_play_once(mut self, play_once: bool) -> Self {
828 self.play_once = play_once;
829 self
830 }
831
832 pub fn with_name<N: AsRef<str>>(mut self, name: N) -> Self {
834 name.as_ref().clone_into(&mut self.name);
835 self
836 }
837
838 pub fn with_playback_time(mut self, time: Duration) -> Self {
840 self.playback_time = time;
841 self
842 }
843
844 pub fn with_position(mut self, position: Vector3<f32>) -> Self {
846 self.position = position;
847 self
848 }
849
850 pub fn with_radius(mut self, radius: f32) -> Self {
852 self.radius = radius;
853 self
854 }
855
856 pub fn with_max_distance(mut self, max_distance: f32) -> Self {
858 self.max_distance = max_distance;
859 self
860 }
861
862 pub fn with_rolloff_factor(mut self, rolloff_factor: f32) -> Self {
864 self.rolloff_factor = rolloff_factor;
865 self
866 }
867
868 pub fn with_bus<S: AsRef<str>>(mut self, bus: S) -> Self {
870 self.bus = bus.as_ref().to_string();
871 self
872 }
873
874 pub fn build(self) -> Result<SoundSource, SoundError> {
876 let mut source = SoundSource {
877 buffer: self.buffer.clone(),
878 gain: self.gain,
879 pitch: self.pitch,
880 play_once: self.play_once,
881 panning: self.panning,
882 status: self.status,
883 looping: self.looping,
884 name: self.name,
885 frame_samples: Default::default(),
886 radius: self.radius,
887 position: self.position,
888 max_distance: self.max_distance,
889 rolloff_factor: self.rolloff_factor,
890 spatial_blend: self.spatial_blend,
891 prev_left_samples: Default::default(),
892 prev_right_samples: Default::default(),
893 bus: self.bus,
894 ..Default::default()
895 };
896
897 source.set_buffer(self.buffer)?;
898 source.set_playback_time(self.playback_time);
899
900 Ok(source)
901 }
902}