Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dasp::Frame: Generic impl for all [impl Sample;const N: usize] #180

Merged
merged 1 commit into from
Nov 11, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
298 changes: 127 additions & 171 deletions dasp_frame/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#![cfg_attr(not(feature = "std"), no_std)]

use core::iter::DoubleEndedIterator;
use core::{iter::DoubleEndedIterator, mem::MaybeUninit};

use dasp_sample::Sample;

Expand Down Expand Up @@ -295,198 +295,133 @@ pub struct ChannelsRef<'a, F: Frame>(core::slice::Iter<'a, F::Sample>);
/// Like [`ChannelsRef`], but yields mutable references instead.
pub struct ChannelsMut<'a, F: Frame>(core::slice::IterMut<'a, F::Sample>);

macro_rules! impl_frame_for_fixed_size_array {
($($NChan:ident $N:expr, [$($idx:expr)*],)*) => {
$(
/// A typified version of a number of channels.
pub struct $NChan;
impl NumChannels for $NChan {}

impl<S> Frame for [S; $N]
where
S: Sample,
{
type Sample = S;
type NumChannels = $NChan;
type Channels = Channels<Self>;
type Float = [S::Float; $N];
type Signed = [S::Signed; $N];

const EQUILIBRIUM: Self = [S::EQUILIBRIUM; $N];
const CHANNELS: usize = $N;
pub struct NChannels<const N: usize> {}
impl<const N: usize> NumChannels for NChannels<N> {}

#[inline]
fn channels(self) -> Self::Channels {
Channels {
next_idx: 0,
frame: self,
}
}

#[inline]
fn channels_ref(&self) -> ChannelsRef<'_, Self> {
ChannelsRef(self.iter())
}

#[inline]
fn channels_mut(&mut self) -> ChannelsMut<'_, Self> {
ChannelsMut(self.iter_mut())
}
impl<S, const N: usize> Frame for [S; N]
where
S: Sample,
{
type Sample = S;
type NumChannels = NChannels<N>;
type Channels = Channels<Self>;
type Float = [S::Float; N];
type Signed = [S::Signed; N];

#[inline]
fn channel(&self, idx: usize) -> Option<&Self::Sample> {
self.get(idx)
}
const EQUILIBRIUM: Self = [S::EQUILIBRIUM; N];
const CHANNELS: usize = N;

#[inline]
fn channel_mut(&mut self, idx: usize) -> Option<&mut Self::Sample> {
self.get_mut(idx)
}
#[inline]
fn channels(self) -> Self::Channels {
Channels {
next_idx: 0,
frame: self,
}
}

#[inline]
fn from_fn<F>(mut from: F) -> Self
where
F: FnMut(usize) -> S,
{
[$(from($idx), )*]
}
#[inline]
fn channels_ref(&self) -> ChannelsRef<'_, Self> {
ChannelsRef(self.iter())
}

#[inline]
fn from_samples<I>(samples: &mut I) -> Option<Self>
where
I: Iterator<Item=Self::Sample>
{
Some([$( {
$idx;
match samples.next() {
Some(sample) => sample,
None => return None,
}
}, )*])
}
#[inline]
fn channels_mut(&mut self) -> ChannelsMut<'_, Self> {
ChannelsMut(self.iter_mut())
}

#[inline(always)]
unsafe fn channel_unchecked(&self, idx: usize) -> &Self::Sample {
self.get_unchecked(idx)
}
#[inline]
fn channel(&self, idx: usize) -> Option<&Self::Sample> {
self.get(idx)
}

#[inline(always)]
unsafe fn channel_unchecked_mut(&mut self, idx: usize) -> &mut Self::Sample {
self.get_unchecked_mut(idx)
}
#[inline]
fn channel_mut(&mut self, idx: usize) -> Option<&mut Self::Sample> {
self.get_mut(idx)
}

#[inline]
fn to_signed_frame(self) -> Self::Signed {
self.map(|s| s.to_sample())
}
#[inline]
fn from_fn<F>(from: F) -> Self
where
F: FnMut(usize) -> S,
{
core::array::from_fn(from)
}

#[inline]
fn to_float_frame(self) -> Self::Float {
self.map(|s| s.to_sample())
}
#[inline]
fn from_samples<I>(samples: &mut I) -> Option<Self>
where
I: Iterator<Item = Self::Sample>,
{
array_from_iter(samples)
}

#[inline]
fn map<F, M>(self, mut map: M) -> F
where
F: Frame<NumChannels=Self::NumChannels>,
M: FnMut(Self::Sample) -> F::Sample,
{
F::from_fn(|channel_idx| {
#[inline(always)]
unsafe fn channel_unchecked(&self, idx: usize) -> &Self::Sample {
self.get_unchecked(idx)
}

// Here we do not require run-time bounds checking as we have asserted that
// the two arrays have the same number of channels at compile time with our
// where clause, i.e.
//
// `F: Frame<NumChannels=Self::NumChannels>`
unsafe { map(*self.channel_unchecked(channel_idx)) }
})
}
#[inline(always)]
unsafe fn channel_unchecked_mut(&mut self, idx: usize) -> &mut Self::Sample {
self.get_unchecked_mut(idx)
}

#[inline]
fn zip_map<O, F, M>(self, other: O, mut zip_map: M) -> F
where
O: Frame<NumChannels=Self::NumChannels>,
F: Frame<NumChannels=Self::NumChannels>,
M: FnMut(Self::Sample, O::Sample) -> F::Sample
{
F::from_fn(|channel_idx| {
#[inline]
fn to_signed_frame(self) -> Self::Signed {
self.map(|s| s.to_sample())
}

// Here we do not require run-time bounds checking as we have asserted that the two
// arrays have the same number of channels at compile time with our where clause, i.e.
//
// ```
// O: Frame<NumChannels=Self::NumChannels>
// F: Frame<NumChannels=Self::NumChannels>
// ```
unsafe {
zip_map(*self.channel_unchecked(channel_idx),
*other.channel_unchecked(channel_idx))
}
})
}
#[inline]
fn to_float_frame(self) -> Self::Float {
self.map(|s| s.to_sample())
}

#[inline]
fn scale_amp(self, amp: S::Float) -> Self {
[$(self[$idx].mul_amp(amp), )*]
}
#[inline]
fn map<F, M>(self, mut map: M) -> F
where
F: Frame<NumChannels = Self::NumChannels>,
M: FnMut(Self::Sample) -> F::Sample,
{
F::from_fn(|channel_idx| {
// Here we do not require run-time bounds checking as we have asserted that
// the two arrays have the same number of channels at compile time with our
// where clause, i.e.
//
// `F: Frame<NumChannels=Self::NumChannels>`
unsafe { map(*self.channel_unchecked(channel_idx)) }
})
}

#[inline]
fn add_amp<F>(self, other: F) -> Self
where
F: Frame<Sample=S::Signed, NumChannels=$NChan>,
{
// Here we do not require run-time bounds checking as we have asserted that the two
// arrays have the same number of channels at compile time with our where clause, i.e.
unsafe {
[$(self[$idx].add_amp(*other.channel_unchecked($idx)), )*]
}
}
#[inline]
fn zip_map<O, F, M>(self, other: O, mut zip_map: M) -> F
where
O: Frame<NumChannels = Self::NumChannels>,
F: Frame<NumChannels = Self::NumChannels>,
M: FnMut(Self::Sample, O::Sample) -> F::Sample,
{
F::from_fn(|channel_idx| {
// Here we do not require run-time bounds checking as we have asserted that the two
// arrays have the same number of channels at compile time with our where clause, i.e.
//
// ```
// O: Frame<NumChannels=Self::NumChannels>
// F: Frame<NumChannels=Self::NumChannels>
// ```
unsafe {
zip_map(
*self.channel_unchecked(channel_idx),
*other.channel_unchecked(channel_idx),
)
}
)*
};
}

impl_frame_for_fixed_size_array! {
N1 1, [0],
N2 2, [0 1],
N3 3, [0 1 2],
N4 4, [0 1 2 3],
N5 5, [0 1 2 3 4],
N6 6, [0 1 2 3 4 5],
N7 7, [0 1 2 3 4 5 6],
N8 8, [0 1 2 3 4 5 6 7],
N9 9, [0 1 2 3 4 5 6 7 8],
N10 10, [0 1 2 3 4 5 6 7 8 9],
N11 11, [0 1 2 3 4 5 6 7 8 9 10],
N12 12, [0 1 2 3 4 5 6 7 8 9 10 11],
N13 13, [0 1 2 3 4 5 6 7 8 9 10 11 12],
N14 14, [0 1 2 3 4 5 6 7 8 9 10 11 12 13],
N15 15, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14],
N16 16, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15],
N17 17, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16],
N18 18, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17],
N19 19, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18],
N20 20, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19],
N21 21, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20],
N22 22, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21],
N23 23, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22],
N24 24, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23],
N25 25, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24],
N26 26, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25],
N27 27, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26],
N28 28, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27],
N29 29, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28],
N30 30, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29],
N31 31, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30],
N32 32, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31],
})
}
}

