From 4d40f855eabe09d88e4e305b3d53b4f8da295b31 Mon Sep 17 00:00:00 2001 From: GitGhillie Date: Wed, 4 Sep 2024 22:01:26 +0200 Subject: [PATCH] Fixed, but for real this time --- crates/phonon-fmod/Cargo.toml | 7 +- crates/phonon-fmod/examples/create_dsp.rs | 4 +- crates/phonon-fmod/examples/playground.rs | 153 ++++++++++++++++++++ crates/phonon-fmod/src/lib.rs | 167 ++++++++++++++-------- 4 files changed, 269 insertions(+), 62 deletions(-) create mode 100644 crates/phonon-fmod/examples/playground.rs diff --git a/crates/phonon-fmod/Cargo.toml b/crates/phonon-fmod/Cargo.toml index bee893f..fc47992 100644 --- a/crates/phonon-fmod/Cargo.toml +++ b/crates/phonon-fmod/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["cdylib", "lib"] [dependencies] phonon = { path = "../phonon" } -libfmod = "~2.222.3" +libfmod = "~2.222.4" glam = "0.25" # todo how do we ensure the same version is used accross the different crates in the workspace? lazy_static = "1.5" #libfmod = { path = "../../../libfmod/libfmod" } @@ -20,4 +20,7 @@ lazy_static = "1.5" name = "manual_registration" [[example]] -name = "create_dsp" \ No newline at end of file +name = "create_dsp" + +[[example]] +name = "playground" \ No newline at end of file diff --git a/crates/phonon-fmod/examples/create_dsp.rs b/crates/phonon-fmod/examples/create_dsp.rs index 73e66d7..01c7b23 100644 --- a/crates/phonon-fmod/examples/create_dsp.rs +++ b/crates/phonon-fmod/examples/create_dsp.rs @@ -21,7 +21,7 @@ fn main() -> Result<(), Error> { let sound = system.create_sound("./data/audio/windless_slopes.ogg", FMOD_LOOP_NORMAL, None)?; system.play_sound(sound, None, false)?; - let desc = DspDescription::try_from(create_dsp_description())?; + let desc = create_dsp_description(); let mydsp = system.create_dsp(desc)?; let mastergroup = system.get_master_channel_group()?; mastergroup.add_dsp(0, mydsp)?; @@ -39,7 +39,7 @@ fn main() -> Result<(), Error> { let mut attributes = FMOD_DSP_PARAMETER_3DATTRIBUTES { relative: FMOD_3D_ATTRIBUTES { position: FMOD_VECTOR { - x: -3.0, + x: -20.0, y: 0.0, z: 0.0, }, diff --git a/crates/phonon-fmod/examples/playground.rs b/crates/phonon-fmod/examples/playground.rs new file mode 100644 index 0000000..2ea7269 --- /dev/null +++ b/crates/phonon-fmod/examples/playground.rs @@ -0,0 +1,153 @@ +use std::os::raw::{c_char, c_float, c_int}; +use std::ptr::null_mut; + +use libfmod::ffi::{ + FMOD_Debug_Initialize, FMOD_DEBUG_LEVEL_LOG, FMOD_DEBUG_MODE, FMOD_DEBUG_MODE_TTY, + 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}; + +fn main() -> Result<(), Error> { + unsafe { + FMOD_Debug_Initialize(FMOD_DEBUG_LEVEL_LOG, FMOD_DEBUG_MODE_TTY, None, null_mut()); + } + + let system = System::create()?; + system.init(32, FMOD_INIT_NORMAL, None)?; + + let sound = system.create_sound("./data/audio/windless_slopes.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: 1.0, + mapping: Default::default(), + }, + }, + }; + + let other_desc = DspParameterDesc { + type_: DspParameterType::Float, + name: name16("woah"), + label: name16("%"), + description: "aaaaaaaa".to_string(), + union: FMOD_DSP_PARAMETER_DESC_UNION { + floatdesc: FMOD_DSP_PARAMETER_DESC_FLOAT { + min: 0.0, + max: 1.0, + defaultval: 1.0, + mapping: Default::default(), + }, + }, + }; + + struct MyDspData { + volume: f32, + } + + unsafe extern "C" fn create_callback(dsp_state: *mut FMOD_DSP_STATE) -> FMOD_RESULT { + let data = Box::new(MyDspData { volume: 1.0 }); + (*dsp_state).plugindata = Box::into_raw(data) as *mut MyDspData 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 = (*dsp_state).plugindata as *mut MyDspData; + (*data).volume = value; + 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; + value.write((*data).volume); + 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], + 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 => { + let (value, _) = mydsp.get_parameter_float(0, 0)?; + println!("volume: {}", value); + } + _ => {} + } + } + let info = mydsp.get_parameter_info(0)?; + println!("default: {}", unsafe { info.union.floatdesc.defaultval }); + + 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 +} diff --git a/crates/phonon-fmod/src/lib.rs b/crates/phonon-fmod/src/lib.rs index 5bcbb3e..c8cb440 100644 --- a/crates/phonon-fmod/src/lib.rs +++ b/crates/phonon-fmod/src/lib.rs @@ -30,17 +30,19 @@ use libfmod::ffi::{ FMOD_DSP_DESCRIPTION, FMOD_DSP_PAN_3D_ROLLOFF_TYPE, FMOD_DSP_PARAMETER_3DATTRIBUTES, FMOD_DSP_PARAMETER_ATTENUATION_RANGE, FMOD_DSP_PARAMETER_DATA_TYPE, FMOD_DSP_PARAMETER_DATA_TYPE_3DATTRIBUTES, FMOD_DSP_PARAMETER_DATA_TYPE_OVERALLGAIN, - FMOD_DSP_PARAMETER_DESC, FMOD_DSP_PARAMETER_DESC_DATA, FMOD_DSP_PARAMETER_DESC_INT, - FMOD_DSP_PARAMETER_DESC_UNION, FMOD_DSP_PARAMETER_OVERALLGAIN, FMOD_DSP_PARAMETER_TYPE_DATA, - FMOD_DSP_PARAMETER_TYPE_INT, FMOD_PLUGIN_SDK_VERSION, + FMOD_DSP_PARAMETER_DESC, FMOD_DSP_PARAMETER_DESC_DATA, FMOD_DSP_PARAMETER_DESC_FLOAT, + FMOD_DSP_PARAMETER_DESC_INT, FMOD_DSP_PARAMETER_DESC_UNION, FMOD_DSP_PARAMETER_OVERALLGAIN, + FMOD_DSP_PARAMETER_TYPE_DATA, FMOD_DSP_PARAMETER_TYPE_INT, FMOD_PLUGIN_SDK_VERSION, }; +use libfmod::{DspDescription, DspParameterDesc, DspParameterType}; use phonon::audio_buffer::AudioBuffer; use phonon::direct_effect::{DirectEffect, TransmissionType}; use phonon::panning_effect::{PanningEffect, PanningEffectParameters}; use std::cell::UnsafeCell; use std::ffi::CString; +use std::mem; use std::os::raw::{c_char, c_int}; -use std::ptr::null_mut; +use std::ptr::{addr_of_mut, null_mut}; #[derive(Copy, Clone)] enum ParameterApplyType { @@ -137,77 +139,127 @@ fn create_param_data( name: &str, description: &'static str, datatype: FMOD_DSP_PARAMETER_DATA_TYPE, -) -> FMOD_DSP_PARAMETER_DESC { - FMOD_DSP_PARAMETER_DESC { - type_: FMOD_DSP_PARAMETER_TYPE_DATA, +) -> DspParameterDesc { + DspParameterDesc { + type_: DspParameterType::Data, name: str_to_c_char_array(name), label: str_to_c_char_array(""), - description: description.as_ptr() as *const c_char, + description: description.to_string(), union: FMOD_DSP_PARAMETER_DESC_UNION { datadesc: FMOD_DSP_PARAMETER_DESC_DATA { datatype }, }, } } +fn create_param_float(name: &str, description: &'static str) -> DspParameterDesc { + DspParameterDesc { + type_: DspParameterType::Float, + name: str_to_c_char_array(name), + label: str_to_c_char_array("%"), + description: description.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(), + }, + }, + } +} + fn create_param_int( name: &str, description: &'static str, - value_names: &'static [&'static str; 3], -) -> FMOD_DSP_PARAMETER_DESC { - FMOD_DSP_PARAMETER_DESC { - type_: FMOD_DSP_PARAMETER_TYPE_INT, + value_names: Vec<&'static str>, +) -> DspParameterDesc { + let value_names_c: Vec<*mut c_char> = value_names + .into_iter() + .map(|value_name| { + CString::new(value_name) + .unwrap_or(CString::from(c"err!")) + .into_raw() + }) + .collect(); + + DspParameterDesc { + type_: DspParameterType::Int, name: str_to_c_char_array(name), - label: str_to_c_char_array("aa"), - description: description.as_ptr() as *const c_char, + label: str_to_c_char_array(""), + description: description.to_string(), union: FMOD_DSP_PARAMETER_DESC_UNION { intdesc: FMOD_DSP_PARAMETER_DESC_INT { min: 0, max: 2, defaultval: 0, goestoinf: 0, - valuenames: value_names.as_ptr() as *const *const c_char, + valuenames: Box::into_raw(value_names_c.into_boxed_slice()) as *const *const c_char, }, }, } } -struct MyStatic { - parameters: UnsafeCell<[*mut FMOD_DSP_PARAMETER_DESC; 2]>, - source: UnsafeCell, - apply_da: UnsafeCell, -} -unsafe impl Sync for MyStatic {} - -lazy_static! { - static ref PARAMETERS: MyStatic = MyStatic { - parameters: UnsafeCell::new([null_mut(), null_mut()]), - source: UnsafeCell::new(FMOD_DSP_PARAMETER_DESC::default()), - apply_da: UnsafeCell::new(FMOD_DSP_PARAMETER_DESC::default()), - }; -} - -fn init_my_static() { - unsafe { - *PARAMETERS.source.get() = create_param_data( - "SourcePos", - "Position of the source.\0", - FMOD_DSP_PARAMETER_DATA_TYPE_3DATTRIBUTES, - ); - - *PARAMETERS.apply_da.get() = create_param_int( - "ApplyDA", - "Apply distance attenuation.\0", - &["Off", "Physics-Based", "Curve-Driven"], - ); - - *PARAMETERS.parameters.get() = [PARAMETERS.source.get(), PARAMETERS.apply_da.get()]; - } -} - -pub fn create_dsp_description() -> FMOD_DSP_DESCRIPTION { - init_my_static(); - - FMOD_DSP_DESCRIPTION { +// fn create_param_data( +// name: &str, +// description: &'static str, +// datatype: FMOD_DSP_PARAMETER_DATA_TYPE, +// ) -> FMOD_DSP_PARAMETER_DESC { +// FMOD_DSP_PARAMETER_DESC { +// type_: FMOD_DSP_PARAMETER_TYPE_DATA, +// name: str_to_c_char_array(name), +// label: str_to_c_char_array(""), +// description: description.as_ptr() as *const c_char, +// union: FMOD_DSP_PARAMETER_DESC_UNION { +// datadesc: FMOD_DSP_PARAMETER_DESC_DATA { datatype }, +// }, +// } +// } +// +// fn create_param_int( +// name: &str, +// description: &'static str, +// value_names: &'static [&'static str; 3], +// ) -> FMOD_DSP_PARAMETER_DESC { +// FMOD_DSP_PARAMETER_DESC { +// type_: FMOD_DSP_PARAMETER_TYPE_INT, +// name: str_to_c_char_array(name), +// label: str_to_c_char_array("aa"), +// description: description.as_ptr() as *const c_char, +// union: FMOD_DSP_PARAMETER_DESC_UNION { +// intdesc: FMOD_DSP_PARAMETER_DESC_INT { +// min: 0, +// max: 2, +// defaultval: 0, +// goestoinf: 0, +// valuenames: value_names.as_ptr() as *const *const c_char, +// }, +// }, +// } +// } + +pub fn create_dsp_description() -> DspDescription { + let param_source = create_param_data( + "SourcePos", + "Position of the source.", + FMOD_DSP_PARAMETER_DATA_TYPE_3DATTRIBUTES, + ); + + let param_da = create_param_int( + "ApplyDA", + "Apply distance attenuation.", + vec!["Off", "Physics-Based", "Curve-Driven"], + ); + + let param_float = create_param_float("volume", "Linear volume."); + let param_float2 = create_param_float("volumee", "Linear volume."); + + // let paramdesc: Box<[FMOD_DSP_PARAMETER_DESC]> = + // Box::new([param_source.into(), param_da.into()]); + // let paramdesc: Box<[FMOD_DSP_PARAMETER_DESC]> = Box::new([param_source]); + // let paramdesc: *mut [FMOD_DSP_PARAMETER_DESC] = Box::into_raw(paramdesc); + // mem::forget(paramdesc); + + DspDescription { pluginsdkversion: FMOD_PLUGIN_SDK_VERSION, name: str_to_c_char_array("Phonon Spatializer"), version: 1, @@ -219,8 +271,8 @@ pub fn create_dsp_description() -> FMOD_DSP_DESCRIPTION { read: None, process: Some(process_callback), setposition: None, - numparameters: 2, - paramdesc: PARAMETERS.parameters.get() as *mut *mut FMOD_DSP_PARAMETER_DESC, + //numparameters: 1, + paramdesc: vec![param_source, param_da, param_float, param_float2], setparameterfloat: None, setparameterint: Some(set_int_callback), setparameterbool: None, //todo @@ -241,10 +293,9 @@ pub fn create_dsp_description() -> FMOD_DSP_DESCRIPTION { /// See https://fmod.com/docs/2.02/api/white-papers-dsp-plugin-api.html#building-a-plug-in #[no_mangle] extern "C" fn FMODGetDSPDescription() -> *mut FMOD_DSP_DESCRIPTION { - unsafe { - let desc = Box::new(create_dsp_description()); - Box::into_raw(desc) - } + let description: FMOD_DSP_DESCRIPTION = create_dsp_description().into(); + let boxed = Box::new(description); + Box::into_raw(boxed) } fn str_to_c_char_array(input: &str) -> [c_char; LEN] {