use libfmod::ffi::{
FMOD_DSP_PARAMETER_DESC_FLOAT, FMOD_DSP_PARAMETER_DESC_UNION, FMOD_DSP_STATE, FMOD_INIT_NORMAL,
FMOD_LOOP_NORMAL, FMOD_OK, FMOD_RESULT,
};
use libfmod::{DspDescription, DspParameterDesc, DspParameterType, Error, System};
use std::os::raw::{c_char, c_float, c_int};
use std::ptr::null_mut;
use std::thread;
use std::time::Duration;
#[test]
fn test_system_advanced_settings_before_init() -> Result<(), Error> {
let system = System::create()?;
let settings = system.get_advanced_settings()?;
println!("Settings: {:?}", settings);
system.release()
}
#[test]
fn test_dsp_custom() -> Result<(), Error> {
let system = System::create()?;
system.init(32, FMOD_INIT_NORMAL, None)?;
let sound = system.create_sound("./tests/data/Assets/1.ogg", FMOD_LOOP_NORMAL, None)?;
system.play_sound(sound, None, false)?;
let volume_desc = DspParameterDesc {
type_: DspParameterType::Float,
name: name16("volume"),
label: name16("%"),
description: "linear volume in percent".to_string(),
union: FMOD_DSP_PARAMETER_DESC_UNION {
floatdesc: FMOD_DSP_PARAMETER_DESC_FLOAT {
min: 0.0,
max: 1.0,
defaultval: 0.42,
mapping: Default::default(),
},
},
};
let other_desc = DspParameterDesc {
type_: DspParameterType::Float,
name: name16("other"),
label: name16("%"),
description: "linear value in percent".to_string(),
union: FMOD_DSP_PARAMETER_DESC_UNION {
floatdesc: FMOD_DSP_PARAMETER_DESC_FLOAT {
min: 0.0,
max: 1.0,
defaultval: 0.42,
mapping: Default::default(),
},
},
};
struct MyDspData {
volume: f32,
other: f32,
}
unsafe extern "C" fn create_callback(dsp_state: *mut FMOD_DSP_STATE) -> FMOD_RESULT {
let data = Box::new(MyDspData {
volume: 1.0,
other: 0.0,
});
(*dsp_state).plugindata = Box::into_raw(data) as *mut _;
FMOD_OK
}
unsafe extern "C" fn set_parameter_float_callback(
dsp_state: *mut FMOD_DSP_STATE,
index: c_int,
value: c_float,
) -> FMOD_RESULT {
let data = &mut *((*dsp_state).plugindata as *mut MyDspData);
match index {
0 => data.volume = value,
1 => data.other = value,
_ => unreachable!(),
}
FMOD_OK
}
unsafe extern "C" fn get_parameter_float_callback(
dsp_state: *mut FMOD_DSP_STATE,
index: c_int,
value: *mut c_float,
_valuestr: *mut c_char,
) -> FMOD_RESULT {
let data = (*dsp_state).plugindata as *mut MyDspData;
let data = match index {
0 => (*data).volume,
1 => (*data).other,
_ => unreachable!(),
};
value.write(data);
FMOD_OK
}
let dspdesc = DspDescription {
pluginsdkversion: 0,
name: name32("My first DSP unit"),
version: 0x00010000,
numinputbuffers: 1,
numoutputbuffers: 1,
create: Some(create_callback),
release: None,
reset: None,
read: None,
process: None,
setposition: None,
paramdesc: vec![volume_desc, other_desc],
setparameterfloat: Some(set_parameter_float_callback),
setparameterint: None,
setparameterbool: None,
setparameterdata: None,
getparameterfloat: Some(get_parameter_float_callback),
getparameterint: None,
getparameterbool: None,
getparameterdata: None,
shouldiprocess: None,
userdata: null_mut(),
sys_register: None,
sys_deregister: None,
sys_mix: None,
};
let mydsp = system.create_dsp(dspdesc)?;
let mastergroup = system.get_master_channel_group()?;
mastergroup.add_dsp(0, mydsp)?;
for step in 0..5 {
match step {
1 => {
mydsp.set_bypass(true)?;
}
2 => {
mydsp.set_bypass(false)?;
}
3 => {
mydsp.set_parameter_float(0, 0.25)?;
}
4 => {
mydsp.set_parameter_float(1, 0.75)?;
}
_ => {}
}
thread::sleep(Duration::from_millis(100))
}
let info = mydsp.get_parameter_info(0)?;
let volume_value_default = unsafe { info.union.floatdesc.defaultval };
let (volume_value, _) = mydsp.get_parameter_float(0, 0)?;
assert_eq!(volume_value_default, 0.42, "volume default value");
assert_eq!(volume_value, 0.25, "volume value");
assert_eq!(info.description, "linear volume in percent", "description");
let info = mydsp.get_parameter_info(1)?;
let (other_value, _) = mydsp.get_parameter_float(1, 0)?;
assert_eq!(other_value, 0.75, "other value");
assert_eq!(info.description, "linear value in percent", "description");
let (name, version, _, _, _) = mydsp.get_info()?;
assert_eq!(name, "My first DSP unit", "dsp info name");
assert_eq!(version, 0x00010000, "dsp info version");
system.release()
}
#[test]
pub fn test_channel_group_get_name() -> Result<(), Error> {
let system = System::create()?;
system.init(32, FMOD_INIT_NORMAL, None)?;
let group = system.get_master_channel_group()?;
let name_5 = group.get_name(5)?;
let name_100 = group.get_name(100)?;
assert_eq!(name_5, "FMOD", "name 5");
assert_eq!(name_100, "FMOD master", "name 100");
system.release()
}
#[test]
pub fn test_get_driver_info() -> Result<(), Error> {
let system = System::create()?;
system.init(32, FMOD_INIT_NORMAL, None)?;
let info = system.get_driver_info(0, 100)?;
println!("info: {:?}", info);
system.release()
}
fn name16(name: &str) -> [i8; 16] {
let mut output = [0; 16];
for (i, ch) in name.as_bytes().iter().enumerate() {
output[i] = *ch as i8;
}
output
}
fn name32(name: &str) -> [i8; 32] {
let mut output = [0; 32];
for (i, ch) in name.as_bytes().iter().enumerate() {
output[i] = *ch as i8;
}
output
}