use core::mem::ManuallyDrop;
use core::ptr::NonNull;
use super::super::loop_sound_span::LoopTimeSpan;
use super::super::{SoundCompletionCallback, StereoVolume};
use super::sound_source::{AsSoundSource, SoundSource};
use crate::callback_builder::Constructed;
use crate::callbacks::RegisteredCallback;
use crate::capi_state::CApiState;
use crate::ctypes::*;
use crate::error::Error;
use crate::null_terminated::ToNullTerminatedString;
use crate::time::{TimeDelta, TimeTicks};
pub struct FilePlayer {
source: ManuallyDrop<SoundSource>,
ptr: NonNull<CFilePlayer>,
fade_callback: Option<RegisteredCallback>,
}
impl FilePlayer {
pub fn from_file(path: &str) -> Result<Self, Error> {
let ptr = unsafe { Self::fns().newPlayer.unwrap()() };
let r =
unsafe { Self::fns().loadIntoPlayer.unwrap()(ptr, path.to_null_terminated_utf8().as_ptr()) };
if r == 0 {
Err(Error::NotFoundError)
} else {
Ok(FilePlayer {
source: ManuallyDrop::new(SoundSource::from_ptr(ptr as *mut CSoundSource)),
ptr: NonNull::new(ptr).unwrap(),
fade_callback: None,
})
}
}
pub fn file_len(&self) -> TimeTicks {
let f = unsafe { Self::fns().getLength.unwrap()(self.cptr() as *mut _) };
TimeTicks::from_seconds_lossy(f)
}
pub fn set_buffer_len(&mut self, length: TimeTicks) {
unsafe { Self::fns().setBufferLength.unwrap()(self.cptr_mut(), length.to_seconds()) };
}
pub fn pause(&mut self) {
unsafe { Self::fns().pause.unwrap()(self.cptr_mut()) }
}
pub fn play(&mut self, times: i32) -> Result<(), Error> {
match unsafe { Self::fns().play.unwrap()(self.cptr_mut(), times) } {
0 => Err(Error::PlayFileError),
_ => Ok(()),
}
}
pub fn stop(&mut self) {
unsafe { Self::fns().stop.unwrap()(self.cptr_mut()) }
}
pub fn did_underrun(&self) -> bool {
unsafe { Self::fns().didUnderrun.unwrap()(self.cptr() as *mut _) != 0 }
}
pub fn set_loop_range(&mut self, loop_range: LoopTimeSpan) {
unsafe {
Self::fns().setLoopRange.unwrap()(
self.cptr_mut(),
loop_range.start().to_seconds(),
loop_range.end().map_or(0f32, TimeTicks::to_seconds),
)
}
}
pub fn set_offset(&mut self, offset: TimeTicks) {
unsafe { Self::fns().setOffset.unwrap()(self.cptr_mut(), offset.to_seconds()) }
}
pub fn offset(&self) -> TimeTicks {
TimeTicks::from_seconds_lossy(unsafe { Self::fns().getOffset.unwrap()(self.cptr() as *mut _) })
}
pub fn set_playback_rate(&mut self, rate: f32) {
unsafe { Self::fns().setRate.unwrap()(self.cptr_mut(), rate) }
}
pub fn playback_rate(&self) -> f32 {
unsafe { Self::fns().getRate.unwrap()(self.cptr() as *mut _) }
}
pub fn set_stop_on_underrun(&mut self, stop: bool) {
unsafe { Self::fns().setStopOnUnderrun.unwrap()(self.cptr_mut(), stop as i32) }
}
pub fn fade_volume<'a, T, F: Fn(T) + 'static>(
&mut self,
volume: StereoVolume,
duration: TimeDelta,
completion_callback: SoundCompletionCallback<'a, T, F, Constructed>,
) {
self.fade_callback = None;
let func = completion_callback.into_inner().and_then(|(callbacks, cb)| {
let key = self.as_source_mut().cptr() as usize;
let (func, reg) = callbacks.add_sound_source_completion(key, cb);
self.fade_callback = Some(reg);
Some(func)
});
unsafe {
Self::fns().fadeVolume.unwrap()(
self.cptr_mut(),
volume.left.into(),
volume.right.into(),
duration.to_sample_frames(),
func,
)
}
}
pub(crate) fn cptr(&self) -> *const CFilePlayer {
self.ptr.as_ptr()
}
pub(crate) fn cptr_mut(&mut self) -> *mut CFilePlayer {
self.ptr.as_ptr()
}
pub(crate) fn fns() -> &'static craydate_sys::playdate_sound_fileplayer {
unsafe { &*CApiState::get().csound.fileplayer }
}
}
impl Drop for FilePlayer {
fn drop(&mut self) {
unsafe { ManuallyDrop::drop(&mut self.source) };
unsafe { Self::fns().freePlayer.unwrap()(self.cptr_mut()) };
}
}
impl AsRef<SoundSource> for FilePlayer {
fn as_ref(&self) -> &SoundSource {
&self.source
}
}
impl AsMut<SoundSource> for FilePlayer {
fn as_mut(&mut self) -> &mut SoundSource {
&mut self.source
}
}