1use core::{num::NonZeroUsize, ops::Range};
2
3pub trait SampleResource: Send + Sync + 'static {
5 fn num_channels(&self) -> NonZeroUsize;
7
8 fn len_frames(&self) -> u64;
12
13 fn fill_buffers(
25 &self,
26 buffers: &mut [&mut [f32]],
27 buffer_range: Range<usize>,
28 start_frame: u64,
29 );
30}
31
32pub struct InterleavedResourceI16 {
33 pub data: Vec<i16>,
34 pub channels: NonZeroUsize,
35}
36
37impl SampleResource for InterleavedResourceI16 {
38 fn num_channels(&self) -> NonZeroUsize {
39 self.channels
40 }
41
42 fn len_frames(&self) -> u64 {
43 (self.data.len() / self.channels.get()) as u64
44 }
45
46 fn fill_buffers(
47 &self,
48 buffers: &mut [&mut [f32]],
49 buffer_range: Range<usize>,
50 start_frame: u64,
51 ) {
52 fill_buffers_interleaved(
53 buffers,
54 buffer_range,
55 start_frame as usize,
56 self.channels,
57 &self.data,
58 pcm_i16_to_f32,
59 );
60 }
61}
62
63pub struct InterleavedResourceU16 {
64 pub data: Vec<u16>,
65 pub channels: NonZeroUsize,
66}
67
68impl SampleResource for InterleavedResourceU16 {
69 fn num_channels(&self) -> NonZeroUsize {
70 self.channels
71 }
72
73 fn len_frames(&self) -> u64 {
74 (self.data.len() / self.channels.get()) as u64
75 }
76
77 fn fill_buffers(
78 &self,
79 buffers: &mut [&mut [f32]],
80 buffer_range: Range<usize>,
81 start_frame: u64,
82 ) {
83 fill_buffers_interleaved(
84 buffers,
85 buffer_range,
86 start_frame as usize,
87 self.channels,
88 &self.data,
89 pcm_u16_to_f32,
90 );
91 }
92}
93
94pub struct InterleavedResourceF32 {
95 pub data: Vec<f32>,
96 pub channels: NonZeroUsize,
97}
98
99impl SampleResource for InterleavedResourceF32 {
100 fn num_channels(&self) -> NonZeroUsize {
101 self.channels
102 }
103
104 fn len_frames(&self) -> u64 {
105 (self.data.len() / self.channels.get()) as u64
106 }
107
108 fn fill_buffers(
109 &self,
110 buffers: &mut [&mut [f32]],
111 buffer_range: Range<usize>,
112 start_frame: u64,
113 ) {
114 fill_buffers_interleaved(
115 buffers,
116 buffer_range,
117 start_frame as usize,
118 self.channels,
119 &self.data,
120 |s| s,
121 );
122 }
123}
124
125impl SampleResource for Vec<Vec<i16>> {
126 fn num_channels(&self) -> NonZeroUsize {
127 NonZeroUsize::new(self.len()).unwrap()
128 }
129
130 fn len_frames(&self) -> u64 {
131 self[0].len() as u64
132 }
133
134 fn fill_buffers(
135 &self,
136 buffers: &mut [&mut [f32]],
137 buffer_range: Range<usize>,
138 start_frame: u64,
139 ) {
140 fill_buffers_deinterleaved(
141 buffers,
142 buffer_range,
143 start_frame as usize,
144 self.as_slice(),
145 pcm_i16_to_f32,
146 );
147 }
148}
149
150impl SampleResource for Vec<Vec<u16>> {
151 fn num_channels(&self) -> NonZeroUsize {
152 NonZeroUsize::new(self.len()).unwrap()
153 }
154
155 fn len_frames(&self) -> u64 {
156 self[0].len() as u64
157 }
158
159 fn fill_buffers(
160 &self,
161 buffers: &mut [&mut [f32]],
162 buffer_range: Range<usize>,
163 start_frame: u64,
164 ) {
165 fill_buffers_deinterleaved(
166 buffers,
167 buffer_range,
168 start_frame as usize,
169 self.as_slice(),
170 pcm_u16_to_f32,
171 );
172 }
173}
174
175impl SampleResource for Vec<Vec<f32>> {
176 fn num_channels(&self) -> NonZeroUsize {
177 NonZeroUsize::new(self.len()).unwrap()
178 }
179
180 fn len_frames(&self) -> u64 {
181 self[0].len() as u64
182 }
183
184 fn fill_buffers(
185 &self,
186 buffers: &mut [&mut [f32]],
187 buffer_range: Range<usize>,
188 start_frame: u64,
189 ) {
190 fill_buffers_deinterleaved_f32(buffers, buffer_range, start_frame as usize, self);
191 }
192}
193
194#[inline]
195pub fn pcm_i16_to_f32(s: i16) -> f32 {
196 f32::from(s) * (1.0 / core::i16::MAX as f32)
197}
198
199#[inline]
200pub fn pcm_u16_to_f32(s: u16) -> f32 {
201 ((f32::from(s)) * (2.0 / core::u16::MAX as f32)) - 1.0
202}
203
204pub fn fill_buffers_interleaved<T: Clone + Copy>(
206 buffers: &mut [&mut [f32]],
207 buffer_range: Range<usize>,
208 start_frame: usize,
209 channels: NonZeroUsize,
210 data: &[T],
211 convert: impl Fn(T) -> f32,
212) {
213 let start_frame = start_frame as usize;
214 let channels = channels.get();
215
216 let frames = buffer_range.end - buffer_range.start;
217
218 if channels == 1 {
219 for (buf_s, &src_s) in buffers[0][buffer_range.clone()]
221 .iter_mut()
222 .zip(&data[start_frame..start_frame + frames])
223 {
224 *buf_s = convert(src_s);
225 }
226 return;
227 }
228
229 if channels == 2 && buffers.len() >= 2 {
230 let (buf0, buf1) = buffers.split_first_mut().unwrap();
232 let buf0 = &mut buf0[buffer_range.clone()];
233 let buf1 = &mut buf1[0][buffer_range.clone()];
234
235 let src_slice = &data[start_frame * 2..(start_frame + frames) * 2];
236
237 for (src_chunk, (buf0_s, buf1_s)) in src_slice
238 .chunks_exact(2)
239 .zip(buf0.iter_mut().zip(buf1.iter_mut()))
240 {
241 *buf0_s = convert(src_chunk[0]);
242 *buf1_s = convert(src_chunk[1]);
243 }
244
245 return;
246 }
247
248 let src_slice = &data[start_frame * channels..(start_frame + frames) * channels];
249 for (ch_i, buf_ch) in (0..channels).zip(buffers.iter_mut()) {
250 for (src_chunk, buf_s) in src_slice
251 .chunks_exact(channels)
252 .zip(buf_ch[buffer_range.clone()].iter_mut())
253 {
254 *buf_s = convert(src_chunk[ch_i]);
255 }
256 }
257}
258
259pub fn fill_buffers_deinterleaved<T: Clone + Copy, V: AsRef<[T]>>(
261 buffers: &mut [&mut [f32]],
262 buffer_range: Range<usize>,
263 start_frame: usize,
264 data: &[V],
265 convert: impl Fn(T) -> f32,
266) {
267 let start_frame = start_frame as usize;
268 let frames = buffer_range.end - buffer_range.start;
269
270 if data.len() == 2 && buffers.len() >= 2 {
271 let (buf0, buf1) = buffers.split_first_mut().unwrap();
273 let buf0 = &mut buf0[buffer_range.clone()];
274 let buf1 = &mut buf1[0][buffer_range.clone()];
275 let s0 = &data[0].as_ref()[start_frame..start_frame + frames];
276 let s1 = &data[1].as_ref()[start_frame..start_frame + frames];
277
278 for i in 0..frames {
279 buf0[i] = convert(s0[i]);
280 buf1[i] = convert(s1[i]);
281 }
282
283 return;
284 }
285
286 for (buf, ch) in buffers.iter_mut().zip(data.iter()) {
287 for (buf_s, &ch_s) in buf[buffer_range.clone()]
288 .iter_mut()
289 .zip(ch.as_ref()[start_frame..start_frame + frames].iter())
290 {
291 *buf_s = convert(ch_s);
292 }
293 }
294}
295
296pub fn fill_buffers_deinterleaved_f32<V: AsRef<[f32]>>(
298 buffers: &mut [&mut [f32]],
299 buffer_range: Range<usize>,
300 start_frame: usize,
301 data: &[V],
302) {
303 let start_frame = start_frame as usize;
304
305 for (buf, ch) in buffers.iter_mut().zip(data.iter()) {
306 buf[buffer_range.clone()].copy_from_slice(
307 &ch.as_ref()[start_frame..start_frame + buffer_range.end - buffer_range.start],
308 );
309 }
310}
311
312#[cfg(feature = "symphonium")]
313pub struct DecodedAudio(pub symphonium::DecodedAudio);
316
317#[cfg(feature = "symphonium")]
318impl DecodedAudio {
319 pub fn duration_seconds(&self) -> f64 {
320 self.0.frames() as f64 / self.0.sample_rate() as f64
321 }
322
323 pub fn into_dyn_resource(self) -> crate::collector::ArcGc<dyn SampleResource> {
324 crate::collector::ArcGc::new_unsized(|| {
325 bevy_platform::sync::Arc::new(self) as bevy_platform::sync::Arc<dyn SampleResource>
326 })
327 }
328}
329
330#[cfg(feature = "symphonium")]
331impl Into<crate::collector::ArcGc<dyn SampleResource>> for DecodedAudio {
332 fn into(self) -> crate::collector::ArcGc<dyn SampleResource> {
333 self.into_dyn_resource()
334 }
335}
336
337#[cfg(feature = "symphonium")]
338impl SampleResource for DecodedAudio {
339 fn num_channels(&self) -> NonZeroUsize {
340 NonZeroUsize::new(self.0.channels()).unwrap()
341 }
342
343 fn len_frames(&self) -> u64 {
344 self.0.frames() as u64
345 }
346
347 fn fill_buffers(
348 &self,
349 buffers: &mut [&mut [f32]],
350 buffer_range: Range<usize>,
351 start_frame: u64,
352 ) {
353 let channels = self.0.channels().min(buffers.len());
354
355 if channels == 2 {
356 let (b1, b2) = buffers.split_first_mut().unwrap();
357
358 self.0.fill_stereo(
359 start_frame as usize,
360 &mut b1[buffer_range.clone()],
361 &mut b2[0][buffer_range.clone()],
362 );
363 } else {
364 for (ch_i, b) in buffers[0..channels].iter_mut().enumerate() {
365 self.0
366 .fill_channel(ch_i, start_frame as usize, &mut b[buffer_range.clone()])
367 .unwrap();
368 }
369 }
370 }
371}
372
373#[cfg(feature = "symphonium")]
374impl From<symphonium::DecodedAudio> for DecodedAudio {
375 fn from(data: symphonium::DecodedAudio) -> Self {
376 Self(data)
377 }
378}
379
380#[cfg(feature = "symphonium")]
381pub struct DecodedAudioF32(pub symphonium::DecodedAudioF32);
384
385#[cfg(feature = "symphonium")]
386impl DecodedAudioF32 {
387 pub fn duration_seconds(&self, sample_rate: u32) -> f64 {
388 self.0.frames() as f64 / sample_rate as f64
389 }
390}
391
392#[cfg(feature = "symphonium")]
393impl SampleResource for DecodedAudioF32 {
394 fn num_channels(&self) -> NonZeroUsize {
395 NonZeroUsize::new(self.0.channels()).unwrap()
396 }
397
398 fn len_frames(&self) -> u64 {
399 self.0.frames() as u64
400 }
401
402 fn fill_buffers(
403 &self,
404 buffers: &mut [&mut [f32]],
405 buffer_range: Range<usize>,
406 start_frame: u64,
407 ) {
408 fill_buffers_deinterleaved_f32(buffers, buffer_range, start_frame as usize, &self.0.data);
409 }
410}
411
412#[cfg(feature = "symphonium")]
413impl From<symphonium::DecodedAudioF32> for DecodedAudioF32 {
414 fn from(data: symphonium::DecodedAudioF32) -> Self {
415 Self(data)
416 }
417}
418
419#[cfg(feature = "symphonium")]
426pub fn load_audio_file<P: AsRef<std::path::Path>>(
427 loader: &mut symphonium::SymphoniumLoader,
428 path: P,
429 #[cfg(feature = "resampler")] sample_rate: core::num::NonZeroU32,
430 #[cfg(feature = "resampler")] resample_quality: symphonium::ResampleQuality,
431) -> Result<DecodedAudio, symphonium::error::LoadError> {
432 loader
433 .load(
434 path,
435 #[cfg(feature = "resampler")]
436 Some(sample_rate.get()),
437 #[cfg(feature = "resampler")]
438 resample_quality,
439 None,
440 )
441 .map(|d| DecodedAudio(d))
442}
443
444#[cfg(feature = "symphonium")]
454pub fn load_audio_file_from_source(
455 loader: &mut symphonium::SymphoniumLoader,
456 source: Box<dyn symphonium::symphonia::core::io::MediaSource>,
457 hint: Option<symphonium::symphonia::core::probe::Hint>,
458 #[cfg(feature = "resampler")] sample_rate: core::num::NonZeroU32,
459 #[cfg(feature = "resampler")] resample_quality: symphonium::ResampleQuality,
460) -> Result<DecodedAudio, symphonium::error::LoadError> {
461 loader
462 .load_from_source(
463 source,
464 hint,
465 #[cfg(feature = "resampler")]
466 Some(sample_rate.get()),
467 #[cfg(feature = "resampler")]
468 resample_quality,
469 None,
470 )
471 .map(|d| DecodedAudio(d))
472}
473
474#[cfg(feature = "symphonium")]
475pub fn decoded_to_resource(
478 data: symphonium::DecodedAudio,
479) -> bevy_platform::sync::Arc<dyn SampleResource> {
480 bevy_platform::sync::Arc::new(DecodedAudio(data))
481}
482
483#[cfg(feature = "symphonium")]
484pub fn decoded_f32_to_resource(
487 data: symphonium::DecodedAudioF32,
488) -> bevy_platform::sync::Arc<dyn SampleResource> {
489 bevy_platform::sync::Arc::new(DecodedAudioF32(data))
490}