use std::{ffi::CString, num::NonZeroU32, os::raw::c_int, ptr::NonNull};
use crate::FileError;
#[derive(Debug)]
pub struct Music(NonNull<dos_like_sys::music_t>);
unsafe impl Send for Music {}
impl Music {
pub fn load_mid(path: impl AsRef<str>) -> Result<Music, FileError> {
let filename = CString::new(path.as_ref()).map_err(|_| FileError::BadFilePath)?;
unsafe {
let music = dos_like_sys::loadmid(filename.as_ptr() as *const _);
if let Some(music) = NonNull::new(music) {
Ok(Music(music))
} else {
Err(FileError::FileNotFound)
}
}
}
pub fn load_mus(path: impl AsRef<str>) -> Result<Music, FileError> {
let filename = CString::new(path.as_ref()).map_err(|_| FileError::BadFilePath)?;
unsafe {
let music = dos_like_sys::loadmus(filename.as_ptr() as *const _);
if let Some(music) = NonNull::new(music) {
Ok(Music(music))
} else {
Err(FileError::FileNotFound)
}
}
}
pub fn load_mod(path: impl AsRef<str>) -> Result<Music, FileError> {
let filename = CString::new(path.as_ref()).map_err(|_| FileError::BadFilePath)?;
unsafe {
let music = dos_like_sys::loadmod(filename.as_ptr() as *const _);
if let Some(music) = NonNull::new(music) {
Ok(Music(music))
} else {
Err(FileError::FileNotFound)
}
}
}
pub fn load_opb(path: impl AsRef<str>) -> Result<Music, FileError> {
let filename = CString::new(path.as_ref()).map_err(|_| FileError::BadFilePath)?;
unsafe {
let music = dos_like_sys::loadopb(filename.as_ptr() as *const _);
if let Some(music) = NonNull::new(music) {
Ok(Music(music))
} else {
Err(FileError::FileNotFound)
}
}
}
#[inline]
pub fn create_mus(data: &[u8]) -> Music {
Music::try_create_mus(data).expect("Invalid MUS data")
}
pub fn try_create_mus(data: &[u8]) -> Option<Music> {
unsafe {
let music = dos_like_sys::createmus(data.as_ptr() as *mut _, data.len() as c_int);
NonNull::new(music).map(Music)
}
}
pub fn play(&self, loop_: bool, volume: u8) {
play_music(self, loop_, volume)
}
}
pub fn play_music(music: &Music, loop_: bool, volume: u8) {
unsafe {
dos_like_sys::playmusic(music.0.as_ptr(), loop_ as c_int, volume as c_int);
}
}
pub fn stop_music() {
unsafe { dos_like_sys::stopmusic() }
}
pub fn is_music_playing() -> bool {
unsafe { dos_like_sys::musicplaying() != 0 }
}
pub fn set_music_volume(volume: u8) {
unsafe { dos_like_sys::musicvolume(volume as i32) }
}
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
#[repr(transparent)]
pub struct Soundbank(NonZeroU32);
impl Soundbank {
pub const DEFAULT_AWE32: Self = Soundbank(
unsafe { NonZeroU32::new_unchecked(dos_like_sys::DEFAULT_SOUNDBANK_AWE32) },
);
pub const DEFAULT_SB16: Self = Soundbank(
unsafe { NonZeroU32::new_unchecked(dos_like_sys::DEFAULT_SOUNDBANK_SB16) },
);
#[inline]
pub fn from_id(id: u32) -> Option<Self> {
Self::from_raw_id(id as c_int)
}
#[inline]
fn from_raw_id(id: c_int) -> Option<Self> {
NonZeroU32::new(id as u32).map(Soundbank)
}
#[inline]
fn to_id(self) -> c_int {
self.0.get() as c_int
}
#[inline]
pub fn install_user_soundbank(filename: impl AsRef<str>) -> Result<Self, FileError> {
install_user_soundbank(filename)
}
#[inline]
pub fn set_soundbank(&self) {
set_soundbank(self);
}
}
pub fn install_user_soundbank(filename: impl AsRef<str>) -> Result<Soundbank, FileError> {
let filename = CString::new(filename.as_ref()).map_err(|_| FileError::BadFilePath)?;
unsafe {
let soundbank_id = dos_like_sys::installusersoundbank(filename.as_ptr() as *const _);
Soundbank::from_id(soundbank_id as u32).ok_or(FileError::FileNotFound)
}
}
#[inline]
pub fn set_soundbank(soundbank: &Soundbank) {
unsafe { dos_like_sys::setsoundbank(soundbank.to_id()) }
}
pub const MUSIC_CHANNELS: u32 = dos_like_sys::MUSIC_CHANNELS;
pub fn note_on(channel: u8, note: u8, velocity: u8) {
unsafe { dos_like_sys::noteon(channel as c_int, note as c_int, velocity as c_int) }
}
pub fn note_off(channel: u8, note: u8) {
unsafe { dos_like_sys::noteoff(channel as c_int, note as c_int) }
}
pub fn all_notes_off(channel: u8) {
unsafe { dos_like_sys::allnotesoff(channel as c_int) }
}
pub fn set_instrument(channel: u8, instrument: u8) {
unsafe { dos_like_sys::setinstrument(channel as c_int, instrument as c_int) }
}