use alloc::vec::Vec;
use core::mem::MaybeUninit;
use core::ptr::NonNull;
use crate::capi_state::CApiState;
use crate::ctypes::*;
use crate::null_terminated::ToNullTerminatedString;
use crate::time::TimeTicks;
#[derive(Debug)]
pub struct AudioSample {
ptr: NonNull<CAudioSample>,
data: Vec<u8>,
}
impl AudioSample {
pub(crate) fn from_ptr(ptr: *mut CAudioSample) -> AudioSample {
AudioSample {
ptr: NonNull::new(ptr).unwrap(),
data: Vec::new(),
}
}
pub fn with_bytes(bytes: usize) -> Self {
let ptr = unsafe { Self::fns().newSampleBuffer.unwrap()(bytes as i32) };
Self::from_ptr(ptr)
}
pub fn from_file(path: &str) -> Option<AudioSample> {
let ptr = unsafe { Self::fns().load.unwrap()(path.to_null_terminated_utf8().as_ptr()) };
if ptr.is_null() {
None
} else {
Some(Self::from_ptr(ptr))
}
}
pub fn from_vec(data: Vec<u8>, format: SoundFormat, sample_rate: u32) -> AudioSample {
assert!(
format == SoundFormat::kSound8bitMono
|| format == SoundFormat::kSound8bitStereo
|| format == SoundFormat::kSound16bitMono
|| format == SoundFormat::kSound16bitStereo
|| format == SoundFormat::kSoundADPCMMono
|| format == SoundFormat::kSound16bitStereo
);
let ptr = unsafe {
Self::fns().newSampleFromData.unwrap()(
data.as_ptr() as *mut u8, format,
sample_rate,
data.len() as i32,
)
};
let mut sample = Self::from_ptr(ptr);
sample.data = data;
sample
}
pub fn from_slice(data: &[u8], format: SoundFormat, sample_rate: u32) -> AudioSample {
assert!(
format == SoundFormat::kSound8bitMono
|| format == SoundFormat::kSound8bitStereo
|| format == SoundFormat::kSound16bitMono
|| format == SoundFormat::kSound16bitStereo
|| format == SoundFormat::kSoundADPCMMono
|| format == SoundFormat::kSound16bitStereo
);
let ptr = unsafe {
Self::fns().newSampleFromData.unwrap()(
data.as_ptr() as *mut u8, format,
sample_rate,
data.len() as i32,
)
};
let mut sample = Self::from_ptr(ptr);
sample.data.reserve(data.len());
sample.data.extend(data.iter());
sample
}
pub fn load_file(&mut self, path: &str) {
unsafe {
Self::fns().loadIntoSample.unwrap()(self.cptr_mut(), path.to_null_terminated_utf8().as_ptr())
};
}
pub fn len(&self) -> TimeTicks {
TimeTicks::from_seconds_lossy(unsafe { Self::fns().getLength.unwrap()(self.cptr() as *mut _) })
}
fn all_data(&self) -> (*mut u8, SoundFormat, u32, u32) {
let mut ptr = MaybeUninit::uninit();
let mut format = MaybeUninit::uninit();
let mut sample_rate = MaybeUninit::uninit();
let mut bytes = MaybeUninit::uninit();
unsafe {
Self::fns().getData.unwrap()(
self.cptr() as *mut _,
ptr.as_mut_ptr(),
format.as_mut_ptr(),
sample_rate.as_mut_ptr(),
bytes.as_mut_ptr(),
)
};
unsafe {
(
ptr.assume_init(),
format.assume_init(),
sample_rate.assume_init(),
bytes.assume_init(),
)
}
}
pub fn data(&self) -> &[u8] {
let (ptr, _, _, bytes) = self.all_data();
unsafe { core::slice::from_raw_parts(ptr, bytes as usize) }
}
pub fn sound_format(&self) -> SoundFormat {
let (_, format, _, _) = self.all_data();
format
}
pub fn sample_rate(&self) -> u32 {
let (_, _, sample_rate, _) = self.all_data();
sample_rate
}
pub(crate) fn cptr(&self) -> *const CAudioSample {
self.ptr.as_ptr()
}
pub(crate) fn cptr_mut(&mut self) -> *mut CAudioSample {
self.ptr.as_ptr()
}
pub(crate) fn fns() -> &'static craydate_sys::playdate_sound_sample {
unsafe { &*CApiState::get().csound.sample }
}
}
impl Drop for AudioSample {
fn drop(&mut self) {
unsafe { Self::fns().freeSample.unwrap()(self.cptr_mut()) }
}
}