use rtsan_standalone::nonblocking;
use core::{marker::PhantomData, ptr::NonNull};
use crate::{AudioBlock, Sample, iter::StridedSampleIter};
pub struct SequentialView<'a, S: Sample> {
data: &'a [S],
num_channels: u16,
num_frames: usize,
num_channels_allocated: u16,
num_frames_allocated: usize,
}
impl<'a, S: Sample> SequentialView<'a, S> {
#[nonblocking]
pub fn from_slice(data: &'a [S], num_channels: u16) -> Self {
assert!(
num_channels > 0 && data.len() % num_channels as usize == 0,
"data length {} must be divisible by num_channels {}",
data.len(),
num_channels
);
let num_frames = data.len() / num_channels as usize;
Self {
data,
num_channels,
num_frames,
num_channels_allocated: num_channels,
num_frames_allocated: num_frames,
}
}
#[nonblocking]
pub fn from_slice_limited(
data: &'a [S],
num_channels_visible: u16,
num_frames_visible: usize,
num_channels_allocated: u16,
num_frames_allocated: usize,
) -> Self {
assert_eq!(
data.len(),
num_channels_allocated as usize * num_frames_allocated
);
assert!(num_channels_visible <= num_channels_allocated);
assert!(num_frames_visible <= num_frames_allocated);
Self {
data,
num_channels: num_channels_visible,
num_frames: num_frames_visible,
num_channels_allocated,
num_frames_allocated,
}
}
#[nonblocking]
pub unsafe fn from_ptr(ptr: *const S, num_channels: u16, num_frames: usize) -> Self {
Self {
data: unsafe { std::slice::from_raw_parts(ptr, num_channels as usize * num_frames) },
num_channels,
num_frames,
num_channels_allocated: num_channels,
num_frames_allocated: num_frames,
}
}
#[nonblocking]
pub unsafe fn from_ptr_limited(
ptr: *const S,
num_channels_visible: u16,
num_frames_visible: usize,
num_channels_allocated: u16,
num_frames_allocated: usize,
) -> Self {
assert!(num_channels_visible <= num_channels_allocated);
assert!(num_frames_visible <= num_frames_allocated);
Self {
data: unsafe {
std::slice::from_raw_parts(
ptr,
num_channels_allocated as usize * num_frames_allocated,
)
},
num_channels: num_channels_visible,
num_frames: num_frames_visible,
num_channels_allocated,
num_frames_allocated,
}
}
#[nonblocking]
pub fn channel(&self, channel: u16) -> &[S] {
assert!(channel < self.num_channels);
let start = channel as usize * self.num_frames_allocated;
let end = start + self.num_frames;
&self.data[start..end]
}
#[nonblocking]
pub fn channels(&self) -> impl ExactSizeIterator<Item = &[S]> {
self.data
.chunks(self.num_frames_allocated)
.take(self.num_channels as usize)
.map(|frame| &frame[..self.num_frames])
}
#[nonblocking]
pub fn raw_data(&self) -> &[S] {
&self.data
}
#[nonblocking]
pub fn view(&self) -> SequentialView<'_, S> {
SequentialView::from_slice_limited(
self.data,
self.num_channels,
self.num_frames,
self.num_channels_allocated,
self.num_frames_allocated,
)
}
}
impl<S: Sample> AudioBlock<S> for SequentialView<'_, S> {
type PlanarView = [S; 0];
#[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::Sequential
}
#[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 * self.num_frames_allocated + frame)
}
}
#[nonblocking]
fn channel_iter(&self, channel: u16) -> impl ExactSizeIterator<Item = &S> {
assert!(channel < self.num_channels);
self.data
.iter()
.skip(channel as usize * self.num_frames_allocated)
.take(self.num_frames)
}
#[nonblocking]
fn channels_iter(&self) -> impl ExactSizeIterator<Item = impl ExactSizeIterator<Item = &S>> {
let num_frames = self.num_frames; let num_frames_allocated = self.num_frames_allocated;
self.data
.chunks(num_frames_allocated)
.take(self.num_channels as usize)
.map(move |channel_chunk| channel_chunk.iter().take(num_frames))
}
#[nonblocking]
fn frame_iter(&self, frame: usize) -> impl ExactSizeIterator<Item = &S> {
assert!(frame < self.num_frames);
self.data
.iter()
.skip(frame)
.step_by(self.num_frames_allocated)
.take(self.num_channels as usize)
}
#[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 stride = self.num_frames_allocated;
let data_ptr = self.data.as_ptr();
(0..num_frames).map(move |frame_idx| {
let start_ptr = if self.data.is_empty() {
NonNull::dangling().as_ptr() } else {
unsafe { data_ptr.add(frame_idx) }
};
StridedSampleIter::<'_, S> {
ptr: NonNull::new(start_ptr as *mut S).unwrap_or(NonNull::dangling()), stride,
remaining: num_channels, _marker: PhantomData,
}
})
}
#[nonblocking]
fn as_view(&self) -> impl AudioBlock<S> {
self.view()
}
#[nonblocking]
fn as_sequential_view(&self) -> Option<SequentialView<'_, S>> {
Some(self.view())
}
}
impl<S: Sample + core::fmt::Debug> core::fmt::Debug for SequentialView<'_, S> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(f, "audio_blocks::SequentialView {{")?;
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(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use rtsan_standalone::no_sanitize_realtime;
#[test]
fn test_member_functions() {
let block = SequentialView::from_slice_limited(
&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 0.0, 0.0, 0.0, 0.0],
2,
3,
3,
4,
);
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.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 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 data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
let block = SequentialView::<f32>::from_slice(&data, 2);
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 data = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
let block = SequentialView::<f32>::from_slice(&data, 2);
let channel = block.channel_iter(0).copied().collect::<Vec<_>>();
assert_eq!(channel, vec![0.0, 1.0, 2.0, 3.0, 4.0]);
let channel = block.channel_iter(1).copied().collect::<Vec<_>>();
assert_eq!(channel, vec![5.0, 6.0, 7.0, 8.0, 9.0]);
}
#[test]
fn test_channel_iters() {
let data = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
let block = SequentialView::<f32>::from_slice(&data, 2);
let mut channels_iter = block.channels_iter();
let channel = channels_iter.next().unwrap().copied().collect::<Vec<_>>();
assert_eq!(channel, vec![0.0, 1.0, 2.0, 3.0, 4.0]);
let channel = channels_iter.next().unwrap().copied().collect::<Vec<_>>();
assert_eq!(channel, vec![5.0, 6.0, 7.0, 8.0, 9.0]);
assert!(channels_iter.next().is_none());
}
#[test]
fn test_frame_iter() {
let data = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
let block = SequentialView::<f32>::from_slice(&data, 2);
let channel = block.frame_iter(0).copied().collect::<Vec<_>>();
assert_eq!(channel, vec![0.0, 5.0]);
let channel = block.frame_iter(1).copied().collect::<Vec<_>>();
assert_eq!(channel, vec![1.0, 6.0]);
let channel = block.frame_iter(2).copied().collect::<Vec<_>>();
assert_eq!(channel, vec![2.0, 7.0]);
let channel = block.frame_iter(3).copied().collect::<Vec<_>>();
assert_eq!(channel, vec![3.0, 8.0]);
let channel = block.frame_iter(4).copied().collect::<Vec<_>>();
assert_eq!(channel, vec![4.0, 9.0]);
}
#[test]
fn test_frame_iters() {
let data = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
let block = SequentialView::<f32>::from_slice(&data, 2);
let mut frames_iter = block.frames_iter();
let channel = frames_iter.next().unwrap().copied().collect::<Vec<_>>();
assert_eq!(channel, vec![0.0, 5.0]);
let channel = frames_iter.next().unwrap().copied().collect::<Vec<_>>();
assert_eq!(channel, vec![1.0, 6.0]);
let channel = frames_iter.next().unwrap().copied().collect::<Vec<_>>();
assert_eq!(channel, vec![2.0, 7.0]);
let channel = frames_iter.next().unwrap().copied().collect::<Vec<_>>();
assert_eq!(channel, vec![3.0, 8.0]);
let channel = frames_iter.next().unwrap().copied().collect::<Vec<_>>();
assert_eq!(channel, vec![4.0, 9.0]);
assert!(frames_iter.next().is_none());
}
#[test]
fn test_from_slice() {
let data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
let block = SequentialView::<f32>::from_slice(&data, 2);
assert_eq!(block.num_channels(), 2);
assert_eq!(block.num_channels_allocated, 2);
assert_eq!(block.num_frames(), 5);
assert_eq!(block.num_frames_allocated, 5);
assert_eq!(
block.channel_iter(0).copied().collect::<Vec<_>>(),
vec![0.0, 1.0, 2.0, 3.0, 4.0]
);
assert_eq!(
block.channel_iter(1).copied().collect::<Vec<_>>(),
vec![5.0, 6.0, 7.0, 8.0, 9.0]
);
assert_eq!(
block.frame_iter(0).copied().collect::<Vec<_>>(),
vec![0.0, 5.0]
);
assert_eq!(
block.frame_iter(1).copied().collect::<Vec<_>>(),
vec![1.0, 6.0]
);
assert_eq!(
block.frame_iter(2).copied().collect::<Vec<_>>(),
vec![2.0, 7.0]
);
assert_eq!(
block.frame_iter(3).copied().collect::<Vec<_>>(),
vec![3.0, 8.0]
);
assert_eq!(
block.frame_iter(4).copied().collect::<Vec<_>>(),
vec![4.0, 9.0]
);
}
#[test]
fn test_view() {
let data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
let block = SequentialView::<f32>::from_slice(&data, 2);
assert!(block.as_interleaved_view().is_none());
assert!(block.as_planar_view().is_none());
assert!(block.as_sequential_view().is_some());
let view = block.as_view();
assert_eq!(
view.channel_iter(0).copied().collect::<Vec<_>>(),
vec![0.0, 1.0, 2.0, 3.0, 4.0]
);
assert_eq!(
view.channel_iter(1).copied().collect::<Vec<_>>(),
vec![5.0, 6.0, 7.0, 8.0, 9.0]
);
}
#[test]
fn test_limited() {
let data = [1.0, 2.0, 0.0, 3.0, 4.0, 0.0, 5.0, 6.0, 0.0, 0.0, 0.0, 0.0];
let block = SequentialView::from_slice_limited(&data, 2, 3, 3, 4);
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_from_ptr() {
let mut data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
let block = unsafe { SequentialView::<f32>::from_ptr(data.as_mut_ptr(), 2, 5) };
assert_eq!(block.num_channels(), 2);
assert_eq!(block.num_channels_allocated, 2);
assert_eq!(block.num_frames(), 5);
assert_eq!(block.num_frames_allocated, 5);
assert_eq!(
block.channel_iter(0).copied().collect::<Vec<_>>(),
vec![0.0, 1.0, 2.0, 3.0, 4.0]
);
assert_eq!(
block.channel_iter(1).copied().collect::<Vec<_>>(),
vec![5.0, 6.0, 7.0, 8.0, 9.0]
);
assert_eq!(
block.frame_iter(0).copied().collect::<Vec<_>>(),
vec![0.0, 5.0]
);
assert_eq!(
block.frame_iter(1).copied().collect::<Vec<_>>(),
vec![1.0, 6.0]
);
assert_eq!(
block.frame_iter(2).copied().collect::<Vec<_>>(),
vec![2.0, 7.0]
);
assert_eq!(
block.frame_iter(3).copied().collect::<Vec<_>>(),
vec![3.0, 8.0]
);
assert_eq!(
block.frame_iter(4).copied().collect::<Vec<_>>(),
vec![4.0, 9.0]
);
}
#[test]
fn test_from_ptr_limited() {
let data = [1.0, 2.0, 0.0, 3.0, 4.0, 0.0, 5.0, 6.0, 0.0, 0.0, 0.0, 0.0];
let block = unsafe { SequentialView::from_ptr_limited(data.as_ptr(), 2, 3, 3, 4) };
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]
#[should_panic]
#[no_sanitize_realtime]
fn test_slice_out_of_bounds() {
let data = [1.0, 1.0, 1.0, 0.0, 2.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0];
let block = SequentialView::from_slice_limited(&data, 2, 3, 3, 4);
block.channel(2);
}
}