use std::{
ffi::CString,
os::raw::{c_int, c_short, c_uint},
ptr::NonNull,
};
use dos_like_sys::sound_t;
use crate::FileError;
pub const SOUND_CHANNELS: u32 = dos_like_sys::SOUND_CHANNELS;
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
#[repr(u32)]
pub enum SoundMode {
Mono8bit5000 = dos_like_sys::soundmode_t_soundmode_8bit_mono_5000,
Mono8bit8000 = dos_like_sys::soundmode_t_soundmode_8bit_mono_8000,
Mono8bit11025 = dos_like_sys::soundmode_t_soundmode_8bit_mono_11025,
Mono8bit16000 = dos_like_sys::soundmode_t_soundmode_8bit_mono_16000,
Mono8bit22050 = dos_like_sys::soundmode_t_soundmode_8bit_mono_22050,
Mono8bit32000 = dos_like_sys::soundmode_t_soundmode_8bit_mono_32000,
Mono8bit44100 = dos_like_sys::soundmode_t_soundmode_8bit_mono_44100,
Mono16Bit5000 = dos_like_sys::soundmode_t_soundmode_16bit_mono_5000,
Mono16Bit8000 = dos_like_sys::soundmode_t_soundmode_16bit_mono_8000,
Mono16Bit11025 = dos_like_sys::soundmode_t_soundmode_16bit_mono_11025,
Mono16Bit16000 = dos_like_sys::soundmode_t_soundmode_16bit_mono_16000,
Mono16Bit22050 = dos_like_sys::soundmode_t_soundmode_16bit_mono_22050,
Mono16Bit32000 = dos_like_sys::soundmode_t_soundmode_16bit_mono_32000,
Mono16Bit44100 = dos_like_sys::soundmode_t_soundmode_16bit_mono_44100,
Stereo8Bit5000 = dos_like_sys::soundmode_t_soundmode_8bit_stereo_5000,
Stereo8Bit8000 = dos_like_sys::soundmode_t_soundmode_8bit_stereo_8000,
Stereo8Bit11025 = dos_like_sys::soundmode_t_soundmode_8bit_stereo_11025,
Stereo8Bit16000 = dos_like_sys::soundmode_t_soundmode_8bit_stereo_16000,
Stereo8Bit22050 = dos_like_sys::soundmode_t_soundmode_8bit_stereo_22050,
Stereo8Bit32000 = dos_like_sys::soundmode_t_soundmode_8bit_stereo_32000,
Stereo8Bit44100 = dos_like_sys::soundmode_t_soundmode_8bit_stereo_44100,
Stereo16Bit5000 = dos_like_sys::soundmode_t_soundmode_16bit_stereo_5000,
Stereo16Bit8000 = dos_like_sys::soundmode_t_soundmode_16bit_stereo_8000,
Stereo16Bit11025 = dos_like_sys::soundmode_t_soundmode_16bit_stereo_11025,
Stereo16Bit16000 = dos_like_sys::soundmode_t_soundmode_16bit_stereo_16000,
Stereo16Bit22050 = dos_like_sys::soundmode_t_soundmode_16bit_stereo_22050,
Stereo16Bit32000 = dos_like_sys::soundmode_t_soundmode_16bit_stereo_32000,
Stereo16Bit44100 = dos_like_sys::soundmode_t_soundmode_16bit_stereo_44100,
}
pub fn set_sound_mode(sound_mode: SoundMode) {
unsafe {
dos_like_sys::setsoundmode(sound_mode as c_uint);
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct Sound(NonNull<sound_t>);
impl Sound {
#[inline]
pub fn load_wav(path: impl AsRef<str>) -> Result<Sound, FileError> {
load_wav(path)
}
#[inline]
pub fn create_sound(channels: u32, sample_rate: u32, samples: &[u16]) -> Sound {
create_sound(channels, sample_rate, samples)
}
#[inline]
pub fn play(&self, channel: u8, loop_: bool, volume: u8) {
play_sound(channel, self, loop_, volume);
}
}
unsafe impl Send for Sound {}
pub fn load_wav(path: impl AsRef<str>) -> Result<Sound, FileError> {
let path = CString::new(path.as_ref()).map_err(|_| FileError::BadFilePath)?;
let p = unsafe { dos_like_sys::loadwav(path.as_ptr() as *const _) };
if let Some(p) = NonNull::new(p) {
Ok(Sound(p))
} else {
Err(FileError::FileNotFound)
}
}
#[inline]
pub fn create_sound(channels: u32, sample_rate: u32, samples: &[u16]) -> Sound {
try_create_sound(channels, sample_rate, samples).expect("Invalid sound parameters")
}
pub fn try_create_sound(channels: u32, sample_rate: u32, samples: &[u16]) -> Option<Sound> {
unsafe {
let sound = dos_like_sys::createsound(
channels as c_int,
sample_rate as c_int,
samples.len() as c_int,
samples.as_ptr() as *mut c_short,
);
NonNull::new(sound).map(Sound)
}
}
pub fn play_sound(channel: u8, sound: &Sound, loop_: bool, volume: u8) {
unsafe {
dos_like_sys::playsound(
channel as c_int,
sound.0.as_ptr(),
loop_ as c_int,
volume as c_int,
);
}
}
pub fn stop_sound(channel: u8) {
unsafe {
dos_like_sys::stopsound(channel as c_int);
}
}
pub fn is_sound_playing(channel: u8) -> bool {
unsafe { dos_like_sys::soundplaying(channel as c_int) != 0 }
}
pub fn set_sound_volume(channel: u8, left: u8, right: u8) {
unsafe {
dos_like_sys::soundvolume(channel as c_int, left as c_int, right as c_int);
}
}