use crate::{pd_func_caller, pd_func_caller_log};
use crankstart_sys::ctypes;
use anyhow::{anyhow, ensure, Error, Result};
use core::ptr;
use cstr_core::CString;
pub mod sampleplayer;
pub use sampleplayer::{AudioSample, SamplePlayer};
pub mod fileplayer;
pub use fileplayer::FilePlayer;
static mut SOUND: Sound = Sound::null();
#[derive(Clone, Debug)]
pub struct Sound {
raw_sound: *const crankstart_sys::playdate_sound,
raw_file_player: *const crankstart_sys::playdate_sound_fileplayer,
raw_sample: *const crankstart_sys::playdate_sound_sample,
raw_sample_player: *const crankstart_sys::playdate_sound_sampleplayer,
}
impl Sound {
const fn null() -> Self {
Self {
raw_sound: ptr::null(),
raw_file_player: ptr::null(),
raw_sample: ptr::null(),
raw_sample_player: ptr::null(),
}
}
#[allow(clippy::new_ret_no_self)]
pub(crate) fn new(raw_sound: *const crankstart_sys::playdate_sound) -> Result<()> {
ensure!(!raw_sound.is_null(), "Null pointer passed to Sound::new");
let raw_file_player = unsafe { (*raw_sound).fileplayer };
ensure!(!raw_file_player.is_null(), "Null sound.fileplayer");
let raw_sample = unsafe { (*raw_sound).sample };
ensure!(!raw_sample.is_null(), "Null sound.sample");
let raw_sample_player = unsafe { (*raw_sound).sampleplayer };
ensure!(!raw_sample_player.is_null(), "Null sound.sampleplayer");
let sound = Self {
raw_sound,
raw_file_player,
raw_sample,
raw_sample_player,
};
unsafe { SOUND = sound };
Ok(())
}
pub fn get() -> Self {
unsafe { SOUND.clone() }
}
pub fn get_file_player(&self) -> Result<FilePlayer> {
let raw_player = pd_func_caller!((*self.raw_file_player).newPlayer)?;
ensure!(
!raw_player.is_null(),
"Null returned from fileplayer.newPlayer"
);
FilePlayer::new(self.raw_file_player, raw_player)
}
pub fn get_sample_player(&self) -> Result<SamplePlayer> {
let raw_player = pd_func_caller!((*self.raw_sample_player).newPlayer)?;
ensure!(
!raw_player.is_null(),
"Null returned from sampleplayer.newPlayer"
);
SamplePlayer::new(self.raw_sample_player, raw_player)
}
pub fn load_audio_sample(&self, sample_path: &str) -> Result<AudioSample> {
let sample_path_c = CString::new(sample_path).map_err(Error::msg)?;
let arg_ptr = sample_path_c.as_ptr() as *const ctypes::c_char;
let raw_audio_sample = pd_func_caller!((*self.raw_sample).load, arg_ptr)?;
ensure!(
!raw_audio_sample.is_null(),
"Null returned from sample.load"
);
AudioSample::new(self.raw_sample, raw_audio_sample)
}
pub fn get_current_time(&self) -> Result<ctypes::c_uint> {
pd_func_caller!((*self.raw_sound).getCurrentTime)
}
pub fn set_outputs_active(&self, headphone: bool, speaker: bool) -> Result<()> {
pd_func_caller!(
(*self.raw_sound).setOutputsActive,
headphone as ctypes::c_int,
speaker as ctypes::c_int
)
}
}