use core::{fmt::Debug, mem::MaybeUninit};
use rtsan_standalone::nonblocking;
use std::marker::PhantomData;
use crate::{AudioBlock, Sample};
pub struct PlanarView<'a, S: Sample, V: AsRef<[S]>> {
data: &'a [V],
num_channels: u16,
num_frames: usize,
num_channels_allocated: u16,
num_frames_allocated: usize,
_phantom: PhantomData<S>,
}
impl<'a, S: Sample, V: AsRef<[S]>> PlanarView<'a, S, V> {
#[nonblocking]
pub fn from_slice(data: &'a [V]) -> Self {
let num_frames_allocated = if data.is_empty() {
0
} else {
data[0].as_ref().len()
};
Self::from_slice_limited(data, data.len() as u16, num_frames_allocated)
}
#[nonblocking]
pub fn from_slice_limited(
data: &'a [V],
num_channels_visible: u16,
num_frames_visible: usize,
) -> Self {
let num_channels_allocated = data.len() as u16;
let num_frames_allocated = if num_channels_allocated == 0 {
0
} else {
data[0].as_ref().len()
};
assert!(num_channels_visible <= num_channels_allocated);
assert!(num_frames_visible <= num_frames_allocated);
data.iter()
.for_each(|v| assert_eq!(v.as_ref().len(), num_frames_allocated));
Self {
data,
num_channels: num_channels_visible,
num_frames: num_frames_visible,
num_channels_allocated,
num_frames_allocated,
_phantom: PhantomData,
}
}
#[nonblocking]
pub fn channel(&self, channel: u16) -> &[S] {
assert!(channel < self.num_channels);
&self.data[channel as usize].as_ref()[..self.num_frames]
}
#[nonblocking]
pub fn channels(&self) -> impl ExactSizeIterator<Item = &[S]> {
self.data
.iter()
.take(self.num_channels as usize)
.map(|channel_data| &channel_data.as_ref()[..self.num_frames])
}
#[nonblocking]
pub fn raw_data(&self) -> &[V] {
self.data
}
#[nonblocking]
pub fn view(&self) -> PlanarView<'_, S, V> {
PlanarView::from_slice_limited(self.data, self.num_channels, self.num_frames)
}
}
impl<S: Sample, V: AsRef<[S]>> AudioBlock<S> for PlanarView<'_, S, V> {
type PlanarView = V;
#[nonblocking]
fn num_channels(&self) -> u16 {
self.num_channels
}
#[nonblocking]
fn num_frames(&self) -> usize {
self.num_frames
}
#[nonblocking]
fn num_channels_allocated(&self) -> u16 {
self.num_channels_allocated
}
#[nonblocking]
fn num_frames_allocated(&self) -> usize {
self.num_frames_allocated
}
#[nonblocking]
fn layout(&self) -> crate::BlockLayout {
crate::BlockLayout::Planar
}
#[nonblocking]
fn sample(&self, channel: u16, frame: usize) -> S {
assert!(channel < self.num_channels);
assert!(frame < self.num_frames);
unsafe {
*self
.data
.get_unchecked(channel as usize)
.as_ref()
.get_unchecked(frame)
}
}
#[nonblocking]
fn channel_iter(&self, channel: u16) -> impl ExactSizeIterator<Item = &S> {
assert!(channel < self.num_channels);
unsafe {
self.data
.get_unchecked(channel as usize)
.as_ref()
.iter()
.take(self.num_frames)
}
}
#[nonblocking]
fn channels_iter(&self) -> impl ExactSizeIterator<Item = impl ExactSizeIterator<Item = &S>> {
let num_frames = self.num_frames; self.data
.iter()
.take(self.num_channels as usize)
.map(move |channel_data| channel_data.as_ref().iter().take(num_frames))
}
#[nonblocking]
fn frame_iter(&self, frame: usize) -> impl ExactSizeIterator<Item = &S> {
assert!(frame < self.num_frames);
self.data
.iter()
.take(self.num_channels as usize)
.map(move |channel_data| unsafe { channel_data.as_ref().get_unchecked(frame) })
}
#[nonblocking]
fn frames_iter(&self) -> impl ExactSizeIterator<Item = impl ExactSizeIterator<Item = &'_ S>> {
let num_channels = self.num_channels as usize;
let num_frames = self.num_frames;
let data_slice: &[V] = self.data;
(0..num_frames).map(move |frame_idx| {
data_slice[..num_channels]
.iter() .map(move |channel_view: &V| {
let channel_slice: &[S] = channel_view.as_ref();
&channel_slice[frame_idx]
})
})
}
#[nonblocking]
fn as_view(&self) -> impl AudioBlock<S> {
self.view()
}
#[nonblocking]
fn as_planar_view(&self) -> Option<PlanarView<'_, S, Self::PlanarView>> {
Some(self.view())
}
}
impl<S: Sample + core::fmt::Debug, V: AsRef<[S]> + Debug> core::fmt::Debug
for PlanarView<'_, S, V>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(f, "audio_blocks::PlanarView {{")?;
writeln!(f, " num_channels: {}", self.num_channels)?;
writeln!(f, " num_frames: {}", self.num_frames)?;
writeln!(
f,
" num_channels_allocated: {}",
self.num_channels_allocated
)?;
writeln!(f, " num_frames_allocated: {}", self.num_frames_allocated)?;
writeln!(f, " channels:")?;
for (i, channel) in self.channels().enumerate() {
writeln!(f, " {}: {:?}", i, channel)?;
}
writeln!(f, " raw_data: {:?}", self.raw_data())?;
writeln!(f, "}}")?;
Ok(())
}
}
pub struct PlanarPtrAdapter<'a, S: Sample, const MAX_CHANNELS: usize> {
data: [MaybeUninit<&'a [S]>; MAX_CHANNELS],
num_channels: u16,
}
impl<'a, S: Sample, const MAX_CHANNELS: usize> PlanarPtrAdapter<'a, S, MAX_CHANNELS> {
#[nonblocking]
pub unsafe fn from_ptr(ptr: *const *const S, num_channels: u16, num_frames: usize) -> Self {
assert!(
num_channels as usize <= MAX_CHANNELS,
"num_channels exceeds MAX_CHANNELS"
);
let mut data: [core::mem::MaybeUninit<&'a [S]>; MAX_CHANNELS] =
unsafe { core::mem::MaybeUninit::uninit().assume_init() };
let ptr_slice: &[*const S] =
unsafe { core::slice::from_raw_parts(ptr, num_channels as usize) };
for ch in 0..num_channels as usize {
data[ch].write(unsafe { core::slice::from_raw_parts(ptr_slice[ch], num_frames) });
}
Self { data, num_channels }
}
#[inline]
pub fn data_slice(&self) -> &[&'a [S]] {
let initialized_part: &[MaybeUninit<&'a [S]>] = &self.data[..self.num_channels as usize];
unsafe {
core::slice::from_raw_parts(
initialized_part.as_ptr() as *const &'a [S],
self.num_channels as usize,
)
}
}
#[nonblocking]
pub fn planar_view(&self) -> PlanarView<'a, S, &[S]> {
PlanarView::from_slice(self.data_slice())
}
}
#[cfg(test)]
mod tests {
use super::*;
use rtsan_standalone::no_sanitize_realtime;
#[test]
fn test_member_functions() {
let data = [
[0.0, 1.0, 2.0, 3.0],
[4.0, 5.0, 6.0, 7.0],
[0.0, 0.0, 0.0, 0.0],
];
let block = PlanarView::from_slice_limited(&data, 2, 3);
assert_eq!(block.channel(0), &[0.0, 1.0, 2.0]);
assert_eq!(block.channel(1), &[4.0, 5.0, 6.0]);
let mut channels = block.channels();
assert_eq!(channels.next().unwrap(), &[0.0, 1.0, 2.0]);
assert_eq!(channels.next().unwrap(), &[4.0, 5.0, 6.0]);
assert_eq!(channels.next(), None);
drop(channels);
assert_eq!(block.raw_data()[0].as_ref(), &[0.0, 1.0, 2.0, 3.0]);
assert_eq!(block.raw_data()[1].as_ref(), &[4.0, 5.0, 6.0, 7.0]);
assert_eq!(block.raw_data()[2].as_ref(), &[0.0, 0.0, 0.0, 0.0]);
let view = block.view();
assert_eq!(view.num_channels(), block.num_channels());
assert_eq!(view.num_frames(), block.num_frames());
assert_eq!(
view.num_channels_allocated(),
block.num_channels_allocated()
);
assert_eq!(view.num_frames_allocated(), block.num_frames_allocated());
assert_eq!(view.raw_data(), block.raw_data());
}
#[test]
fn test_samples() {
let ch1 = &[0.0, 1.0, 2.0, 3.0, 4.0];
let ch2 = &[5.0, 6.0, 7.0, 8.0, 9.0];
let data = [ch1, ch2];
let block = PlanarView::from_slice(&data);
for ch in 0..block.num_channels() {
for f in 0..block.num_frames() {
assert_eq!(
block.sample(ch, f),
(ch as usize * block.num_frames() + f) as f32
);
}
}
}
#[test]
fn test_channel_iter() {
let ch1 = vec![0.0, 2.0, 4.0, 6.0, 8.0];
let ch2 = vec![1.0, 3.0, 5.0, 7.0, 9.0];
let data = vec![ch1, ch2];
let block = PlanarView::from_slice(&data);
let channel = block.channel_iter(0).copied().collect::<Vec<_>>();
assert_eq!(channel, vec![0.0, 2.0, 4.0, 6.0, 8.0]);
let channel = block.channel_iter(1).copied().collect::<Vec<_>>();
assert_eq!(channel, vec![1.0, 3.0, 5.0, 7.0, 9.0]);
}
#[test]
fn test_channel_iters() {
let ch1 = vec![0.0, 2.0, 4.0, 6.0, 8.0];
let ch2 = vec![1.0, 3.0, 5.0, 7.0, 9.0];
let data = vec![ch1, ch2];
let block = PlanarView::from_slice(&data);
let mut channels_iter = block.channels_iter();
let channel = channels_iter.next().unwrap().copied().collect::<Vec<_>>();
assert_eq!(channel, vec![0.0, 2.0, 4.0, 6.0, 8.0]);
let channel = channels_iter.next().unwrap().copied().collect::<Vec<_>>();
assert_eq!(channel, vec![1.0, 3.0, 5.0, 7.0, 9.0]);
assert!(channels_iter.next().is_none());
}
#[test]
fn test_frame_iter() {
let ch1 = vec![0.0, 2.0, 4.0, 6.0, 8.0];
let ch2 = vec![1.0, 3.0, 5.0, 7.0, 9.0];
let data = vec![ch1.as_slice(), ch2.as_slice()];
let block = PlanarView::from_slice(&data);
let channel = block.frame_iter(0).copied().collect::<Vec<_>>();
assert_eq!(channel, vec![0.0, 1.0]);
let channel = block.frame_iter(1).copied().collect::<Vec<_>>();
assert_eq!(channel, vec![2.0, 3.0]);
let channel = block.frame_iter(2).copied().collect::<Vec<_>>();
assert_eq!(channel, vec![4.0, 5.0]);
let channel = block.frame_iter(3).copied().collect::<Vec<_>>();
assert_eq!(channel, vec![6.0, 7.0]);
let channel = block.frame_iter(4).copied().collect::<Vec<_>>();
assert_eq!(channel, vec![8.0, 9.0]);
}
#[test]
fn test_frame_iters() {
let ch1 = vec![0.0, 2.0, 4.0, 6.0, 8.0];
let ch2 = vec![1.0, 3.0, 5.0, 7.0, 9.0];
let data = vec![ch1.as_slice(), ch2.as_slice()];
let block = PlanarView::from_slice(&data);
let mut frames_iter = block.frames_iter();
let channel = frames_iter.next().unwrap().copied().collect::<Vec<_>>();
assert_eq!(channel, vec![0.0, 1.0]);
let channel = frames_iter.next().unwrap().copied().collect::<Vec<_>>();
assert_eq!(channel, vec![2.0, 3.0]);
let channel = frames_iter.next().unwrap().copied().collect::<Vec<_>>();
assert_eq!(channel, vec![4.0, 5.0]);
let channel = frames_iter.next().unwrap().copied().collect::<Vec<_>>();
assert_eq!(channel, vec![6.0, 7.0]);
let channel = frames_iter.next().unwrap().copied().collect::<Vec<_>>();
assert_eq!(channel, vec![8.0, 9.0]);
assert!(frames_iter.next().is_none());
}
#[test]
fn test_from_vec() {
let vec = vec![vec![0.0, 2.0, 4.0, 6.0, 8.0], vec![1.0, 3.0, 5.0, 7.0, 9.0]];
let block = PlanarView::from_slice(&vec);
assert_eq!(block.num_channels(), 2);
assert_eq!(block.num_frames(), 5);
assert_eq!(
block.channel_iter(0).copied().collect::<Vec<_>>(),
vec![0.0, 2.0, 4.0, 6.0, 8.0]
);
assert_eq!(
block.channel_iter(1).copied().collect::<Vec<_>>(),
vec![1.0, 3.0, 5.0, 7.0, 9.0]
);
assert_eq!(
block.frame_iter(0).copied().collect::<Vec<_>>(),
vec![0.0, 1.0]
);
assert_eq!(
block.frame_iter(1).copied().collect::<Vec<_>>(),
vec![2.0, 3.0]
);
assert_eq!(
block.frame_iter(2).copied().collect::<Vec<_>>(),
vec![4.0, 5.0]
);
assert_eq!(
block.frame_iter(3).copied().collect::<Vec<_>>(),
vec![6.0, 7.0]
);
assert_eq!(
block.frame_iter(4).copied().collect::<Vec<_>>(),
vec![8.0, 9.0]
);
}
#[test]
fn test_view() {
let vec = vec![vec![0.0, 2.0, 4.0, 6.0, 8.0], vec![1.0, 3.0, 5.0, 7.0, 9.0]];
let block = PlanarView::from_slice(&vec);
assert!(block.as_interleaved_view().is_none());
assert!(block.as_planar_view().is_some());
assert!(block.as_sequential_view().is_none());
let view = block.as_view();
assert_eq!(
view.channel_iter(0).copied().collect::<Vec<_>>(),
vec![0.0, 2.0, 4.0, 6.0, 8.0]
);
assert_eq!(
view.channel_iter(1).copied().collect::<Vec<_>>(),
vec![1.0, 3.0, 5.0, 7.0, 9.0]
);
}
#[test]
fn test_limited() {
let data = vec![vec![0.0; 4]; 3];
let block = PlanarView::from_slice_limited(&data, 2, 3);
assert_eq!(block.num_channels(), 2);
assert_eq!(block.num_frames(), 3);
assert_eq!(block.num_channels_allocated, 3);
assert_eq!(block.num_frames_allocated, 4);
for i in 0..block.num_channels() {
assert_eq!(block.channel_iter(i).count(), 3);
}
for i in 0..block.num_frames() {
assert_eq!(block.frame_iter(i).count(), 2);
}
}
#[test]
fn test_pointer() {
unsafe {
let num_channels = 2;
let num_frames = 5;
let mut vec = [vec![0.0, 2.0, 4.0, 6.0, 8.0], vec![1.0, 3.0, 5.0, 7.0, 9.0]];
let ptr_vec: Vec<*const f32> =
vec.iter_mut().map(|inner_vec| inner_vec.as_ptr()).collect();
let ptr = ptr_vec.as_ptr();
let adapter = PlanarPtrAdapter::<_, 16>::from_ptr(ptr, num_channels, num_frames);
let planar = adapter.planar_view();
assert_eq!(
planar.channel_iter(0).copied().collect::<Vec<_>>(),
vec![0.0, 2.0, 4.0, 6.0, 8.0]
);
assert_eq!(
planar.channel_iter(1).copied().collect::<Vec<_>>(),
vec![1.0, 3.0, 5.0, 7.0, 9.0]
);
}
}
#[test]
#[should_panic]
#[no_sanitize_realtime]
fn test_slice_out_of_bounds() {
let data = [[1.0; 4], [2.0; 4], [0.0; 4]];
let block = PlanarView::from_slice_limited(&data, 2, 3);
block.channel(2);
}
}