use crate::{pd_func_caller, pd_func_caller_log};
use crankstart_sys::ctypes;
use anyhow::{anyhow, ensure, Error, Result};
use cstr_core::CString;
#[derive(Debug)]
pub struct FilePlayer {
raw_subsystem: *const crankstart_sys::playdate_sound_fileplayer,
raw_player: *mut crankstart_sys::FilePlayer,
}
impl Drop for FilePlayer {
fn drop(&mut self) {
pd_func_caller_log!((*self.raw_subsystem).freePlayer, self.raw_player);
}
}
impl FilePlayer {
pub(crate) fn new(
raw_subsystem: *const crankstart_sys::playdate_sound_fileplayer,
raw_player: *mut crankstart_sys::FilePlayer,
) -> Result<Self> {
ensure!(
!raw_subsystem.is_null(),
"Null pointer given as subsystem to FilePlayer::new"
);
ensure!(
!raw_player.is_null(),
"Null pointer given as player to FilePlayer::new"
);
Ok(Self {
raw_subsystem,
raw_player,
})
}
pub fn load_into_player(&self, file_path: &str) -> Result<()> {
let file_path_c = CString::new(file_path).map_err(Error::msg)?;
let arg_ptr = file_path_c.as_ptr() as *const ctypes::c_char;
let result = pd_func_caller!(
(*self.raw_subsystem).loadIntoPlayer,
self.raw_player,
arg_ptr
)?;
if result == 1 {
Ok(())
} else {
Err(anyhow!(
"load_into_player given nonexistent file '{}'",
file_path
))
}
}
pub fn play(&self, repeat_count: ctypes::c_int) -> Result<()> {
let result = pd_func_caller!((*self.raw_subsystem).play, self.raw_player, repeat_count,)?;
if result == 1 {
Ok(())
} else {
Err(anyhow!(
"fileplayer.play should return 1; returned {}",
result
))
}
}
pub fn stop(&self) -> Result<()> {
pd_func_caller!((*self.raw_subsystem).stop, self.raw_player)
}
pub fn pause(&self) -> Result<()> {
pd_func_caller!((*self.raw_subsystem).pause, self.raw_player)
}
pub fn is_playing(&self) -> Result<bool> {
let result = pd_func_caller!((*self.raw_subsystem).isPlaying, self.raw_player)?;
Ok(result == 1)
}
pub fn set_buffer_length(&self, length: f32) -> Result<()> {
pd_func_caller!(
(*self.raw_subsystem).setBufferLength,
self.raw_player,
length
)
}
pub fn set_stop_on_underrun(&self, stop: bool) -> Result<()> {
pd_func_caller!(
(*self.raw_subsystem).setStopOnUnderrun,
self.raw_player,
stop as ctypes::c_int
)
}
pub fn did_underrun(&self) -> Result<bool> {
let result = pd_func_caller!((*self.raw_subsystem).didUnderrun, self.raw_player)?;
Ok(result == 1)
}
pub fn get_offset(&self) -> Result<f32> {
pd_func_caller!((*self.raw_subsystem).getOffset, self.raw_player)
}
pub fn set_offset(&self, offset: f32) -> Result<()> {
pd_func_caller!((*self.raw_subsystem).setOffset, self.raw_player, offset)
}
pub fn get_volume(&self) -> Result<(f32, f32)> {
let mut left = 0.0;
let mut right = 0.0;
pd_func_caller!(
(*self.raw_subsystem).getVolume,
self.raw_player,
&mut left,
&mut right,
)?;
Ok((left, right))
}
pub fn set_volume(&self, left: f32, right: f32) -> Result<()> {
pd_func_caller!(
(*self.raw_subsystem).setVolume,
self.raw_player,
left,
right
)
}
pub fn get_rate(&self) -> Result<f32> {
pd_func_caller!((*self.raw_subsystem).getRate, self.raw_player)
}
pub fn set_rate(&self, playback_speed: f32) -> Result<()> {
ensure!(
playback_speed >= 0.0,
"FilePlayer cannot play in reverse (playback_speed < 0)"
);
pd_func_caller!(
(*self.raw_subsystem).setRate,
self.raw_player,
playback_speed
)
}
pub fn get_length(&self) -> Result<f32> {
pd_func_caller!((*self.raw_subsystem).getLength, self.raw_player)
}
}