fyrox_sound/buffer/generic.rs
1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Generic buffer module.
22//!
23//! # Overview
24//!
25//! Generic buffer is just an array of raw samples in IEEE float format with some additional info (sample rate,
26//! channel count, etc.). All samples stored in interleaved format, which means samples for each channel are
27//! near - `LRLRLR...`.
28//!
29//! # Usage
30//!
31//! Generic source can be created like so:
32//!
33//! ```no_run
34//! use std::sync::{Mutex, Arc};
35//! use fyrox_sound::buffer::{SoundBufferResource, DataSource, SoundBufferResourceExtension};
36//! use fyrox_resource::io::FsResourceIo;
37//!
38//! async fn make_buffer() -> SoundBufferResource {
39//! let data_source = DataSource::from_file("sound.wav", &FsResourceIo).await.unwrap();
40//! SoundBufferResource::new_generic(data_source).unwrap()
41//! }
42//! ```
43
44#![allow(clippy::manual_range_contains)]
45
46use crate::{buffer::DataSource, decoder::Decoder};
47use fyrox_core::{reflect::prelude::*, visitor::prelude::*};
48use std::ops::{Deref, DerefMut};
49use std::time::Duration;
50
51use super::SoundBufferResourceLoadError;
52
53/// Samples container.
54#[derive(Debug, Default, Visit, Clone, Reflect)]
55pub struct Samples(pub Vec<f32>);
56
57impl Deref for Samples {
58 type Target = Vec<f32>;
59
60 fn deref(&self) -> &Self::Target {
61 &self.0
62 }
63}
64
65impl DerefMut for Samples {
66 fn deref_mut(&mut self) -> &mut Self::Target {
67 &mut self.0
68 }
69}
70
71/// Generic sound buffer that contains decoded samples and allows random access.
72#[derive(Debug, Clone, Default, Visit, Reflect)]
73pub struct GenericBuffer {
74 /// Interleaved decoded samples (mono sounds: L..., stereo sounds: LR...)
75 /// For streaming buffers it contains only small part of decoded data
76 /// (usually something around 1 sec).
77 #[visit(skip)]
78 pub(crate) samples: Samples,
79 #[visit(skip)]
80 pub(crate) channel_count: usize,
81 #[visit(skip)]
82 pub(crate) sample_rate: usize,
83 #[visit(skip)]
84 pub(crate) channel_duration_in_samples: usize,
85}
86
87impl GenericBuffer {
88 /// Creates new generic buffer from specified data source. May fail if data source has unsupported
89 /// format, corrupted, etc.
90 ///
91 /// # Notes
92 ///
93 /// `DataSource::RawStreaming` is **not** supported with generic buffers, use streaming buffer
94 /// instead!
95 ///
96 /// Data source with raw samples must have sample count multiple of channel count, otherwise this
97 /// function will return `Err`.
98 pub fn new(source: DataSource) -> Result<Self, SoundBufferResourceLoadError> {
99 match source {
100 DataSource::Raw {
101 sample_rate,
102 channel_count,
103 samples,
104 } => {
105 if channel_count < 1 || channel_count > 2 || samples.len() % channel_count != 0 {
106 Err(SoundBufferResourceLoadError::DataSourceError)
107 } else {
108 Ok(Self {
109 channel_duration_in_samples: samples.len() / channel_count,
110 samples: Samples(samples),
111 channel_count,
112 sample_rate,
113 })
114 }
115 }
116 DataSource::RawStreaming(_) => Err(SoundBufferResourceLoadError::DataSourceError),
117 _ => {
118 let decoder = Decoder::new(source)?;
119 if decoder.get_channel_count() < 1 || decoder.get_channel_count() > 2 {
120 return Err(SoundBufferResourceLoadError::DataSourceError);
121 }
122
123 Ok(Self {
124 sample_rate: decoder.get_sample_rate(),
125 channel_count: decoder.get_channel_count(),
126 channel_duration_in_samples: decoder.channel_duration_in_samples(),
127 samples: Samples(decoder.into_samples()),
128 })
129 }
130 }
131 }
132
133 /// Checks if buffer is empty or not.
134 #[inline]
135 pub fn is_empty(&self) -> bool {
136 self.samples.is_empty()
137 }
138
139 /// Returns shared reference to an array with samples.
140 #[inline]
141 pub fn samples(&self) -> &[f32] {
142 &self.samples
143 }
144
145 /// Returns mutable reference to an array with samples that could be modified.
146 pub fn samples_mut(&mut self) -> &mut [f32] {
147 &mut self.samples
148 }
149
150 /// Returns exact amount of channels in the buffer.
151 #[inline]
152 pub fn channel_count(&self) -> usize {
153 self.channel_count
154 }
155
156 /// Returns sample rate of the buffer.
157 #[inline]
158 pub fn sample_rate(&self) -> usize {
159 self.sample_rate
160 }
161
162 /// Returns exact time length of the buffer.
163 #[inline]
164 pub fn duration(&self) -> Duration {
165 if self.sample_rate == 0 {
166 return Duration::ZERO;
167 }
168 Duration::from_nanos(
169 (self.channel_duration_in_samples as u64 * 1_000_000_000u64) / self.sample_rate as u64,
170 )
171 }
172
173 /// Returns exact duration of each channel (in samples) of the buffer. The returned value represents the entire length
174 /// of each channel in the buffer, even if it is streaming and its content is not yet fully decoded.
175 #[inline]
176 pub fn channel_duration_in_samples(&self) -> usize {
177 self.channel_duration_in_samples
178 }
179}