1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
//! Generic buffer module.
//!
//! # Overview
//!
//! Generic buffer is just an array of raw samples in IEEE float format with some additional info (sample rate,
//! channel count, etc.). All samples stored in interleaved format, which means samples for each channel are
//! near - `LRLRLR...`.
//!
//! # Usage
//!
//! Generic source can be created like so:
//!
//! ```no_run
//! use std::sync::{Mutex, Arc};
//! use fyrox_sound::buffer::{SoundBufferResource, DataSource, SoundBufferResourceExtension};
//!
//! async fn make_buffer() -> SoundBufferResource {
//! let data_source = DataSource::from_file("sound.wav").await.unwrap();
//! SoundBufferResource::new_generic(data_source).unwrap()
//! }
//! ```
#![allow(clippy::manual_range_contains)]
use crate::{buffer::DataSource, decoder::Decoder};
use fyrox_core::{reflect::prelude::*, visitor::prelude::*};
use std::{path::Path, path::PathBuf, time::Duration};
/// Generic sound buffer that contains decoded samples and allows random access.
#[derive(Debug, Default, Visit, Reflect)]
pub struct GenericBuffer {
/// Interleaved decoded samples (mono sounds: L..., stereo sounds: LR...)
/// For streaming buffers it contains only small part of decoded data
/// (usually something around 1 sec).
#[visit(skip)]
pub(crate) samples: Vec<f32>,
#[visit(skip)]
pub(crate) channel_count: usize,
#[visit(skip)]
pub(crate) sample_rate: usize,
#[visit(rename = "Path")]
pub(crate) external_source_path: PathBuf,
}
impl GenericBuffer {
/// Creates new generic buffer from specified data source. May fail if data source has unsupported
/// format, corrupted, etc.
///
/// # Notes
///
/// `DataSource::RawStreaming` is **not** supported with generic buffers, use streaming buffer
/// instead!
///
/// Data source with raw samples must have sample count multiple of channel count, otherwise this
/// function will return `Err`.
pub fn new(source: DataSource) -> Result<Self, DataSource> {
match source {
DataSource::Raw {
sample_rate,
channel_count,
samples,
} => {
if channel_count < 1 || channel_count > 2 || samples.len() % channel_count != 0 {
Err(DataSource::Raw {
sample_rate,
channel_count,
samples,
})
} else {
Ok(Self {
samples,
channel_count,
sample_rate,
external_source_path: Default::default(),
})
}
}
DataSource::RawStreaming(_) => Err(source),
_ => {
let external_source_path = if let DataSource::File { path, .. } = &source {
path.clone()
} else {
Default::default()
};
// Store cursor to handle errors.
let (is_memory, external_cursor) = if let DataSource::Memory(cursor) = &source {
(true, cursor.clone())
} else {
(false, Default::default())
};
let decoder = Decoder::new(source)?;
if decoder.get_channel_count() < 1 || decoder.get_channel_count() > 2 {
if is_memory {
return Err(DataSource::Memory(external_cursor));
} else {
// There is not much we can do here: if the user supplied DataSource::File,
// they probably do not want us to re-read the file again in
// DataSource::from_file.
return Err(DataSource::Raw {
sample_rate: decoder.get_sample_rate(),
channel_count: decoder.get_channel_count(),
samples: vec![],
});
}
}
Ok(Self {
sample_rate: decoder.get_sample_rate(),
channel_count: decoder.get_channel_count(),
samples: decoder.into_samples(),
external_source_path,
})
}
}
}
/// In case if buffer was created from file, this method returns file name. Can be useful for
/// serialization needs where you just need to know which file needs to be reloaded from disk
/// when you loading a saved game.
#[inline]
pub fn external_data_path(&self) -> &Path {
&self.external_source_path
}
/// Sets new path for external data source.
pub fn set_external_data_path(&mut self, path: PathBuf) -> PathBuf {
std::mem::replace(&mut self.external_source_path, path)
}
/// Checks if buffer is empty or not.
#[inline]
pub fn is_empty(&self) -> bool {
self.samples.is_empty()
}
/// Returns shared reference to an array with samples.
#[inline]
pub fn samples(&self) -> &[f32] {
&self.samples
}
/// Returns mutable reference to an array with samples that could be modified.
pub fn samples_mut(&mut self) -> &mut [f32] {
&mut self.samples
}
/// Returns exact amount of channels in the buffer.
#[inline]
pub fn channel_count(&self) -> usize {
self.channel_count
}
/// Returns sample rate of the buffer.
#[inline]
pub fn sample_rate(&self) -> usize {
self.sample_rate
}
/// Returns exact duration of the buffer.
#[inline]
pub fn duration(&self) -> Duration {
Duration::from_secs_f64(
(self.samples.len() / (self.channel_count * self.sample_rate)) as f64,
)
}
}