Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
prokopyl committed Jul 25, 2024
1 parent 2aa332b commit 485289e
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 61 deletions.
139 changes: 107 additions & 32 deletions plugin/src/process/audio/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::ops::RangeBounds;
use std::ptr;
use std::ptr::NonNull;

#[derive(Copy, Clone, Eq)]
#[derive(Copy, Clone)]
pub struct AudioBuffer<'a, S> {
ptr: NonNull<S>,
len: usize,
Expand All @@ -18,9 +18,12 @@ pub struct AudioBuffer<'a, S> {
impl<'a, S> AudioBuffer<'a, S> {
/// # Safety
/// TODO
/// TODO: panic if null ptr instead?
#[inline]
pub unsafe fn from_raw_parts(ptr: NonNull<S>, len: usize) -> Self {
pub unsafe fn from_raw_parts(ptr: *mut S, len: usize) -> Self {
let Some(ptr) = NonNull::new(ptr) else {
null_audio_buffer()
};

Self {
ptr,
len,
Expand All @@ -31,7 +34,8 @@ impl<'a, S> AudioBuffer<'a, S> {
#[inline]
pub fn from_mut_slice(slice: &'a mut [S]) -> Self {
Self {
ptr: NonNull::new(slice.as_mut_ptr()).unwrap(), // TODO: unwrap,
// SAFETY: pointer comes from a reference to a slice, it has to be non-null
ptr: unsafe { NonNull::new_unchecked(slice.as_mut_ptr()) },
len: slice.len(),
_lifetime: PhantomData,
}
Expand Down Expand Up @@ -59,8 +63,8 @@ impl<'a, S> AudioBuffer<'a, S> {
}

#[inline]
pub const fn as_ptr(&self) -> NonNull<S> {
self.ptr
pub const fn as_ptr(&self) -> *mut S {
self.ptr.as_ptr()
}

// TODO : test the heck outta this
Expand Down Expand Up @@ -142,7 +146,7 @@ impl<'a, S: Copy> AudioBuffer<'a, S> {
#[inline]
pub fn copy_to_slice(&self, buf: &mut [S]) {
if buf.len() != self.len {
out_of_bounds() // TODO: better error
slice_len_mismatch(self.len, buf.len())
}

// SAFETY: TODO
Expand All @@ -152,28 +156,31 @@ impl<'a, S: Copy> AudioBuffer<'a, S> {
#[inline]
pub fn copy_to_buffer(&self, buf: AudioBuffer<S>) {
if buf.len != self.len {
out_of_bounds() // TODO: better error
slice_len_mismatch(self.len, buf.len)
}

todo!()
// SAFETY: TODO
unsafe { ptr::copy(self.ptr.as_ptr(), buf.as_ptr(), buf.len()) }
}

#[inline]
pub fn copy_from_slice(&self, buf: &[S]) {
if buf.len() != self.len {
out_of_bounds() // TODO: better error
slice_len_mismatch(buf.len(), self.len)
}

todo!()
// SAFETY: TODO
unsafe { ptr::copy_nonoverlapping(buf.as_ptr(), self.ptr.as_ptr(), buf.len()) }
}

#[inline]
pub fn copy_from_buffer(&self, buf: AudioBuffer<S>) {
if buf.len != self.len {
out_of_bounds() // TODO: better error
slice_len_mismatch(buf.len, self.len)
}

todo!()
// SAFETY: TODO
unsafe { ptr::copy(buf.as_ptr(), self.ptr.as_ptr(), buf.len()) }
}

#[inline]
Expand Down Expand Up @@ -215,44 +222,112 @@ impl<'a, S> IntoIterator for &AudioBuffer<'a, S> {
}
}

impl<'a, S: Debug> Debug for AudioBuffer<'a, S> {
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
todo!()
impl<'a, S: Debug + Copy> Debug for AudioBuffer<'a, S> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut dbg = f.debug_list();
for s in self {
dbg.entry(&s.get());
}
dbg.finish()
}
}

impl<'a, S: PartialEq> PartialEq for AudioBuffer<'a, S> {
fn eq(&self, _other: &Self) -> bool {
todo!()
impl<'a, S: PartialEq + Copy> PartialEq for AudioBuffer<'a, S> {
fn eq(&self, other: &Self) -> bool {
if self.len != other.len {
return false;
}

for (a, b) in self.iter().zip(other) {
if a.get() != b.get() {
return false;
}
}

true
}
}

impl<'a, S: PartialEq> PartialEq<[S]> for AudioBuffer<'a, S> {
fn eq(&self, _other: &[S]) -> bool {
todo!()
impl<'a, S: PartialEq + Copy> PartialEq<[S]> for AudioBuffer<'a, S> {
fn eq(&self, other: &[S]) -> bool {
if self.len != other.len() {
return false;
}

for (a, b) in self.iter().zip(other) {
if a.get() != *b {
return false;
}
}

true
}
}

impl<'a, S: PartialEq, const N: usize> PartialEq<[S; N]> for AudioBuffer<'a, S> {
fn eq(&self, _other: &[S; N]) -> bool {
todo!()
impl<'a, S: PartialEq + Copy, const N: usize> PartialEq<[S; N]> for AudioBuffer<'a, S> {
fn eq(&self, other: &[S; N]) -> bool {
if self.len != other.len() {
return false;
}

for (a, b) in self.iter().zip(other) {
if a.get() != *b {
return false;
}
}

true
}
}

impl<'a, S: PartialEq> PartialEq<&[S]> for AudioBuffer<'a, S> {
fn eq(&self, _other: &&[S]) -> bool {
todo!()
impl<'a, S: PartialEq + Copy> PartialEq<&[S]> for AudioBuffer<'a, S> {
fn eq(&self, other: &&[S]) -> bool {
if self.len != other.len() {
return false;
}

for (a, b) in self.iter().zip(*other) {
if a.get() != *b {
return false;
}
}

true
}
}

impl<'a, S: PartialEq, const N: usize> PartialEq<&[S; N]> for AudioBuffer<'a, S> {
fn eq(&self, _other: &&[S; N]) -> bool {
todo!()
impl<'a, S: PartialEq + Copy, const N: usize> PartialEq<&[S; N]> for AudioBuffer<'a, S> {
fn eq(&self, other: &&[S; N]) -> bool {
if self.len != other.len() {
return false;
}

for (a, b) in self.iter().zip(*other) {
if a.get() != *b {
return false;
}
}

true
}
}

#[cold]
#[inline(never)]
pub fn out_of_bounds() -> ! {
fn out_of_bounds() -> ! {
panic!("Out of bounds") // TODO: better error message
}

#[cold]
#[inline(never)]
fn null_audio_buffer() -> ! {
panic!("Invalid audio buffer: buffer pointer is NULL.")
}

#[cold]
#[inline(never)]
fn slice_len_mismatch(src_len: usize, dst_len: usize) -> ! {
panic!(
"Buffer size mismatch: source has length {src_len}, but destination has length {dst_len}"
)
}
37 changes: 8 additions & 29 deletions plugin/src/process/audio/port.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use crate::prelude::Audio;
use crate::process::audio::{AudioBuffer, BufferError, CelledClapAudioBuffer, SampleType};
use clack_common::process::ConstantMask;
use std::ops::Index;
use std::ptr::NonNull;
use std::slice::{Iter, SliceIndex};
use std::slice::Iter;

/// An iterator of all the available [`Port`]s from an [`Audio`] struct.
pub struct PortsIter<'a> {
Expand Down Expand Up @@ -189,12 +187,9 @@ impl<'a, S> PortChannels<'a, S> {
pub fn channel(&self, channel_index: u32) -> Option<AudioBuffer<'a, S>> {
// SAFETY: this type guarantees the buffer pointer is valid and of size frames_count
unsafe {
self.data.get(channel_index as usize).map(|data| {
AudioBuffer::from_raw_parts(
NonNull::new_unchecked(*data), // TODO: unwrap instead?
self.frames_count as usize,
)
})
self.data
.get(channel_index as usize)
.map(|data| AudioBuffer::from_raw_parts(*data, self.frames_count as usize))
}
}

Expand Down Expand Up @@ -228,21 +223,10 @@ impl<'a, T> IntoIterator for &'a PortChannels<'a, T> {
}
}

// TODO: hide implementation detail
impl<'a, T, Idx: SliceIndex<[*mut T]>> Index<Idx> for PortChannels<'a, T> {
type Output = PortChannels<'a, T>;

#[inline]
fn index(&self, index: Idx) -> &Self::Output {
let _ = self.data.get(index);
todo!()
}
}

/// An iterator over all of an [`Port`]'s channels' sample buffers.
pub struct PortChannelsIter<'a, T> {
pub(crate) data: Iter<'a, *mut T>,
pub(crate) frames_count: u32,
data: Iter<'a, *mut T>,
frames_count: u32,
}

impl<'a, T> Iterator for PortChannelsIter<'a, T> {
Expand All @@ -252,14 +236,9 @@ impl<'a, T> Iterator for PortChannelsIter<'a, T> {
fn next(&mut self) -> Option<Self::Item> {
self.data
.next()
// SAFETY: iterator can only get created from an InputChannels, which guarantees
// SAFETY: iterator can only get created from a PortChannels, which guarantees
// the buffer is both valid and of length frames_count
.map(|ptr| unsafe {
AudioBuffer::from_raw_parts(
NonNull::new_unchecked(*ptr), // TODO: unwrap instead?
self.frames_count as usize,
)
})
.map(|ptr| unsafe { AudioBuffer::from_raw_parts(*ptr, self.frames_count as usize) })
}

#[inline]
Expand Down

0 comments on commit 485289e

Please sign in to comment.