use alloc::vec::Vec;
use core::mem::ManuallyDrop;
use core::ptr::NonNull;
use super::super::sources::delay_line_tap::DelayLineTap;
use super::sound_effect::SoundEffect;
use crate::capi_state::CApiState;
use crate::ctypes::*;
use crate::time::TimeDelta;
#[derive(Debug)]
pub struct DelayLine {
effect: ManuallyDrop<SoundEffect>,
ptr: NonNull<CDelayLine>,
taps: Vec<DelayLineTap>,
length_in_frames: i32,
max_tap_position_in_frames: i32,
}
impl DelayLine {
pub fn new(length: TimeDelta, stereo: bool) -> Self {
let ptr =
unsafe { Self::fns().newDelayLine.unwrap()(length.to_sample_frames(), stereo as i32) };
DelayLine {
effect: ManuallyDrop::new(SoundEffect::from_ptr(ptr as *mut CSoundEffect)),
ptr: NonNull::new(ptr).unwrap(),
taps: Vec::new(),
length_in_frames: length.to_sample_frames(),
max_tap_position_in_frames: 0,
}
}
pub fn add_tap(&mut self, delay: TimeDelta) -> Option<&mut DelayLineTap> {
let max_frames = self.max_tap_position_in_frames.max(delay.to_sample_frames());
if max_frames <= self.length_in_frames {
let tap = DelayLineTap::new(self, delay);
self.taps.push(tap);
self.max_tap_position_in_frames = max_frames;
Some(unsafe { self.taps.last_mut().unwrap_unchecked() })
} else {
None
}
}
pub fn taps(&self) -> &[DelayLineTap] {
&self.taps
}
pub fn taps_mut(&mut self) -> &mut [DelayLineTap] {
&mut self.taps
}
pub fn set_len(&mut self, length: TimeDelta) {
let length_in_frames = length.to_sample_frames().max(self.max_tap_position_in_frames);
unsafe { Self::fns().setLength.unwrap()(self.cptr_mut(), length_in_frames) }
}
pub fn len(&self) -> TimeDelta {
TimeDelta::from_sample_frames(self.length_in_frames)
}
pub fn set_feedback(&mut self, feedback: f32) {
unsafe { Self::fns().setFeedback.unwrap()(self.cptr_mut(), feedback) }
}
pub(crate) fn cptr_mut(&mut self) -> *mut CDelayLine {
self.ptr.as_ptr()
}
pub(crate) fn fns() -> &'static craydate_sys::playdate_sound_effect_delayline {
unsafe { &*(*CApiState::get().csound.effect).delayline }
}
}
impl Drop for DelayLine {
fn drop(&mut self) {
self.taps.clear();
unsafe { ManuallyDrop::drop(&mut self.effect) };
unsafe { Self::fns().freeDelayLine.unwrap()(self.cptr_mut()) }
}
}
impl AsRef<SoundEffect> for DelayLine {
fn as_ref(&self) -> &SoundEffect {
&self.effect
}
}
impl AsMut<SoundEffect> for DelayLine {
fn as_mut(&mut self) -> &mut SoundEffect {
&mut self.effect
}
}