use audioadapter::Adapter;
use audioadapter_buffers::{
adapter_to_float::ConvertNumbers,
direct::{InterleavedSlice, SequentialSlice},
};
use audioadapter_sample::sample::RawSample;
use core::{
num::{NonZeroU32, NonZeroUsize},
ops::Range,
};
#[cfg(not(feature = "std"))]
use bevy_platform::prelude::Vec;
use crate::collector::ArcGc;
pub trait SampleResourceInfo {
fn num_channels(&self) -> NonZeroUsize;
fn len_frames(&self) -> u64;
fn sample_rate(&self) -> Option<NonZeroU32> {
None
}
}
pub trait SampleResource: SampleResourceInfo {
fn fill_buffers(
&self,
out_buffer: &mut [&mut [f32]],
out_buffer_range: Range<usize>,
start_frame: u64,
) -> usize;
}
pub trait SampleResourceF32: SampleResourceInfo {
fn channel(&self, i: usize) -> Option<&[f32]>;
}
impl<T: SampleResource + Send + Sync + 'static> From<T>
for ArcGc<dyn SampleResource + Send + Sync + 'static>
{
fn from(value: T) -> Self {
ArcGc::new_unsized(|| {
bevy_platform::sync::Arc::new(value)
as bevy_platform::sync::Arc<dyn SampleResource + Send + Sync + 'static>
})
}
}
impl<T: SampleResourceF32 + Send + Sync + 'static> From<T>
for ArcGc<dyn SampleResourceF32 + Send + Sync + 'static>
{
fn from(value: T) -> Self {
ArcGc::new_unsized(|| {
bevy_platform::sync::Arc::new(value)
as bevy_platform::sync::Arc<dyn SampleResourceF32 + Send + Sync + 'static>
})
}
}
#[derive(Clone)]
pub struct InterleavedResourceF32 {
pub data: Vec<f32>,
pub channels: NonZeroUsize,
pub sample_rate: Option<NonZeroU32>,
}
impl InterleavedResourceF32 {
pub fn into_dyn_resource(self) -> ArcGc<dyn SampleResource + Send + Sync + 'static> {
ArcGc::new_unsized(|| {
bevy_platform::sync::Arc::new(self)
as bevy_platform::sync::Arc<dyn SampleResource + Send + Sync + 'static>
})
}
}
impl SampleResourceInfo for InterleavedResourceF32 {
fn num_channels(&self) -> NonZeroUsize {
self.channels
}
fn len_frames(&self) -> u64 {
(self.data.len() / self.channels.get()) as u64
}
fn sample_rate(&self) -> Option<NonZeroU32> {
self.sample_rate
}
}
impl SampleResource for InterleavedResourceF32 {
fn fill_buffers(
&self,
out_buffer: &mut [&mut [f32]],
out_buffer_range: Range<usize>,
start_frame: u64,
) -> usize {
fill_buffers_interleaved(
out_buffer,
out_buffer_range,
start_frame,
self.channels,
&self.data,
self.len_frames() as usize,
)
}
}
impl core::fmt::Debug for InterleavedResourceF32 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"InterleavedResourceF32 {{ channels: {}, frames: {} }}",
self.channels.get(),
self.data.len() / self.channels.get(),
)
}
}
impl SampleResourceInfo for Vec<Vec<f32>> {
fn num_channels(&self) -> NonZeroUsize {
NonZeroUsize::new(self.len()).unwrap()
}
fn len_frames(&self) -> u64 {
self[0].len() as u64
}
}
impl SampleResource for Vec<Vec<f32>> {
fn fill_buffers(
&self,
out_buffer: &mut [&mut [f32]],
out_buffer_range: Range<usize>,
start_frame: u64,
) -> usize {
fill_buffers_deinterleaved_f32(
out_buffer,
out_buffer_range,
start_frame,
self,
self[0].len(),
)
}
}
impl SampleResourceF32 for Vec<Vec<f32>> {
fn channel(&self, i: usize) -> Option<&[f32]> {
self.get(i).map(|data| data.as_slice())
}
}
pub fn fill_buffers_interleaved<T: RawSample + Clone>(
out_buffer: &mut [&mut [f32]],
out_buffer_range: Range<usize>,
start_frame: u64,
channels: NonZeroUsize,
resource: &[T],
resource_len_frames: usize,
) -> usize {
let channels = channels.get();
let Some((frames, start_frame)) = constrain_frames(
out_buffer_range.end - out_buffer_range.start,
start_frame,
resource_len_frames,
) else {
return 0;
};
if channels == 2 && out_buffer.len() >= 2 {
let (buf0, buf1) = out_buffer.split_first_mut().unwrap();
let buf0 = &mut buf0[out_buffer_range.start..out_buffer_range.start + frames];
let buf1 = &mut buf1[0][out_buffer_range.start..out_buffer_range.start + frames];
let src_slice = &resource[start_frame * 2..(start_frame + frames) * 2];
for (src_chunk, (buf0_s, buf1_s)) in src_slice
.chunks_exact(2)
.zip(buf0.iter_mut().zip(buf1.iter_mut()))
{
*buf0_s = src_chunk[0].to_scaled_float();
*buf1_s = src_chunk[1].to_scaled_float();
}
return frames;
}
let src_slice = &resource[start_frame * channels..(start_frame + frames) * channels];
let adapter = InterleavedSlice::new(src_slice, channels, frames).unwrap();
let convert = ConvertNumbers::<&dyn Adapter<T>, f32>::new(&adapter as &dyn Adapter<T>);
for (ch_i, out_ch) in out_buffer.iter_mut().enumerate().take(channels) {
convert.copy_from_channel_to_slice(
ch_i,
start_frame,
&mut out_ch[out_buffer_range.start..out_buffer_range.start + frames],
);
}
frames
}
pub fn fill_channel_deinterleaved<T: RawSample + Clone>(
out_buffer_channel: &mut [f32],
out_buffer_range: Range<usize>,
start_frame: u64,
resource_channel: &[T],
) -> usize {
let Some((frames, start_frame)) = constrain_frames(
out_buffer_range.end - out_buffer_range.start,
start_frame,
resource_channel.len(),
) else {
return 0;
};
let adapter = SequentialSlice::new(resource_channel, 1, frames).unwrap();
let convert = ConvertNumbers::<&dyn Adapter<T>, f32>::new(&adapter as &dyn Adapter<T>);
convert.copy_from_channel_to_slice(
0,
start_frame,
&mut out_buffer_channel[out_buffer_range.start..out_buffer_range.start + frames],
);
frames
}
pub fn fill_buffers_deinterleaved_f32<V: AsRef<[f32]>>(
out_buffer: &mut [&mut [f32]],
out_buffer_range: Range<usize>,
start_frame: u64,
resource_channels: &[V],
resource_len_frames: usize,
) -> usize {
let Some((frames, start_frame)) = constrain_frames(
out_buffer_range.end - out_buffer_range.start,
start_frame,
resource_len_frames,
) else {
return 0;
};
for (out_ch, in_ch) in out_buffer.iter_mut().zip(resource_channels.iter()) {
out_ch[out_buffer_range.start..out_buffer_range.start + frames]
.copy_from_slice(&in_ch.as_ref()[start_frame..start_frame + frames]);
}
frames
}
pub fn constrain_frames(
requested_frames: usize,
start_frame: u64,
resource_len_frames: usize,
) -> Option<(usize, usize)> {
let frames = (requested_frames as u64)
.min((resource_len_frames as u64).saturating_sub(start_frame)) as usize;
if frames == 0 {
None
} else {
Some((frames, start_frame as usize))
}
}