fyrox_sound/buffer/streaming.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//! Streaming buffer.
22//!
23//! # Overview
24//!
25//! Streaming buffers are used for long sounds (usually longer than 15 seconds) to reduce memory usage.
26//! Some sounds in games are very long - music, ambient sounds, voice, etc. and it is too inefficient
27//! to load and decode them directly into memory all at once - it will just take enormous amount of memory
28//! that could be used to something more useful.
29//!
30//! # Usage
31//!
32//! There are almost no difference with generic buffers:
33//!
34//! ```no_run
35//! use std::sync::{Mutex, Arc};
36//! use fyrox_sound::buffer::{SoundBufferResource, DataSource, SoundBufferResourceExtension};
37//! use fyrox_resource::io::FsResourceIo;
38//!
39//! async fn make_streaming_buffer() -> SoundBufferResource {
40//! let data_source = DataSource::from_file("some_long_sound.ogg", &FsResourceIo).await.unwrap();
41//! SoundBufferResource::new_streaming(data_source).unwrap()
42//! }
43//! ```
44//!
45//! # Notes
46//!
47//! Streaming buffer cannot be shared across multiple source. On attempt to create a source with a streaming
48//! buffer that already in use you'll get error.
49
50use crate::buffer::generic::Samples;
51use crate::{
52 buffer::{generic::GenericBuffer, DataSource, RawStreamingDataSource},
53 decoder::Decoder,
54 error::SoundError,
55};
56use fyrox_core::{reflect::prelude::*, visitor::prelude::*};
57use std::{
58 ops::{Deref, DerefMut},
59 time::Duration,
60};
61
62/// Streaming buffer for long sounds. Does not support random access.
63#[derive(Debug, Default, Visit, Reflect)]
64#[reflect(non_cloneable)]
65pub struct StreamingBuffer {
66 pub(crate) generic: GenericBuffer,
67 /// Count of sources that share this buffer, it is important to keep only one
68 /// user of streaming buffer, because streaming buffer does not allow random
69 /// access.
70 #[visit(skip)]
71 pub(crate) use_count: usize,
72 #[visit(skip)]
73 #[reflect(hidden)]
74 streaming_source: StreamingSource,
75}
76
77#[derive(Debug)]
78enum StreamingSource {
79 Null,
80 Decoder(Decoder),
81 Raw(Box<dyn RawStreamingDataSource>),
82}
83
84impl Default for StreamingSource {
85 fn default() -> Self {
86 Self::Null
87 }
88}
89
90impl StreamingSource {
91 #[inline]
92 fn new(data_source: DataSource) -> Result<Self, SoundError> {
93 match data_source {
94 DataSource::File { .. } | DataSource::Memory(_) => {
95 Ok(Self::Decoder(Decoder::new(data_source)?))
96 }
97 DataSource::RawStreaming(raw) => Ok(Self::Raw(raw)),
98 // It makes no sense to stream raw data which is already loaded into memory.
99 _ => Err(SoundError::UnsupportedFormat),
100 }
101 }
102
103 #[inline]
104 fn sample_rate(&self) -> usize {
105 match self {
106 StreamingSource::Decoder(decoder) => decoder.get_sample_rate(),
107 StreamingSource::Raw(raw) => raw.sample_rate(),
108 StreamingSource::Null => 0,
109 }
110 }
111
112 #[inline]
113 fn channel_count(&self) -> usize {
114 match self {
115 StreamingSource::Decoder(decoder) => decoder.get_channel_count(),
116 StreamingSource::Raw(raw) => raw.channel_count(),
117 StreamingSource::Null => 0,
118 }
119 }
120
121 fn channel_duration_in_samples(&self) -> usize {
122 match self {
123 StreamingSource::Null => 0,
124 StreamingSource::Decoder(decoder) => decoder.channel_duration_in_samples(),
125 StreamingSource::Raw(raw) => raw.channel_duration_in_samples(),
126 }
127 }
128
129 fn rewind(&mut self) -> Result<(), SoundError> {
130 match self {
131 StreamingSource::Null => Ok(()),
132 StreamingSource::Decoder(decoder) => decoder.rewind(),
133 StreamingSource::Raw(raw) => raw.rewind(),
134 }
135 }
136
137 fn time_seek(&mut self, location: Duration) -> Result<(), SoundError> {
138 match self {
139 StreamingSource::Null => Ok(()),
140 StreamingSource::Decoder(decoder) => decoder.time_seek(location),
141 StreamingSource::Raw(raw) => raw.time_seek(location),
142 }
143 }
144
145 #[inline]
146 fn read_next_samples_block_into(&mut self, buffer: &mut Vec<f32>) -> usize {
147 buffer.clear();
148 let count = StreamingBuffer::STREAM_SAMPLE_COUNT * self.channel_count();
149 match self {
150 StreamingSource::Decoder(decoder) => {
151 for _ in 0..count {
152 if let Some(sample) = decoder.next() {
153 buffer.push(sample)
154 } else {
155 break;
156 }
157 }
158 }
159 StreamingSource::Raw(raw_streaming) => {
160 for _ in 0..count {
161 if let Some(sample) = raw_streaming.next() {
162 buffer.push(sample)
163 } else {
164 break;
165 }
166 }
167 }
168 StreamingSource::Null => (),
169 }
170
171 buffer.len()
172 }
173}
174
175impl StreamingBuffer {
176 /// Defines amount of samples `per channel` which each streaming buffer will use for internal buffer.
177 pub const STREAM_SAMPLE_COUNT: usize = 44100;
178
179 /// Creates new streaming buffer using given data source. May fail if data source has unsupported format
180 /// or it has corrupted data. Length of internal generic buffer cannot be changed but can be fetched from
181 /// `StreamingBuffer::STREAM_SAMPLE_COUNT`
182 ///
183 /// # Notes
184 ///
185 /// This function will return Err if data source is `Raw`. It makes no sense to stream raw data which
186 /// is already loaded into memory. Use Generic source instead!
187 pub fn new(source: DataSource) -> Result<Self, SoundError> {
188 let mut streaming_source = StreamingSource::new(source)?;
189
190 let mut samples = Vec::new();
191 let channel_count = streaming_source.channel_count();
192 streaming_source.read_next_samples_block_into(&mut samples);
193 debug_assert_eq!(samples.len() % channel_count, 0);
194
195 Ok(Self {
196 generic: GenericBuffer {
197 samples: Samples(samples),
198 sample_rate: streaming_source.sample_rate(),
199 channel_count: streaming_source.channel_count(),
200 channel_duration_in_samples: streaming_source.channel_duration_in_samples(),
201 },
202 use_count: 0,
203 streaming_source,
204 })
205 }
206
207 #[inline]
208 pub(crate) fn read_next_block(&mut self) {
209 self.streaming_source
210 .read_next_samples_block_into(&mut self.generic.samples);
211 }
212
213 #[inline]
214 pub(crate) fn rewind(&mut self) -> Result<(), SoundError> {
215 self.streaming_source.rewind()
216 }
217
218 #[inline]
219 pub(crate) fn time_seek(&mut self, location: Duration) -> Result<(), SoundError> {
220 self.streaming_source.time_seek(location)
221 }
222}
223
224impl Deref for StreamingBuffer {
225 type Target = GenericBuffer;
226
227 /// Returns shared reference to internal generic buffer. Can be useful to get some info (sample rate,
228 /// channel count).
229 fn deref(&self) -> &Self::Target {
230 &self.generic
231 }
232}
233
234impl DerefMut for StreamingBuffer {
235 /// Returns mutable reference to internal generic buffer. Can be used to modify it.
236 fn deref_mut(&mut self) -> &mut Self::Target {
237 &mut self.generic
238 }
239}