use crate::{
StereoKitError,
maths::{Bool32T, Vec3},
system::IAsset,
};
use std::{
ffi::{CStr, CString, c_char},
path::Path,
ptr::NonNull,
};
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct Sound(pub NonNull<_SoundT>);
impl Drop for Sound {
fn drop(&mut self) {
unsafe { sound_release(self.0.as_ptr()) };
}
}
impl AsRef<Sound> for Sound {
fn as_ref(&self) -> &Sound {
self
}
}
#[repr(C)]
#[derive(Debug)]
pub struct _SoundT {
_unused: [u8; 0],
}
pub type SoundT = *mut _SoundT;
unsafe impl Send for Sound {}
unsafe impl Sync for Sound {}
unsafe extern "C" {
pub fn sound_find(id: *const c_char) -> SoundT;
pub fn sound_set_id(sound: SoundT, id: *const c_char);
pub fn sound_get_id(sound: SoundT) -> *const c_char;
pub fn sound_create(filename_utf8: *const c_char) -> SoundT;
pub fn sound_create_stream(buffer_duration: f32) -> SoundT;
pub fn sound_create_samples(in_arr_samples_at_48000s: *const f32, sample_count: u64) -> SoundT;
pub fn sound_generate(
audio_generator: Option<unsafe extern "C" fn(sample_time: f32) -> f32>,
duration: f32,
) -> SoundT;
pub fn sound_write_samples(sound: SoundT, in_arr_samples: *const f32, sample_count: u64);
pub fn sound_read_samples(sound: SoundT, out_arr_samples: *mut f32, sample_count: u64) -> u64;
pub fn sound_unread_samples(sound: SoundT) -> u64;
pub fn sound_total_samples(sound: SoundT) -> u64;
pub fn sound_cursor_samples(sound: SoundT) -> u64;
pub fn sound_get_decibels(sound: SoundT) -> f32;
pub fn sound_set_decibels(sound: SoundT, decibels: f32);
pub fn sound_play(sound: SoundT, at: Vec3, volume: f32) -> SoundInst;
pub fn sound_duration(sound: SoundT) -> f32;
pub fn sound_addref(sound: SoundT);
pub fn sound_release(sound: SoundT);
}
impl IAsset for Sound {
fn get_id(&self) -> &str {
self.get_id()
}
}
impl Default for Sound {
fn default() -> Self {
Sound::click()
}
}
impl Sound {
pub fn create_stream(stream_buffer_duration: f32) -> Result<Sound, StereoKitError> {
Ok(Sound(
NonNull::new(unsafe { sound_create_stream(stream_buffer_duration) })
.ok_or(StereoKitError::SoundCreate("create_stream failed".into()))?,
))
}
pub fn from_file(file_utf8: impl AsRef<Path>) -> Result<Sound, StereoKitError> {
let path_buf = file_utf8.as_ref().to_path_buf();
let c_str = CString::new(path_buf.clone().to_str().ok_or(StereoKitError::SoundFile(path_buf.clone()))?)?;
Ok(Sound(
NonNull::new(unsafe { sound_create(c_str.as_ptr()) }).ok_or(StereoKitError::SoundFile(path_buf))?,
))
}
pub fn from_samples(in_arr_samples_at_48000s: &[f32]) -> Result<Sound, StereoKitError> {
Ok(Sound(
NonNull::new(unsafe {
sound_create_samples(in_arr_samples_at_48000s.as_ptr(), in_arr_samples_at_48000s.len() as u64)
})
.ok_or(StereoKitError::SoundCreate("from_samples failed".into()))?,
))
}
pub fn generate(generator: unsafe extern "C" fn(f32) -> f32, duration: f32) -> Result<Sound, StereoKitError> {
Ok(Sound(
NonNull::new(unsafe { sound_generate(Some(generator), duration) })
.ok_or(StereoKitError::SoundCreate("sound_generate failed".into()))?,
))
}
pub fn find<S: AsRef<str>>(id: S) -> Result<Sound, StereoKitError> {
let cstr_id = CString::new(id.as_ref())?;
Ok(Sound(
NonNull::new(unsafe { sound_find(cstr_id.as_ptr()) })
.ok_or(StereoKitError::SoundFind(id.as_ref().to_string(), "not found".to_owned()))?,
))
}
pub fn clone_ref(&self) -> Sound {
Sound(NonNull::new(unsafe { sound_find(sound_get_id(self.0.as_ptr())) }).expect("<asset>::clone_ref failed!"))
}
pub fn id<S: AsRef<str>>(&mut self, id: S) -> &mut Self {
let cstr_id = CString::new(id.as_ref()).unwrap();
unsafe { sound_set_id(self.0.as_ptr(), cstr_id.as_ptr()) };
self
}
pub fn play(&self, at: impl Into<Vec3>, volume: Option<f32>) -> SoundInst {
let volume = volume.unwrap_or(1.0);
unsafe { sound_play(self.0.as_ptr(), at.into(), volume) }
}
pub fn decibels(&self, decibels: f32) {
unsafe { sound_set_decibels(self.0.as_ptr(), decibels) }
}
pub fn read_samples(&self, out_arr_samples: &mut [f32], sample_count: Option<u64>) -> u64 {
let sample_count = sample_count.unwrap_or(out_arr_samples.len() as u64);
unsafe { sound_read_samples(self.0.as_ptr(), out_arr_samples.as_mut_ptr(), sample_count) }
}
pub fn write_samples(&self, in_arr_samples: &[f32], sample_count: Option<u64>) {
let sample_count = sample_count.unwrap_or(in_arr_samples.len() as u64);
unsafe { sound_write_samples(self.0.as_ptr(), in_arr_samples.as_ptr(), sample_count) };
}
pub fn get_id(&self) -> &str {
unsafe { CStr::from_ptr(sound_get_id(self.0.as_ptr())) }.to_str().unwrap()
}
pub fn get_cursor_samples(&self) -> u64 {
unsafe { sound_cursor_samples(self.0.as_ptr()) }
}
pub fn get_duration(&self) -> f32 {
unsafe { sound_duration(self.0.as_ptr()) }
}
pub fn get_decibels(&self) -> f32 {
unsafe { sound_get_decibels(self.0.as_ptr()) }
}
pub fn get_total_samples(&self) -> u64 {
unsafe { sound_total_samples(self.0.as_ptr()) }
}
pub fn get_unread_samples(&self) -> u64 {
unsafe { sound_unread_samples(self.0.as_ptr()) }
}
pub fn click() -> Self {
let cstr_id = CString::new("default/sound_click").unwrap();
Sound(NonNull::new(unsafe { sound_find(cstr_id.as_ptr()) }).unwrap())
}
pub fn unclick() -> Self {
let cstr_id = CString::new("default/sound_unclick").unwrap();
Sound(NonNull::new(unsafe { sound_find(cstr_id.as_ptr()) }).unwrap())
}
pub fn grab() -> Self {
let cstr_id = CString::new("default/sound_grab").unwrap();
Sound(NonNull::new(unsafe { sound_find(cstr_id.as_ptr()) }).unwrap())
}
pub fn ungrab() -> Self {
let cstr_id = CString::new("default/sound_ungrab").unwrap();
Sound(NonNull::new(unsafe { sound_find(cstr_id.as_ptr()) }).unwrap())
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct SoundInst {
pub _id: u16,
pub _slot: i16,
}
unsafe extern "C" {
pub fn sound_inst_stop(sound_inst: SoundInst);
pub fn sound_inst_is_playing(sound_inst: SoundInst) -> Bool32T;
pub fn sound_inst_set_pos(sound_inst: SoundInst, pos: Vec3);
pub fn sound_inst_get_pos(sound_inst: SoundInst) -> Vec3;
pub fn sound_inst_set_volume(sound_inst: SoundInst, volume: f32);
pub fn sound_inst_get_volume(sound_inst: SoundInst) -> f32;
pub fn sound_inst_get_intensity(sound_inst: SoundInst) -> f32;
}
impl SoundInst {
pub fn stop(self) {
unsafe { sound_inst_stop(self) }
}
pub fn position(&mut self, at: impl Into<Vec3>) -> &mut Self {
unsafe { sound_inst_set_pos(*self, at.into()) }
self
}
pub fn volume(&mut self, volume: f32) -> &mut Self {
unsafe { sound_inst_set_volume(*self, volume) }
self
}
pub fn get_position(&self) -> Vec3 {
unsafe { sound_inst_get_pos(*self) }
}
pub fn get_volume(&self) -> f32 {
unsafe { sound_inst_get_volume(*self) }
}
pub fn get_intensity(&self) -> f32 {
unsafe { sound_inst_get_intensity(*self) }
}
pub fn is_playing(&self) -> bool {
unsafe { sound_inst_is_playing(*self) != 0 }
}
}