Skip to main content

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}