use std::{self, rc::Rc};
use log;
use riff_wave;
use num_derive::FromPrimitive;
use crate::{ll, fmod_result, dsp, reverb3d, sound, vector, ChannelGroup,
ChannelGroupRef, CpuUsage, DriverState, Dsp, Error, Guid, ListenerAttributes,
Mode, PluginHandle, Plugintype, Reverb3d, Sound, SoundRam, Speaker,
Speakermode, Timeunit};
static FMOD_SYSTEM_CREATE_DESTROY_MUTEX : std::sync::LazyLock <std::sync::Mutex <()>> =
std::sync::LazyLock::new (std::sync::Mutex::default);
#[derive(Clone, Debug, PartialEq)]
pub struct System {
inner : Rc <Inner>
}
#[derive(PartialEq)]
struct Inner (*mut ll::FMOD_SYSTEM);
#[derive(Debug)]
pub struct DriverInfo {
pub name : String,
pub guid : Guid,
pub systemrate : i32,
pub speakermode : Speakermode,
pub speakermodechannels : i32
}
bitflags!{
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
pub struct CallbackType : u32 {
const DEVICELISTCHANGED = ll::FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED;
const DEVICELOST = ll::FMOD_SYSTEM_CALLBACK_DEVICELOST;
const MEMORYALLOCATIONFAILED = ll::FMOD_SYSTEM_CALLBACK_MEMORYALLOCATIONFAILED;
const THREADCREATED = ll::FMOD_SYSTEM_CALLBACK_THREADCREATED;
const BADDSPCONNECTION = ll::FMOD_SYSTEM_CALLBACK_BADDSPCONNECTION;
const PREMIX = ll::FMOD_SYSTEM_CALLBACK_PREMIX;
const POSTMIX = ll::FMOD_SYSTEM_CALLBACK_POSTMIX;
const ERROR = ll::FMOD_SYSTEM_CALLBACK_ERROR;
const MIDMIX = ll::FMOD_SYSTEM_CALLBACK_MIDMIX;
const THREADDESTROYED = ll::FMOD_SYSTEM_CALLBACK_THREADDESTROYED;
const PREUPDATE = ll::FMOD_SYSTEM_CALLBACK_PREUPDATE;
const POSTUPDATE = ll::FMOD_SYSTEM_CALLBACK_POSTUPDATE;
const RECORDLISTCHANGED = ll::FMOD_SYSTEM_CALLBACK_RECORDLISTCHANGED;
const ALL = ll::FMOD_SYSTEM_CALLBACK_ALL;
}
}
bitflags!{
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
pub struct Initflags : u32 {
const NORMAL = ll::FMOD_INIT_NORMAL;
const STREAM_FROM_UPDATE = ll::FMOD_INIT_STREAM_FROM_UPDATE;
const MIX_FROM_UPDATE = ll::FMOD_INIT_MIX_FROM_UPDATE;
const _3D_RIGHTHANDED = ll::FMOD_INIT_3D_RIGHTHANDED;
const CHANNEL_LOWPASS = ll::FMOD_INIT_CHANNEL_LOWPASS;
const CHANNEL_DISTANCEFILTER = ll::FMOD_INIT_CHANNEL_DISTANCEFILTER;
const PROFILE_ENABLE = ll::FMOD_INIT_PROFILE_ENABLE;
const VOL0_BECOMES_VIRTUAL = ll::FMOD_INIT_VOL0_BECOMES_VIRTUAL;
const GEOMETRY_USECLOSEST = ll::FMOD_INIT_GEOMETRY_USECLOSEST;
const PREFER_DOLBY_DOWNMIX = ll::FMOD_INIT_PREFER_DOLBY_DOWNMIX;
const THREAD_UNSAFE = ll::FMOD_INIT_THREAD_UNSAFE;
const PROFILE_METER_ALL = ll::FMOD_INIT_PROFILE_METER_ALL;
const DISABLE_SRS_HIGHPASSFILTER = ll::FMOD_INIT_DISABLE_SRS_HIGHPASSFILTER;
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, FromPrimitive)]
pub enum Outputtype {
Autodetect = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_AUTODETECT as isize,
Unknown = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_UNKNOWN as isize,
Nosound = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_NOSOUND as isize,
Wavwriter = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WAVWRITER as isize,
NosoundNrt = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_NOSOUND_NRT as isize,
WavwriterNrt = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WAVWRITER_NRT as isize,
Dsound = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_DSOUND as isize,
Winmm = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WINMM as isize,
Wasapi = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WASAPI as isize,
Asio = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_ASIO as isize,
Pulseaudio = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_PULSEAUDIO as isize,
Alsa = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_ALSA as isize,
Coreaudio = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_COREAUDIO as isize,
Xaudio = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_XAUDIO as isize,
Ps3 = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_PS3 as isize,
Audiotrack = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_AUDIOTRACK as isize,
Opensl = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_OPENSL as isize,
Wiiu = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WIIU as isize,
Audioout = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_AUDIOOUT as isize,
Audio3d = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_AUDIO3D as isize,
Atmos = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_ATMOS as isize,
Webaudio = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WEBAUDIO as isize,
Nnaudio = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_NNAUDIO as isize,
Winsonic = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WINSONIC as isize,
MAX = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_MAX as isize
}
impl System {
#[inline]
#[expect(clippy::should_implement_trait)]
pub fn default() -> Result <Self, Error> {
Self::new (None, 256, Initflags::NORMAL)
}
#[inline]
pub fn new (
num_software_channels : Option <u16>,
num_virtual_channels : u16,
initflags : Initflags
) -> Result <Self, Error> {
let mut system = Self::create()?;
if let Some (n) = num_software_channels {
system.set_software_channels (n as i32)?;
}
#[cfg(not(target_os = "windows"))]
system.set_output (Outputtype::Alsa)?;
system.init (num_virtual_channels, initflags)?;
Ok (system)
}
#[inline]
fn raw (&self) -> *mut ll::FMOD_SYSTEM {
self.inner.0
}
#[inline]
#[expect(clippy::needless_pass_by_ref_mut)]
pub (crate) fn raw_mut (&mut self) -> *mut ll::FMOD_SYSTEM {
self.inner.0
}
#[inline]
pub fn update (&mut self) -> Result <(), Error> {
unsafe {
fmod_result!(ll::FMOD_System_Update (self.raw()))
}
}
#[inline]
pub fn get_3d_listener_attributes (&self, listener : i32)
-> Result <ListenerAttributes, Error>
{
let zero = ll::FMOD_VECTOR { x: 0.0, y: 0.0, z: 0.0 };
let mut pos = zero;
let mut vel = zero;
let mut forward = zero;
let mut up = zero;
unsafe {
fmod_result!(
ll::FMOD_System_Get3DListenerAttributes (
self.raw(), listener, &mut pos, &mut vel, &mut forward, &mut up)
)?;
}
let listener_attributes =
ListenerAttributes::from_ll (pos, vel, forward, up);
Ok (listener_attributes)
}
#[inline]
pub fn get_3d_num_listeners (&self) -> Result <i32, Error> {
let mut numlisteners = 0;
unsafe {
fmod_result!(ll::FMOD_System_Get3DNumListeners (
self.raw(), &mut numlisteners)
)?;
}
Ok (numlisteners)
}
#[inline]
pub fn get_3d_settings (&self) -> Result <(f32, f32, f32), Error> {
let mut dopplerscale = 0.0;
let mut distancefactor = 0.0;
let mut rolloffscale = 0.0;
unsafe {
fmod_result!(ll::FMOD_System_Get3DSettings (
self.raw(), &mut dopplerscale, &mut distancefactor, &mut rolloffscale)
)?;
}
Ok ((dopplerscale, distancefactor, rolloffscale))
}
#[inline]
pub fn get_channels_playing (&self) -> Result <(i32, i32), Error> {
let mut channels = 0;
let mut realchannels = 0;
unsafe {
fmod_result!(
ll::FMOD_System_GetChannelsPlaying (
self.raw(), &mut channels, &mut realchannels)
)?;
}
Ok ((channels, realchannels))
}
#[inline]
pub fn get_cpu_usage (&self) -> Result <CpuUsage, Error> {
let mut usage = CpuUsage::default();
unsafe {
fmod_result!(
ll::FMOD_System_GetCPUUsage (
self.raw(),
&mut usage.dsp,
&mut usage.stream,
&mut usage.geometry,
&mut usage.update,
&mut usage.total)
)?;
}
Ok (usage)
}
#[inline]
pub fn get_driver (&self) -> Result <i32, Error> {
let mut driver = 0;
unsafe {
fmod_result!(ll::FMOD_System_GetDriver (self.raw(), &mut driver))?;
}
Ok (driver)
}
#[inline]
pub fn get_driver_info (&self, id : i32) -> Result <DriverInfo, Error> {
let name_len = 256i32;
#[expect(clippy::cast_sign_loss)]
let mut name = vec![0; name_len as usize];
let mut guid = ll::FMOD_GUID {
Data1: 0, Data2: 0, Data3: 0, Data4: [0; 8]
};
let mut systemrate = 0;
let mut speakermode = 0;
let mut speakermodechannels = 0;
unsafe {
use std::os::raw;
fmod_result!(ll::FMOD_System_GetDriverInfo (
self.raw(),
id as raw::c_int,
name.as_mut_ptr() as *mut raw::c_char,
name_len as raw::c_int,
&mut guid,
&mut systemrate,
&mut speakermode,
&mut speakermodechannels
))?;
}
let name = {
name.retain (|c| *c != 0x0);
String::from_utf8 (name).map_err (|e|{
log::error!("system driver name string invalid utf8: {e}");
Error::InvalidString
})?
};
let guid = Guid::from (guid);
let speakermode = Speakermode::from_ll (speakermode);
let info = DriverInfo {
name, guid, systemrate, speakermode, speakermodechannels
};
Ok (info)
}
#[inline]
pub fn get_dsp_buffer_size (&self) -> Result <(u32, i32), Error> {
let mut bufferlength = 0;
let mut numbuffers = 0;
unsafe {
fmod_result!(
ll::FMOD_System_GetDSPBufferSize (
self.raw(), &mut bufferlength, &mut numbuffers)
)?;
}
Ok ((bufferlength, numbuffers))
}
#[inline]
pub fn get_geometry_occlusion (&self, listener : [f32; 3], source : [f32; 3])
-> Result <(f32, f32), Error>
{
let listener = vector::to_ll (listener);
let source = vector::to_ll (source);
let mut direct = 0.0;
let mut reverb = 0.0;
unsafe {
fmod_result!(
ll::FMOD_System_GetGeometryOcclusion (self.raw(),
&listener, &source, &mut direct, &mut reverb)
)?;
}
Ok ((direct, reverb))
}
#[inline]
pub fn get_geometry_settings (&self) -> Result <f32, Error> {
let mut maxworldsize = 0.0;
unsafe {
fmod_result!(
ll::FMOD_System_GetGeometrySettings (self.raw(), &mut maxworldsize)
)?;
}
Ok (maxworldsize)
}
#[inline]
pub fn get_master_channel_group (&self) -> Result <ChannelGroupRef, Error> {
let mut raw = std::ptr::null_mut();
unsafe {
fmod_result!(
ll::FMOD_System_GetMasterChannelGroup (self.raw(), &mut raw)
)?;
}
let channel_group =
ChannelGroup::from_raw_parts (raw, false, self.clone());
Ok (ChannelGroupRef { channel_group })
}
#[inline]
pub fn get_num_drivers (&self) -> Result <i32, Error> {
let mut numdrivers = 0;
unsafe {
fmod_result!(ll::FMOD_System_GetNumDrivers (self.raw(), &mut numdrivers))?;
}
Ok (numdrivers)
}
#[inline]
pub fn get_num_plugins (&self, plugintype : Plugintype)
-> Result <i32, Error>
{
let mut numplugins = 0;
unsafe {
fmod_result!(ll::FMOD_System_GetNumPlugins (
self.raw(), plugintype as ll::FMOD_PLUGINTYPE, &mut numplugins)
)?;
}
Ok (numplugins)
}
#[inline]
pub fn get_output (&self) -> Result <Outputtype, Error> {
let mut outputtype = 0;
unsafe {
fmod_result!(ll::FMOD_System_GetOutput (self.raw(), &mut outputtype))?;
}
Ok (Outputtype::from_ll (outputtype))
}
#[inline]
pub fn get_output_by_plugin (&self) -> Result <PluginHandle, Error> {
let mut handle = 0;
unsafe {
fmod_result!(ll::FMOD_System_GetOutputByPlugin (self.raw(), &mut handle))?;
}
Ok (PluginHandle (handle))
}
#[inline]
pub fn get_record_driver_info (&self, id : i32)
-> Result <(DriverInfo, DriverState), Error>
{
let name_len = 256i32;
#[expect(clippy::cast_sign_loss)]
let mut name = vec![0; name_len as usize];
let mut guid = ll::FMOD_GUID {
Data1: 0, Data2: 0, Data3: 0, Data4: [0; 8]
};
let mut systemrate = 0;
let mut speakermode = 0;
let mut speakermodechannels = 0;
let mut state = 0;
unsafe {
use std::os::raw;
fmod_result!(ll::FMOD_System_GetRecordDriverInfo (
self.raw(),
id as raw::c_int,
name.as_mut_ptr() as *mut raw::c_char,
name_len as raw::c_int,
&mut guid,
&mut systemrate,
&mut speakermode,
&mut speakermodechannels,
&mut state
))?;
}
let name = {
name.retain (|c| *c != 0x0);
String::from_utf8 (name).map_err (|e|{
log::error!("system record driver name string invalid utf8: {e}");
Error::InvalidString
})?
};
let guid = Guid::from (guid);
let speakermode = Speakermode::from_ll (speakermode);
let info = DriverInfo {
name, guid, systemrate, speakermode, speakermodechannels
};
let state = DriverState::from_bits (state).ok_or_else (||{
log::error!("system driver state bits not valid: {state:032b}");
Error::InvalidParam
})?;
Ok ((info, state))
}
#[inline]
pub fn get_record_num_drivers (&self) -> Result <(i32, i32), Error> {
let mut numdrivers = 0;
let mut numconnected = 0;
unsafe {
fmod_result!(ll::FMOD_System_GetRecordNumDrivers (
self.raw(), &mut numdrivers, &mut numconnected
))?;
}
Ok ((numdrivers, numconnected))
}
#[inline]
pub fn get_reverb_properties (&self, instance : i32)
-> Result <reverb3d::Properties, Error>
{
let mut properties = ll::FMOD_REVERB_PROPERTIES {
DecayTime: 0.0,
EarlyDelay: 0.0,
LateDelay: 0.0,
HFReference: 0.0,
HFDecayRatio: 0.0,
Diffusion: 0.0,
Density: 0.0,
LowShelfFrequency: 0.0,
LowShelfGain: 0.0,
HighCut: 0.0,
EarlyLateMix: 0.0,
WetLevel: 0.0
};
unsafe {
fmod_result!(
ll::FMOD_System_GetReverbProperties (self.raw(),
instance, &mut properties)
)?;
}
let properties = reverb3d::Properties::from_ll (&properties);
Ok (properties)
}
#[inline]
pub fn get_software_channels (&self) -> Result <i32, Error> {
let mut numsoftwarechannels = 0;
unsafe {
fmod_result!(
ll::FMOD_System_GetSoftwareChannels (
self.raw(), &mut numsoftwarechannels)
)?;
}
Ok (numsoftwarechannels)
}
#[inline]
pub fn get_software_format (&self)
-> Result <(i32, Speakermode, i32), Error>
{
let mut samplerate = 0;
let mut speakermode = 0;
let mut numrawspeakers = 0;
unsafe {
fmod_result!(
ll::FMOD_System_GetSoftwareFormat (
self.raw(), &mut samplerate, &mut speakermode, &mut numrawspeakers)
)?;
}
let speakermode = Speakermode::from_ll (speakermode);
Ok ((samplerate, speakermode, numrawspeakers))
}
#[inline]
pub fn get_sound_ram (&self) -> Result <SoundRam, Error> {
let mut ram = SoundRam::default();
unsafe {
fmod_result!(
ll::FMOD_System_GetSoundRAM (self.raw(),
&mut ram.currentalloced, &mut ram.maxalloced, &mut ram.total)
)?;
}
Ok (ram)
}
#[inline]
pub fn get_speaker_mode_channels (&self, mode : Speakermode)
-> Result <i32, Error>
{
let mut channels = 0;
unsafe {
fmod_result!(
ll::FMOD_System_GetSpeakerModeChannels (
self.raw(), mode as ll::FMOD_SPEAKERMODE, &mut channels)
)?;
}
Ok (channels)
}
#[inline]
pub fn get_speaker_position (&self, speaker : Speaker)
-> Result <(f32, f32, bool), Error>
{
let mut x = 0.0;
let mut y = 0.0;
let mut active = 0;
unsafe {
fmod_result!(
ll::FMOD_System_GetSpeakerPosition (
self.raw(), speaker as ll::FMOD_SPEAKER, &mut x, &mut y, &mut active)
)?;
}
Ok ((x, y, active != 0))
}
#[inline]
pub fn get_stream_buffer_size (&self)
-> Result <(u32, Timeunit), Error>
{
let mut filebuffersize = 0;
let mut filebuffersizetype = 0;
unsafe {
fmod_result!(
ll::FMOD_System_GetStreamBufferSize (
self.raw(), &mut filebuffersize, &mut filebuffersizetype)
)?;
}
let timeunit = Timeunit::from_bits (filebuffersizetype).ok_or_else (||{
log::error!("system stream buffer timeunit bits not valid: \
{filebuffersizetype:032b}");
Error::InvalidParam
})?;
Ok ((filebuffersize, timeunit))
}
#[inline]
pub fn get_version (&self) -> Result <u32, Error> {
let mut version = 0;
unsafe {
fmod_result!(ll::FMOD_System_GetVersion (self.raw(), &mut version))?;
}
Ok (version)
}
#[inline]
pub fn get_version_string (&self) -> Result <String, Error> {
self.get_version().map (crate::version_string)
}
#[inline]
pub fn create_channel_group (&mut self, name : Option <&str>)
-> Result <ChannelGroup, Error>
{
let mut raw = std::ptr::null_mut();
let name_str = name.unwrap_or ("");
let name_string = std::ffi::CString::new (name_str).map_err (|e|{
log::error!("create channel group name \"{name_str}\" contains a null byte: {e}");
Error::InvalidString
})?;
let name_ptr = if name.is_some() {
name_string.as_ptr()
} else {
std::ptr::null()
};
unsafe {
fmod_result!(ll::FMOD_System_CreateChannelGroup (self.raw(), name_ptr, &mut raw))?
}
Ok (ChannelGroup::from_raw_parts (raw, true, self.clone()))
}
#[inline]
pub fn create_dsp (&mut self, description : &'static dsp::Description)
-> Result <Dsp, Error>
{
let mut raw = std::ptr::null_mut();
unsafe {
fmod_result!(
ll::FMOD_System_CreateDSP (self.raw(),
std::ptr::from_ref (description.as_ref()), &mut raw)
)?
}
Ok (Dsp::from_raw_parts (raw, true, self.clone()))
}
#[inline]
pub fn create_dsp_by_type (&mut self, type_ : dsp::Type)
-> Result <Dsp, Error>
{
let mut raw = std::ptr::null_mut();
unsafe {
fmod_result!(
ll::FMOD_System_CreateDSPByType (self.raw(), type_ as ll::FMOD_DSP_TYPE,
&mut raw)
)?;
}
Ok (Dsp::from_raw_parts (raw, true, self.clone()))
}
pub fn create_dsp_sfxreverb (&mut self,
properties : &reverb3d::Properties, dry_level : f32
) -> Result <Dsp, Error> {
let mut raw = std::ptr::null_mut();
unsafe {
fmod_result!(
ll::FMOD_System_CreateDSPByType (
self.raw(),
dsp::Type::Sfxreverb as ll::FMOD_DSP_TYPE,
&mut raw
)
)?;
}
let mut dsp = Dsp::from_raw_parts (raw, true, self.clone());
dsp.set_parameters_sfxreverb (properties, dry_level)?;
Ok (dsp)
}
#[inline]
pub fn create_reverb3d (&mut self) -> Result <Reverb3d, Error> {
let mut raw = std::ptr::null_mut();
unsafe {
fmod_result!(ll::FMOD_System_CreateReverb3D (self.raw(), &mut raw))?;
}
Ok (Reverb3d::from_raw_parts (raw, self.clone()))
}
pub fn create_sound_from_file (&mut self,
filename : &str,
mode : Mode,
exinfo : Option <&mut sound::Createsoundexinfo>
) -> Result <Sound, Error> {
let filename = std::ffi::CString::new (filename).map_err (|e|{
log::error!("create sound filename \"{filename}\" contains a null byte: {e}");
Error::InvalidString
})?;
let mut exinfo = exinfo.map (sound::Createsoundexinfo::to_ll);
let mut raw = std::ptr::null_mut();
unsafe {
fmod_result!(
ll::FMOD_System_CreateSound (
self.raw(),
filename.as_ptr(),
mode.bits(),
exinfo.as_mut().map_or (
std::ptr::null_mut(), std::ptr::from_mut::<ll::FMOD_CREATESOUNDEXINFO>),
&mut raw)
)?;
}
Ok (Sound::from_raw_parts (raw, true, self.clone()))
}
pub fn create_sound_from_memory (&mut self,
data : &[u8],
mut mode : Mode,
exinfo : Option <&mut sound::Createsoundexinfo>
) -> Result <Sound, Error> {
mode |= Mode::OPENMEMORY;
let mut exinfo_default = Default::default();
let mut exinfo = {
let exinfo = exinfo.unwrap_or (&mut exinfo_default);
exinfo.length = u32::try_from (data.len()).map_err (|_|{
log::error!("create sound from memory data too big: {}", data.len());
Error::InvalidParam
})?;
sound::Createsoundexinfo::to_ll (exinfo)
};
let mut raw = std::ptr::null_mut();
let data = if !data.is_empty() {
data.as_ptr() as *const std::os::raw::c_char
} else {
std::ptr::null()
};
unsafe {
fmod_result!(
ll::FMOD_System_CreateSound (
self.raw(),
data,
mode.bits(),
&mut exinfo,
&mut raw)
)?;
}
Ok (Sound::from_raw_parts (raw, true, self.clone()))
}
pub fn create_sound_from_pcm (&mut self,
pcm : &[i16],
mode : Mode,
exinfo : Option <&mut sound::Createsoundexinfo>
) -> Result <Sound, Error> {
const WAV_HEADER_LEN : usize = 44;
let pcm_bytelen = pcm.len() * 2;
let wav_bytelen = WAV_HEADER_LEN + pcm_bytelen;
let mut wav = vec![0; wav_bytelen];
{
let cursor = std::io::Cursor::new (&mut wav);
let writer = std::io::BufWriter::new (cursor);
let mut wav_writer = riff_wave::WaveWriter::new (1, 44100, 16, writer)
.unwrap();
for sample in pcm.iter() {
wav_writer.write_sample_i16 (*sample).unwrap();
}
}
self.create_sound_from_memory (wav.as_slice(), mode, exinfo)
}
#[inline]
pub fn create_sound_from_file_default (&mut self, filename : &str)
-> Result <Sound, Error>
{
self.create_sound_from_file (filename, Mode::DEFAULT, None)
}
#[inline]
pub fn create_sound_from_memory_default (&mut self, data : &[u8])
-> Result <Sound, Error>
{
self.create_sound_from_memory (data, Mode::DEFAULT, None)
}
#[inline]
pub fn create_sound_from_pcm_default (&mut self, pcm : &[i16])
-> Result <Sound, Error>
{
self.create_sound_from_pcm (pcm, Mode::DEFAULT, None)
}
#[inline]
pub fn set_3d_listener_attributes (&mut self,
listener : i32, attributes : &ListenerAttributes
) -> Result <(), Error> {
let pos = vector::to_ll (attributes.pos);
let vel = vector::to_ll (attributes.vel);
let forward = vector::to_ll (attributes.forward);
let up = vector::to_ll (attributes.up);
unsafe {
fmod_result!(
ll::FMOD_System_Set3DListenerAttributes (self.raw(),
listener, &pos, &vel, &forward, &up)
)
}
}
#[inline]
pub fn set_output (&mut self, output : Outputtype) -> Result <(), Error> {
unsafe {
fmod_result!(
ll::FMOD_System_SetOutput (self.raw(), output as ll::FMOD_OUTPUTTYPE))
}
}
#[inline]
pub fn set_reverb_properties (&mut self,
instance : i32, properties : &reverb3d::Properties
) -> Result <(), Error> {
let properties = properties.to_ll();
unsafe {
fmod_result!(
ll::FMOD_System_SetReverbProperties (self.raw(), instance, &properties)
)
}
}
#[inline]
fn create() -> Result <Self, Error> {
let raw = {
let _lock = FMOD_SYSTEM_CREATE_DESTROY_MUTEX.lock().unwrap();
let mut raw = std::ptr::null_mut();
unsafe {
fmod_result!(ll::FMOD_System_Create (&mut raw))?;
}
raw
};
let inner = Rc::new (Inner (raw));
let system = System { inner };
let system_version = system.get_version_string()?;
if system_version != *crate::FMOD_VERSION_STRING {
log::error!(
"FMOD created system got shared library version {:?}, \
bindings were generated for version {:?}",
system_version, *crate::FMOD_VERSION_STRING);
panic!(
"FMOD created system got shared library version {:?}, \
bindings were generated for version {:?}",
system_version, *crate::FMOD_VERSION_STRING);
}
Ok (system)
}
#[inline]
fn init (&mut self, max_channels : u16, init_flags : Initflags)
-> Result <(), Error>
{
let max_channels = max_channels as i32;
unsafe {
fmod_result!(ll::FMOD_System_Init (
self.raw(), max_channels, init_flags.bits(), std::ptr::null_mut()))
}
}
#[inline]
fn set_software_channels (&mut self, numsoftwarechannels : i32)
-> Result <(), Error>
{
unsafe {
fmod_result!(
ll::FMOD_System_SetSoftwareChannels (self.raw(), numsoftwarechannels)
)
}
}
}
impl std::fmt::Debug for Inner {
fn fmt (&self, f : &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:p}", self.0)
}
}
impl Drop for Inner {
fn drop (&mut self) {
let _lock = FMOD_SYSTEM_CREATE_DESTROY_MUTEX.lock().unwrap();
unsafe {
let _ = fmod_result!(ll::FMOD_System_Release (self.0)).map_err (
|err| log::error!("error releasing FMOD System@{:p}: {:?}", self.0, err));
}
}
}
impl From <ll::FMOD_GUID> for Guid {
fn from (guid : ll::FMOD_GUID) -> Self {
Guid {
data1: guid.Data1,
data2: guid.Data2,
data3: guid.Data3,
data4: guid.Data4
}
}
}
impl Outputtype {
pub fn from_ll (ll : ll::FMOD_OUTPUTTYPE) -> Self {
use num_traits::FromPrimitive;
#[allow(clippy::allow_attributes, clippy::unnecessary_cast)]
Self::from_u32 (ll as u32).unwrap()
}
}