use std::ops::{Bound, Range, RangeBounds};
use crate::audio::conv::{FromSample, IntoSample};
use crate::audio::sample::{Sample, SampleBytes};
pub fn plane_pair_by_buffer_index<S: Sample>(
planes: &[Vec<S>],
range: Range<usize>,
idx0: usize,
idx1: usize,
) -> Option<(&[S], &[S])> {
assert!(idx0 != idx1, "buffer indicies cannot be the same");
let num_planes = planes.len();
if idx0 < num_planes && idx1 < num_planes {
if idx0 < idx1 {
let (a, b) = planes.split_at(idx1);
Some((&a[idx0][range.clone()], &b[0][range.clone()]))
}
else {
let (a, b) = planes.split_at(idx0);
Some((&b[0][range.clone()], &a[idx1][range.clone()]))
}
}
else {
None
}
}
pub fn plane_pair_by_buffer_index_mut<S: Sample>(
planes: &mut [Vec<S>],
range: Range<usize>,
idx0: usize,
idx1: usize,
) -> Option<(&mut [S], &mut [S])> {
assert!(idx0 != idx1, "buffer indicies cannot be the same");
let num_planes = planes.len();
if idx0 < num_planes && idx1 < num_planes {
if idx0 < idx1 {
let (a, b) = planes.split_at_mut(idx1);
Some((&mut a[idx0][range.clone()], &mut b[0][range.clone()]))
}
else {
let (a, b) = planes.split_at_mut(idx0);
Some((&mut b[0][range.clone()], &mut a[idx1][range.clone()]))
}
}
else {
None
}
}
pub fn get_sub_range<R>(range: R, bound: &Range<usize>) -> Range<usize>
where
R: RangeBounds<usize>,
{
const fn panic_start_index_overflow() -> usize {
panic!("attempted to index audio buffer slice from after maximum usize")
}
const fn panic_end_index_overflow() -> usize {
panic!("attempted to index audio buffer slice slice up to maximum usize")
}
let len = bound.len();
let start = match range.start_bound() {
Bound::Included(&start) => start,
Bound::Excluded(start) => start.checked_add(1).unwrap_or_else(panic_start_index_overflow),
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(end) => end.checked_add(1).unwrap_or_else(panic_end_index_overflow),
Bound::Excluded(&end) => end,
Bound::Unbounded => len,
};
assert!(start <= end, "audio buffer slice index start {start} is beyond end {end}");
assert!(end <= len, "audio buffer slice end {end} index is out of range {len}");
let start = start.checked_add(bound.start).unwrap_or_else(panic_start_index_overflow);
let end = end.checked_add(bound.start).unwrap_or_else(panic_end_index_overflow);
Range { start, end }
}
#[inline(never)]
pub fn copy_to_slice_interleaved<Sin, Sout, Src, Dst>(
src: &[Src],
bound: Range<usize>,
mut dst: Dst,
) where
Sin: Sample,
Sout: Sample + FromSample<Sin>,
Src: AsRef<[Sin]>,
Dst: AsMut<[Sout]>,
{
let dst = dst.as_mut();
let num_planes = src.len();
assert!(
dst.len() == num_planes * bound.len(),
"destination slice does not match number of samples"
);
let mut i = 0;
while num_planes - i > 1 {
let src0 = &src[i + 0].as_ref()[bound.clone()];
let src1 = &src[i + 1].as_ref()[bound.clone()];
for ((&s0, &s1), d) in src0.iter().zip(src1).zip(dst.chunks_exact_mut(num_planes)) {
d[i + 0] = s0.into_sample();
d[i + 1] = s1.into_sample();
}
i += 2
}
while i < num_planes {
let src0 = &src[i].as_ref()[bound.clone()];
for (&s0, d) in src0.iter().zip(dst.chunks_exact_mut(num_planes)) {
d[i] = s0.into_sample();
}
i += 1;
}
}
#[inline(never)]
pub fn copy_from_slice_interleaved<Sin, Sout, Src, Dst>(
src: Src,
bound: Range<usize>,
dst: &mut [Dst],
) where
Sin: Sample,
Sout: Sample + FromSample<Sin>,
Src: AsRef<[Sin]>,
Dst: AsMut<[Sout]>,
{
let src = src.as_ref();
let num_planes = dst.len();
assert!(
src.len() == num_planes * bound.len(),
"source slice length does not match expected number of samples"
);
let mut i = 0;
while num_planes - i > 1 {
let (l, r) = dst.split_at_mut(i + 1);
let dst0 = &mut l.last_mut().unwrap().as_mut()[bound.clone()];
let dst1 = &mut r.first_mut().unwrap().as_mut()[bound.clone()];
for ((d0, d1), s) in dst0.iter_mut().zip(dst1).zip(src.chunks_exact(num_planes)) {
*d0 = s[i + 0].into_sample();
*d1 = s[i + 1].into_sample();
}
i += 2
}
while i < num_planes {
let dst0 = &mut dst[i].as_mut()[bound.clone()];
for (d0, s) in dst0.iter_mut().zip(src.chunks_exact(num_planes)) {
*d0 = s[i].into_sample();
}
i += 1;
}
}
#[inline(always)]
pub fn convert<Sin: Sample, Sout: SampleBytes + FromSample<Sin>>(s: Sin) -> Sout {
s.into_sample()
}
#[inline(always)]
pub fn identity<Sin: Sample + SampleBytes>(s: Sin) -> Sin {
s
}
#[inline(never)]
pub fn copy_to_slice<Sin, Sout>(src: &[Sin], dst: &mut [Sout])
where
Sin: Sample,
Sout: Sample + FromSample<Sin>,
{
assert!(src.len() == dst.len(), "destination slice does not match number of samples");
for (d, s) in dst.iter_mut().zip(src) {
*d = (*s).into_sample();
}
}
#[inline(never)]
pub fn copy_bytes_interleaved<Sout, Sin, Src, F, Dst>(
src: &[Src],
bound: Range<usize>,
f: F,
mut dst: Dst,
) where
Sout: SampleBytes,
Sin: Sample,
Src: AsRef<[Sin]>,
F: Fn(Sin) -> Sout,
Dst: AsMut<[u8]>,
{
let dst: &mut [Sout::RawType] = bytemuck::cast_slice_mut(dst.as_mut());
let num_planes = src.len();
assert!(
dst.len() == num_planes * bound.len(),
"destination slice does not match number of samples"
);
let mut i = 0;
while num_planes - i > 1 {
let src0 = &src[i + 0].as_ref()[bound.clone()];
let src1 = &src[i + 1].as_ref()[bound.clone()];
for ((&s0, &s1), d) in src0.iter().zip(src1).zip(dst.chunks_exact_mut(num_planes)) {
d[i + 0] = f(s0).to_ne_sample_bytes();
d[i + 1] = f(s1).to_ne_sample_bytes();
}
i += 2
}
while i < num_planes {
let src0 = &src[i].as_ref()[bound.clone()];
for (&s0, d) in src0.iter().zip(dst.chunks_exact_mut(num_planes)) {
d[i] = f(s0).to_ne_sample_bytes();
}
i += 1;
}
}
#[inline(never)]
pub fn copy_bytes_planar<Sout, Sin, Src, F, Dst>(
src: &[Src],
bound: Range<usize>,
f: F,
dst: &mut [Dst],
) where
Sout: SampleBytes,
Sin: Sample,
Src: AsRef<[Sin]>,
F: Fn(Sin) -> Sout,
Dst: AsMut<[u8]>,
{
assert!(dst.len() == src.len(), "expected {} destination slices", src.len());
for (src, dst) in src.iter().zip(dst) {
let src = &src.as_ref()[bound.clone()];
let dst: &mut [Sout::RawType] = bytemuck::cast_slice_mut(dst.as_mut());
assert!(src.len() == dst.len(), "destination slice does not match number of samples");
for (&s, d) in src.iter().zip(dst) {
*d = f(s).to_ne_sample_bytes();
}
}
}
#[cfg(test)]
mod tests {
use super::copy_from_slice_interleaved;
#[test]
fn verify_copy_from_slice_interleaved() {
let src = vec![
0.00, -1.0, 0.5, 0.25, -0.75, 0.25, 0.50, -0.50, 0.0, 0.75, -0.25, -0.25, 1.00, 0.00, -0.5, ];
{
let mut dst = vec![vec![0.0; 5]; 3];
copy_from_slice_interleaved(&src, 0..5, &mut dst);
assert_eq!(dst[0], [0.0, 0.25, 0.5, 0.75, 1.0]);
assert_eq!(dst[1], [-1.0, -0.75, -0.5, -0.25, 0.0]);
assert_eq!(dst[2], [0.5, 0.25, 0.0, -0.25, -0.5]);
}
{
let mut dst = vec![vec![0.0; 5]; 3];
copy_from_slice_interleaved(&src[3..12], 1..4, &mut dst);
assert_eq!(dst[0], [0.0, 0.25, 0.5, 0.75, 0.0]);
assert_eq!(dst[1], [0.0, -0.75, -0.5, -0.25, 0.0]);
assert_eq!(dst[2], [0.0, 0.25, 0.0, -0.25, 0.0]);
}
}
}