use crate::alloc::{alloc, boxed::Box, sync::Arc};
use core::{
convert::TryFrom,
mem,
ops::{Deref, DerefMut},
ptr,
sync::atomic::{AtomicIsize, Ordering},
};
use crate::{frame, math::Float, Frame, Seek, Signal};
#[derive(Debug)]
pub struct Frames<T> {
rate: f64,
samples: [T],
}
impl<T> Frames<T> {
pub fn from_slice(rate: u32, samples: &[T]) -> Arc<Self>
where
T: Copy,
{
let header_layout = alloc::Layout::new::<f64>();
let (layout, payload_offset) = header_layout
.extend(
alloc::Layout::from_size_align(mem::size_of_val(samples), mem::align_of::<T>())
.unwrap(),
)
.unwrap();
let layout = layout.pad_to_align();
unsafe {
let mem = alloc::alloc(layout);
mem.cast::<f64>().write(rate.into());
let payload = mem.add(payload_offset).cast::<T>();
for (i, &x) in samples.iter().enumerate() {
payload.add(i).write(x);
}
Box::from_raw(ptr::slice_from_raw_parts_mut(mem, samples.len()) as *mut Self).into()
}
}
pub fn from_iter<I>(rate: u32, iter: I) -> Arc<Self>
where
I: IntoIterator<Item = T>,
I::IntoIter: ExactSizeIterator,
{
let iter = iter.into_iter();
let len = iter.len();
let header_layout = alloc::Layout::new::<f64>();
let (layout, payload_offset) = header_layout
.extend(
alloc::Layout::from_size_align(mem::size_of::<T>() * len, mem::align_of::<T>())
.unwrap(),
)
.unwrap();
let layout = layout.pad_to_align();
unsafe {
let mem = alloc::alloc(layout);
mem.cast::<f64>().write(rate.into());
let payload = mem.add(payload_offset).cast::<T>();
let mut n = 0;
for (i, x) in iter.enumerate() {
payload.add(i).write(x);
n += 1;
}
assert_eq!(n, len, "iterator returned incorrect length");
Box::from_raw(ptr::slice_from_raw_parts_mut(mem, len) as *mut Self).into()
}
}
pub fn rate(&self) -> u32 {
self.rate as u32
}
pub fn runtime(&self) -> f64 {
self.samples.len() as f64 / self.rate
}
#[inline]
pub fn interpolate(&self, s: f64) -> T
where
T: Frame + Copy,
{
let x0 = s as isize;
let fract = (s - x0 as f64) as f32;
let (a, b) = self.get_pair(x0);
frame::lerp(&a, &b, fract)
}
#[inline]
fn get_pair(&self, sample: isize) -> (T, T)
where
T: Frame + Copy,
{
if sample >= 0 {
let sample = sample as usize;
if sample < self.samples.len() - 1 {
(self.samples[sample], self.samples[sample + 1])
} else if sample < self.samples.len() {
(self.samples[sample], T::ZERO)
} else {
(T::ZERO, T::ZERO)
}
} else if sample < -1 {
(T::ZERO, T::ZERO)
} else {
(T::ZERO, self.samples[0])
}
}
}
impl<T> Deref for Frames<T> {
type Target = [T];
fn deref(&self) -> &[T] {
&self.samples
}
}
impl<T> DerefMut for Frames<T> {
fn deref_mut(&mut self) -> &mut [T] {
&mut self.samples
}
}
#[derive(Debug)]
pub struct FramesSignal<T> {
data: Arc<Frames<T>>,
t: f64,
sample_t: Arc<AtomicIsize>,
}
impl<T> FramesSignal<T> {
pub fn new(data: Arc<Frames<T>>, start_seconds: f64) -> (FramesSignalControl, Self) {
let samples = data.len();
let signal = Self {
t: start_seconds,
sample_t: Arc::new(AtomicIsize::new((start_seconds * data.rate) as isize)),
data,
};
let control = FramesSignalControl {
samples,
sample_position: signal.sample_t.clone(),
rate: signal.data.rate,
};
(control, signal)
}
}
impl<T: Frame + Copy> Signal for FramesSignal<T> {
type Frame = T;
#[inline]
fn sample(&mut self, interval: f32, out: &mut [T]) {
let s0 = self.t * self.data.rate;
let ds = interval * self.data.rate as f32;
let base = s0 as isize;
if (ds - 1.0).abs() <= f32::EPSILON {
let fract = (s0 - base as f64) as f32;
for (i, o) in out.iter_mut().enumerate() {
let (a, b) = self.data.get_pair(base + i as isize);
*o = frame::lerp(&a, &b, fract);
}
} else {
let mut offset = (s0 - base as f64) as f32;
for o in out.iter_mut() {
let trunc = unsafe { offset.to_int_unchecked::<isize>() };
let (a, b) = self.data.get_pair(base + trunc);
let fract = offset - trunc as f32;
*o = frame::lerp(&a, &b, fract);
offset += ds;
}
}
self.t += f64::from(interval) * out.len() as f64;
self.sample_t
.store((self.t * self.data.rate) as isize, Ordering::Relaxed);
}
#[inline]
fn is_finished(&self) -> bool {
self.t >= (self.data.samples.len() - 1) as f64 / self.data.rate
}
}
impl<T: Frame + Copy> Seek for FramesSignal<T> {
#[inline]
fn seek(&mut self, seconds: f32) {
self.t += f64::from(seconds);
}
}
impl<T> From<Arc<Frames<T>>> for FramesSignal<T> {
fn from(samples: Arc<Frames<T>>) -> Self {
Self::new(samples, 0.0).1
}
}
pub struct FramesSignalControl {
samples: usize,
sample_position: Arc<AtomicIsize>,
rate: f64,
}
impl FramesSignalControl {
#[inline]
pub fn playback_position(&self) -> f64 {
self.sample_position.load(Ordering::Relaxed) as f64 / self.rate
}
#[inline]
pub fn is_finished(&self) -> bool {
usize::try_from(self.sample_position.load(Ordering::Relaxed))
.map_or(false, |x| x >= self.samples)
}
}
#[cfg(test)]
mod tests {
use super::*;
use ::alloc::vec;
fn assert_out(stream: &mut FramesSignal<f32>, interval: f32, expected: &[f32]) {
let mut output = vec![0.0; expected.len()];
stream.sample(interval, &mut output);
assert_eq!(&output, expected);
}
#[test]
fn from_slice() {
const DATA: &[f32] = &[1.0, 2.0, 3.0];
let frames = Frames::from_slice(1, DATA);
assert_eq!(&frames[..], DATA);
}
#[test]
fn sample() {
let (_, mut signal) = FramesSignal::new(Frames::from_slice(1, &[1.0, 2.0, 3.0, 4.0]), -2.0);
assert_out(&mut signal, 0.25, &[0.0, 0.0, 0.0, 0.0]);
assert_out(&mut signal, 0.5, &[0.0, 0.5, 1.0]);
assert_out(&mut signal, 1.0, &[1.5, 2.5, 3.5, 2.0, 0.0]);
}
#[test]
fn playback_position() {
let (control, mut signal) =
FramesSignal::new(Frames::from_slice(1, &[1.0, 2.0, 3.0]), -2.0);
let init = control.playback_position();
assert_eq!(init, -2.0);
assert!(!control.is_finished());
let mut buf = [0.0; 10];
signal.sample(0.2, &mut buf);
assert_eq!(0.0, control.playback_position());
assert!(!control.is_finished());
signal.sample(0.1, &mut buf);
assert_eq!(1.0, control.playback_position());
signal.sample(0.1, &mut buf);
assert_eq!(2.0, control.playback_position());
signal.sample(0.2, &mut buf);
assert!(control.is_finished());
assert_eq!(4.0, control.playback_position());
signal.sample(0.5, &mut buf);
assert_eq!(9.0, control.playback_position());
}
}