1use audioadapter::Adapter;
2use audioadapter_buffers::{
3 adapter_to_float::ConvertNumbers,
4 direct::{InterleavedSlice, SequentialSlice},
5};
6use audioadapter_sample::sample::RawSample;
7use core::{
8 num::{NonZeroU32, NonZeroUsize},
9 ops::Range,
10};
11
12#[cfg(not(feature = "std"))]
13use bevy_platform::prelude::Vec;
14
15use crate::collector::ArcGc;
16
17pub trait SampleResourceInfo {
19 fn num_channels(&self) -> NonZeroUsize;
21
22 fn len_frames(&self) -> u64;
26
27 fn sample_rate(&self) -> Option<NonZeroU32> {
31 None
32 }
33}
34
35pub trait SampleResource: SampleResourceInfo {
37 fn fill_buffers(
57 &self,
58 out_buffer: &mut [&mut [f32]],
59 out_buffer_range: Range<usize>,
60 start_frame: u64,
61 ) -> usize;
62}
63
64pub trait SampleResourceF32: SampleResourceInfo {
66 fn channel(&self, i: usize) -> Option<&[f32]>;
68}
69
70impl<T: SampleResource + Send + Sync + 'static> From<T>
71 for ArcGc<dyn SampleResource + Send + Sync + 'static>
72{
73 fn from(value: T) -> Self {
74 ArcGc::new_unsized(|| {
75 bevy_platform::sync::Arc::new(value)
76 as bevy_platform::sync::Arc<dyn SampleResource + Send + Sync + 'static>
77 })
78 }
79}
80
81impl<T: SampleResourceF32 + Send + Sync + 'static> From<T>
82 for ArcGc<dyn SampleResourceF32 + Send + Sync + 'static>
83{
84 fn from(value: T) -> Self {
85 ArcGc::new_unsized(|| {
86 bevy_platform::sync::Arc::new(value)
87 as bevy_platform::sync::Arc<dyn SampleResourceF32 + Send + Sync + 'static>
88 })
89 }
90}
91
92#[derive(Clone)]
93pub struct InterleavedResourceF32 {
94 pub data: Vec<f32>,
95 pub channels: NonZeroUsize,
96 pub sample_rate: Option<NonZeroU32>,
97}
98
99impl InterleavedResourceF32 {
100 pub fn into_dyn_resource(self) -> ArcGc<dyn SampleResource + Send + Sync + 'static> {
101 ArcGc::new_unsized(|| {
102 bevy_platform::sync::Arc::new(self)
103 as bevy_platform::sync::Arc<dyn SampleResource + Send + Sync + 'static>
104 })
105 }
106}
107
108impl SampleResourceInfo for InterleavedResourceF32 {
109 fn num_channels(&self) -> NonZeroUsize {
110 self.channels
111 }
112
113 fn len_frames(&self) -> u64 {
114 (self.data.len() / self.channels.get()) as u64
115 }
116
117 fn sample_rate(&self) -> Option<NonZeroU32> {
118 self.sample_rate
119 }
120}
121
122impl SampleResource for InterleavedResourceF32 {
123 fn fill_buffers(
124 &self,
125 out_buffer: &mut [&mut [f32]],
126 out_buffer_range: Range<usize>,
127 start_frame: u64,
128 ) -> usize {
129 fill_buffers_interleaved(
130 out_buffer,
131 out_buffer_range,
132 start_frame,
133 self.channels,
134 &self.data,
135 self.len_frames() as usize,
136 )
137 }
138}
139
140impl core::fmt::Debug for InterleavedResourceF32 {
141 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
142 write!(
143 f,
144 "InterleavedResourceF32 {{ channels: {}, frames: {} }}",
145 self.channels.get(),
146 self.data.len() / self.channels.get(),
147 )
148 }
149}
150
151impl SampleResourceInfo for Vec<Vec<f32>> {
152 fn num_channels(&self) -> NonZeroUsize {
153 NonZeroUsize::new(self.len()).unwrap()
154 }
155
156 fn len_frames(&self) -> u64 {
157 self[0].len() as u64
158 }
159}
160
161impl SampleResource for Vec<Vec<f32>> {
162 fn fill_buffers(
163 &self,
164 out_buffer: &mut [&mut [f32]],
165 out_buffer_range: Range<usize>,
166 start_frame: u64,
167 ) -> usize {
168 fill_buffers_deinterleaved_f32(
169 out_buffer,
170 out_buffer_range,
171 start_frame,
172 self,
173 self[0].len(),
174 )
175 }
176}
177
178impl SampleResourceF32 for Vec<Vec<f32>> {
179 fn channel(&self, i: usize) -> Option<&[f32]> {
180 self.get(i).map(|data| data.as_slice())
181 }
182}
183
184pub fn fill_buffers_interleaved<T: RawSample + Clone>(
190 out_buffer: &mut [&mut [f32]],
191 out_buffer_range: Range<usize>,
192 start_frame: u64,
193 channels: NonZeroUsize,
194 resource: &[T],
195 resource_len_frames: usize,
196) -> usize {
197 let channels = channels.get();
198
199 let Some((frames, start_frame)) = constrain_frames(
200 out_buffer_range.end - out_buffer_range.start,
201 start_frame,
202 resource_len_frames,
203 ) else {
204 return 0;
205 };
206
207 if channels == 2 && out_buffer.len() >= 2 {
209 let (buf0, buf1) = out_buffer.split_first_mut().unwrap();
210 let buf0 = &mut buf0[out_buffer_range.start..out_buffer_range.start + frames];
211 let buf1 = &mut buf1[0][out_buffer_range.start..out_buffer_range.start + frames];
212
213 let src_slice = &resource[start_frame * 2..(start_frame + frames) * 2];
214
215 for (src_chunk, (buf0_s, buf1_s)) in src_slice
216 .chunks_exact(2)
217 .zip(buf0.iter_mut().zip(buf1.iter_mut()))
218 {
219 *buf0_s = src_chunk[0].to_scaled_float();
220 *buf1_s = src_chunk[1].to_scaled_float();
221 }
222
223 return frames;
224 }
225
226 let src_slice = &resource[start_frame * channels..(start_frame + frames) * channels];
227
228 let adapter = InterleavedSlice::new(src_slice, channels, frames).unwrap();
229 let convert = ConvertNumbers::<&dyn Adapter<T>, f32>::new(&adapter as &dyn Adapter<T>);
230
231 for (ch_i, out_ch) in out_buffer.iter_mut().enumerate().take(channels) {
232 convert.copy_from_channel_to_slice(
233 ch_i,
234 start_frame,
235 &mut out_ch[out_buffer_range.start..out_buffer_range.start + frames],
236 );
237 }
238
239 frames
240}
241
242pub fn fill_channel_deinterleaved<T: RawSample + Clone>(
248 out_buffer_channel: &mut [f32],
249 out_buffer_range: Range<usize>,
250 start_frame: u64,
251 resource_channel: &[T],
252) -> usize {
253 let Some((frames, start_frame)) = constrain_frames(
254 out_buffer_range.end - out_buffer_range.start,
255 start_frame,
256 resource_channel.len(),
257 ) else {
258 return 0;
259 };
260
261 let adapter = SequentialSlice::new(resource_channel, 1, frames).unwrap();
262 let convert = ConvertNumbers::<&dyn Adapter<T>, f32>::new(&adapter as &dyn Adapter<T>);
263
264 convert.copy_from_channel_to_slice(
265 0,
266 start_frame,
267 &mut out_buffer_channel[out_buffer_range.start..out_buffer_range.start + frames],
268 );
269
270 frames
271}
272
273pub fn fill_buffers_deinterleaved_f32<V: AsRef<[f32]>>(
279 out_buffer: &mut [&mut [f32]],
280 out_buffer_range: Range<usize>,
281 start_frame: u64,
282 resource_channels: &[V],
283 resource_len_frames: usize,
284) -> usize {
285 let Some((frames, start_frame)) = constrain_frames(
286 out_buffer_range.end - out_buffer_range.start,
287 start_frame,
288 resource_len_frames,
289 ) else {
290 return 0;
291 };
292
293 for (out_ch, in_ch) in out_buffer.iter_mut().zip(resource_channels.iter()) {
294 out_ch[out_buffer_range.start..out_buffer_range.start + frames]
295 .copy_from_slice(&in_ch.as_ref()[start_frame..start_frame + frames]);
296 }
297
298 frames
299}
300
301pub fn constrain_frames(
308 requested_frames: usize,
309 start_frame: u64,
310 resource_len_frames: usize,
311) -> Option<(usize, usize)> {
312 let frames = (requested_frames as u64)
313 .min((resource_len_frames as u64).saturating_sub(start_frame)) as usize;
314 if frames == 0 {
315 None
316 } else {
317 Some((frames, start_frame as usize))
318 }
319}