macro_rules! impl_frame_for_sample {
($($T:ty)*) => {
$(
impl Frame for $T {
type Sample = $T;
type NumChannels = N1;
type NumChannels = NChannels<1>;
type Channels = Channels<Self>;
type Float = <$T as Sample>::Float;
type Signed = <$T as Sample>::Signed;
Expand Down Expand Up @@ -612,7 +547,7 @@ macro_rules! impl_frame_for_sample {
#[inline]
fn add_amp<F>(self, other: F) -> Self
where
F: Frame<Sample=<$T as Sample>::Signed, NumChannels=N1>,
F: Frame<Sample=<$T as Sample>::Signed, NumChannels=NChannels<1>>,
{
// Here we do not require run-time bounds checking as we have asserted that the two
// arrays have the same number of channels at compile time with our where clause, i.e.
Expand Down Expand Up @@ -714,3 +649,24 @@ impl<'a, F: Frame> DoubleEndedIterator for ChannelsMut<'a, F> {
self.0.next_back()
}
}

fn array_from_iter<T, const N: usize>(mut iter: impl Iterator<Item = T>) -> Option<[T; N]> {
// Hopefully something equivalent will be in stdlib some day

unsafe {
let mut result: [MaybeUninit<T>; N] = MaybeUninit::uninit().assume_init();

for i in 0..N {
if let Some(sample) = iter.next() {
result[i].write(sample);
} else {
for i in 0..i {
result[i].assume_init_drop()
}
return None;
}
}

Some(result.map(|v| v.assume_init()))
}
}