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
51/// Samples container.
52#[derive(Debug, Default, Visit, Reflect)]
53pub struct Samples(pub Vec<f32>);
54
55impl Deref for Samples {
56 type Target = Vec<f32>;
57
58 fn deref(&self) -> &Self::Target {
59 &self.0
60 }
61}
62
63impl DerefMut for Samples {
64 fn deref_mut(&mut self) -> &mut Self::Target {
65 &mut self.0
66 }
67}
68
69/// Generic sound buffer that contains decoded samples and allows random access.
70#[derive(Debug, Default, Visit, Reflect)]
71pub struct GenericBuffer {
72 /// Interleaved decoded samples (mono sounds: L..., stereo sounds: LR...)
73 /// For streaming buffers it contains only small part of decoded data
74 /// (usually something around 1 sec).
75 #[visit(skip)]
76 pub(crate) samples: Samples,
77 #[visit(skip)]
78 pub(crate) channel_count: usize,
79 #[visit(skip)]
80 pub(crate) sample_rate: usize,
81 #[visit(skip)]
82 pub(crate) channel_duration_in_samples: usize,
83}
84
85impl GenericBuffer {
86 /// Creates new generic buffer from specified data source. May fail if data source has unsupported
87 /// format, corrupted, etc.
88 ///
89 /// # Notes
90 ///
91 /// `DataSource::RawStreaming` is **not** supported with generic buffers, use streaming buffer
92 /// instead!
93 ///
94 /// Data source with raw samples must have sample count multiple of channel count, otherwise this
95 /// function will return `Err`.
96 pub fn new(source: DataSource) -> Result<Self, DataSource> {
97 match source {
98 DataSource::Raw {
99 sample_rate,
100 channel_count,
101 samples,
102 } => {
103 if channel_count < 1 || channel_count > 2 || samples.len() % channel_count != 0 {
104 Err(DataSource::Raw {
105 sample_rate,
106 channel_count,
107 samples,
108 })
109 } else {
110 Ok(Self {
111 channel_duration_in_samples: samples.len() / channel_count,
112 samples: Samples(samples),
113 channel_count,
114 sample_rate,
115 })
116 }
117 }
118 DataSource::RawStreaming(_) => Err(source),
119 _ => {
120 // Store cursor to handle errors.
121 let (is_memory, external_cursor) = if let DataSource::Memory(cursor) = &source {
122 (true, cursor.clone())
123 } else {
124 (false, Default::default())
125 };
126
127 let decoder = Decoder::new(source)?;
128 if decoder.get_channel_count() < 1 || decoder.get_channel_count() > 2 {
129 if is_memory {
130 return Err(DataSource::Memory(external_cursor));
131 } else {
132 // There is not much we can do here: if the user supplied DataSource::File,
133 // they probably do not want us to re-read the file again in
134 // DataSource::from_file.
135 return Err(DataSource::Raw {
136 sample_rate: decoder.get_sample_rate(),
137 channel_count: decoder.get_channel_count(),
138 samples: vec![],
139 });
140 }
141 }
142
143 Ok(Self {
144 sample_rate: decoder.get_sample_rate(),
145 channel_count: decoder.get_channel_count(),
146 channel_duration_in_samples: decoder.channel_duration_in_samples(),
147 samples: Samples(decoder.into_samples()),
148 })
149 }
150 }
151 }
152
153 /// Checks if buffer is empty or not.
154 #[inline]
155 pub fn is_empty(&self) -> bool {
156 self.samples.is_empty()
157 }
158
159 /// Returns shared reference to an array with samples.
160 #[inline]
161 pub fn samples(&self) -> &[f32] {
162 &self.samples
163 }
164
165 /// Returns mutable reference to an array with samples that could be modified.
166 pub fn samples_mut(&mut self) -> &mut [f32] {
167 &mut self.samples
168 }
169
170 /// Returns exact amount of channels in the buffer.
171 #[inline]
172 pub fn channel_count(&self) -> usize {
173 self.channel_count
174 }
175
176 /// Returns sample rate of the buffer.
177 #[inline]
178 pub fn sample_rate(&self) -> usize {
179 self.sample_rate
180 }
181
182 /// Returns exact time length of the buffer.
183 #[inline]
184 pub fn duration(&self) -> Duration {
185 Duration::from_nanos(
186 (self.channel_duration_in_samples as u64 * 1_000_000_000u64) / self.sample_rate as u64,
187 )
188 }
189
190 /// Returns exact duration of each channel (in samples) of the buffer. The returned value represents the entire length
191 /// of each channel in the buffer, even if it is streaming and its content is not yet fully decoded.
192 #[inline]
193 pub fn channel_duration_in_samples(&self) -> usize {
194 self.channel_duration_in_samples
195 }
196}