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}