Skip to content

Commit

Permalink
Apply some more Direct Flags from FMOD. Cleanup. (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
GitGhillie authored Sep 21, 2024
1 parent 74d7ef0 commit 27e759d
Show file tree
Hide file tree
Showing 17 changed files with 107 additions and 66 deletions.
49 changes: 39 additions & 10 deletions crates/phonon-fmod/src/callbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,13 @@ use std::ptr::{null_mut, slice_from_raw_parts_mut};
use std::slice;

pub(crate) unsafe extern "C" fn create_callback(dsp_state: *mut FMOD_DSP_STATE) -> FMOD_RESULT {
// todo: I guess the settings frame_size, sampling_rate and speaker_layout could change at
// any time in the other callbacks.

let dsp_state_wrapped = FmodDspState::new(dsp_state);
let frame_size = dsp_state_wrapped.get_block_size().unwrap() as usize;
let sampling_rate = dsp_state_wrapped.get_sample_rate().unwrap();

let audio_settings = AudioSettings::new(sampling_rate, frame_size);
let speaker_layout = SpeakerLayoutType::Stereo; // todo, support mono as well
// todo, support mono as well (don't forget the process callback)
let speaker_layout = SpeakerLayoutType::Stereo;

// why does distance attenuation range seem to exist twice?
let fmod_gain_state = Box::new(EffectState {
Expand Down Expand Up @@ -57,6 +55,7 @@ pub(crate) unsafe extern "C" fn create_callback(dsp_state: *mut FMOD_DSP_STATE)
max: 20.0,
},
attenuation_range_set: false,
audio_settings: audio_settings,
in_buffer_stereo: AudioBuffer::new(frame_size),
in_buffer_mono: AudioBuffer::new(frame_size),
out_buffer: AudioBuffer::new(frame_size),
Expand Down Expand Up @@ -112,10 +111,22 @@ pub(crate) unsafe extern "C" fn process_callback(
let num_channels = *(*in_buffer_array).buffernumchannels as usize;
let num_samples = num_channels * length as usize;

// todo I think these can technically change at any time and that is currently
// not taken into account
let block_size = dsp_state.get_block_size().unwrap();
let sample_rate = dsp_state.get_sample_rate().unwrap();
let new_block_size = dsp_state.get_block_size().unwrap() as usize;
let new_sample_rate = dsp_state.get_sample_rate().unwrap();

let block_size = (*effect_state).audio_settings.frame_size;
let sample_rate = (*effect_state).audio_settings.sampling_rate;

if (new_block_size != block_size) || (new_sample_rate != sample_rate) {
let audio_settings = AudioSettings::new(new_sample_rate, new_block_size);
(*effect_state).in_buffer_stereo = AudioBuffer::new(new_block_size);
(*effect_state).in_buffer_mono = AudioBuffer::new(new_block_size);
(*effect_state).out_buffer = AudioBuffer::new(new_block_size);
(*effect_state).direct_buffer = AudioBuffer::new(new_block_size);
(*effect_state).mono_buffer = AudioBuffer::new(new_block_size);
(*effect_state).direct_effect = DirectEffect::new(audio_settings);
(*effect_state).audio_settings = audio_settings;
}

let inbuf = slice::from_raw_parts(*(*in_buffer_array).buffers, num_samples);
let outbuf = slice::from_raw_parts_mut(*(*out_buffer_array).buffers, num_samples);
Expand All @@ -132,6 +143,7 @@ pub(crate) unsafe extern "C" fn process_callback(

// todo: Check if all set and get callbacks return FMOD_ERR_INVALID_PARAM when the index is unknown

#[expect(dead_code, reason = "No float params have been added yet")]
pub(crate) unsafe extern "C" fn set_float_callback(
dsp_state: *mut FMOD_DSP_STATE,
_index: c_int,
Expand All @@ -143,6 +155,7 @@ pub(crate) unsafe extern "C" fn set_float_callback(
FMOD_OK
}

#[expect(dead_code, reason = "No float params have been added yet")]
pub(crate) unsafe extern "C" fn get_float_callback(
dsp_state: *mut FMOD_DSP_STATE,
_index: c_int,
Expand Down Expand Up @@ -218,6 +231,10 @@ pub(crate) unsafe extern "C" fn set_int_callback(
Params::ApplyDistanceAttenuation => {
data.apply_distance_attenuation = value.into();
}
Params::ApplyAirabsorption => data.apply_air_absorption = value.into(),
Params::ApplyDirectivity => data.apply_directivity = value.into(),
Params::ApplyOcclusion => data.apply_occlusion = value.into(),
Params::ApplyTransmission => data.apply_transmission = value.into(),
_ => return FMOD_OK, // todo should be FMOD_ERR_INVALID_PARAM,
}
} else {
Expand All @@ -239,8 +256,20 @@ pub(crate) unsafe extern "C" fn get_int_callback(
if let Some(param) = Params::from_repr(index) {
match param {
Params::ApplyDistanceAttenuation => {
let apply_da: c_int = (*effect).apply_distance_attenuation.into();
value.write(apply_da);
let apply: c_int = (*effect).apply_distance_attenuation.into();
value.write(apply);
}
Params::ApplyAirabsorption => {
let apply: c_int = (*effect).apply_air_absorption.into();
value.write(apply);
}
Params::ApplyDirectivity => {
let apply: c_int = (*effect).apply_directivity.into();
value.write(apply);
}
Params::ApplyOcclusion => {
let apply: c_int = (*effect).apply_occlusion.into();
value.write(apply);
}
_ => return FMOD_OK, // todo should be FMOD_ERR_INVALID_PARAM
}
Expand Down
1 change: 1 addition & 0 deletions crates/phonon-fmod/src/fmod_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ impl FmodDspState {
}
}

#[expect(dead_code, reason = "Not sure yet how this works")]
pub(crate) unsafe fn log_message(&self, message: &'static str) {
let functions = (*self.0).functions;
let log_fn = (*functions).log.unwrap();
Expand Down
64 changes: 47 additions & 17 deletions crates/phonon-fmod/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use libfmod::ffi::{
FMOD_DSP_PARAMETER_ATTENUATION_RANGE, FMOD_DSP_PARAMETER_OVERALLGAIN, FMOD_PLUGIN_SDK_VERSION,
};
use libfmod::DspDescription;
use phonon::audio_buffer::AudioBuffer;
use phonon::audio_buffer::{AudioBuffer, AudioSettings};
use phonon::direct_effect::{
DirectApplyFlags, DirectEffect, DirectEffectParameters, TransmissionType,
};
Expand Down Expand Up @@ -71,6 +71,7 @@ impl Into<c_int> for ParameterApplyType {
}
}

#[expect(dead_code, reason = "Not everything is implemented yet")]
pub(crate) struct EffectState {
source: FMOD_DSP_PARAMETER_3DATTRIBUTES,
overall_gain: FMOD_DSP_PARAMETER_OVERALLGAIN,
Expand Down Expand Up @@ -100,6 +101,8 @@ pub(crate) struct EffectState {
attenuation_range: FMOD_DSP_PARAMETER_ATTENUATION_RANGE,
attenuation_range_set: bool, // todo: Original is atomic

audio_settings: AudioSettings,

in_buffer_stereo: AudioBuffer<2>,
in_buffer_mono: AudioBuffer<1>,
out_buffer: AudioBuffer<2>,
Expand All @@ -110,7 +113,49 @@ pub(crate) struct EffectState {
direct_effect: DirectEffect,
}

fn apply_flag(
apply: ParameterApplyType,
target_flag: DirectApplyFlags,
current_flags: &mut DirectApplyFlags,
) {
match apply {
ParameterApplyType::Disable => current_flags.set(target_flag, false),
ParameterApplyType::SimulationDefined => current_flags.set(target_flag, true),
ParameterApplyType::UserDefined => current_flags.set(target_flag, true), //todo
}
}

impl EffectState {
fn create_flags(&mut self) -> DirectApplyFlags {
let mut flags = DirectApplyFlags::empty();

apply_flag(
self.apply_distance_attenuation,
DirectApplyFlags::DistanceAttenuation,
&mut flags,
);

apply_flag(
self.apply_air_absorption,
DirectApplyFlags::AirAbsorption,
&mut flags,
);

apply_flag(
self.apply_directivity,
DirectApplyFlags::Directivity,
&mut flags,
);

apply_flag(
self.apply_occlusion,
DirectApplyFlags::Occlusion,
&mut flags,
);

flags
}

fn process(
&mut self,
in_buffer: &[f32],
Expand All @@ -125,24 +170,9 @@ impl EffectState {
let direction = Vec3::new(position.x, position.y, position.z);
let panning_params = PanningEffectParameters { direction };

let mut flags = DirectApplyFlags::AirAbsorption
| DirectApplyFlags::Occlusion
| DirectApplyFlags::Transmission;

match self.apply_distance_attenuation {
ParameterApplyType::Disable => flags.set(DirectApplyFlags::DistanceAttenuation, false),
ParameterApplyType::SimulationDefined => {
flags.set(DirectApplyFlags::DistanceAttenuation, true)
}
ParameterApplyType::UserDefined => {
// todo
flags.set(DirectApplyFlags::DistanceAttenuation, true)
}
}

let direct_params = DirectEffectParameters {
direct_sound_path: self.direct_sound_path,
flags,
flags: self.create_flags(),
transmission_type: TransmissionType::FrequencyDependent,
};

Expand Down
1 change: 1 addition & 0 deletions crates/phonon-fmod/src/parameter_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ fn create_param_data(
}
}

#[expect(dead_code, reason = "No float params have been added yet")]
fn create_param_float(name: &str, description: &'static str) -> DspParameterDesc {
DspParameterDesc {
type_: DspParameterType::Float,
Expand Down
10 changes: 0 additions & 10 deletions crates/phonon/src/direct_simulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,6 @@ use crate::scene::Scene;
use crate::sphere::Sphere;
use glam::Vec3;

// todo: Remove in favor of DirectApplyFlags?
enum DirectSimulationType {
CalcDistanceAttenuation,
CalcAirAbsorption,
CalcDirectivity,
CalcOcclusion,
CalcTransmission,
CalcDelay,
}

pub enum OcclusionType {
Raycast,
Volumetric,
Expand Down
4 changes: 3 additions & 1 deletion crates/phonon/src/eq_effect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,10 @@ impl EqEffect {
self.apply_filter_cascade(self.current, &input[0], &mut output[0]);
}

return AudioEffectState::TailComplete;
AudioEffectState::TailComplete
}

#[expect(dead_code, reason = "Used in HybridReverbEffect, not ported yet")]
fn tail_apply(
&mut self,
input: &AudioBuffer<1>,
Expand All @@ -125,6 +126,7 @@ impl EqEffect {
)
}

#[expect(dead_code, reason = "Used in HybridReverbEffect, not ported yet")]
fn tail(output: &mut AudioBuffer<1>) -> AudioEffectState {
output.make_silent();
AudioEffectState::TailComplete
Expand Down
17 changes: 0 additions & 17 deletions crates/phonon/src/hit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,3 @@ pub(crate) struct Hit {
pub(crate) normal: Vec3,
pub(crate) material: Material,
}

impl Hit {
pub(crate) fn new_empty() -> Self {
Self {
distance: f32::MAX,
triangle_index: 0,
object_index: 0,
material_index: 0,
normal: Default::default(),
material: Material {
absorption: [0.0, 0.0, 0.0],
scattering: 0.0,
transmission: [0.0, 0.0, 0.0],
},
}
}
}
2 changes: 1 addition & 1 deletion crates/phonon/src/iir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ impl IIRFilterer {
}

/// Applies the filter to an entire buffer of input, using SIMD operations.
pub fn apply(&mut self, size: usize, input: &[f32], output: &mut [f32]) {
pub fn apply(&mut self, _size: usize, input: &[f32], output: &mut [f32]) {
//todo: Temporary implementation, no SIMD optimizations yet
//todo: Can panic
for i in 0..input.len() {
Expand Down
2 changes: 1 addition & 1 deletion crates/phonon/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! A community effort to rewrite Valve's Steam Audio into a Rust library.
#[cfg(feature = "serde")]
#[cfg(feature = "serde-serialize")]
#[macro_use]
extern crate serde;

Expand Down
2 changes: 1 addition & 1 deletion crates/phonon/src/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::bands::NUM_BANDS;
/// An acoustic material. The acoustic surface properties of an object are represented using multi-band absorption
/// and transmission loss coefficients, and a single random-incidence scattering coefficient.
/// All values are in the 0.0 to 1.0 range.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Material {
pub absorption: [f32; NUM_BANDS],
Expand Down
2 changes: 1 addition & 1 deletion crates/phonon/src/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use parry3d::shape::TriMesh;

/// A triangle mesh. Vertices are stored in a contiguous array, and the triangles are stored in indexed form. Each
/// triangle requires three indices to store (i.e., strip or fan representations are not supported).
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct Mesh {
pub(crate) mesh: TriMesh,
normals: Array1<Vec3>,
Expand Down
2 changes: 1 addition & 1 deletion crates/phonon/src/panning_effect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl PanningEffect {
direction: Vec3,
speaker_layout: &SpeakerLayout,
index: usize,
panning_data: &PanningData,
_panning_data: &PanningData, // todo: Can't this be based on the SpeakerLayout?
) -> f32 {
match speaker_layout.layout_type {
SpeakerLayoutType::Mono => 1.0,
Expand Down
1 change: 1 addition & 0 deletions crates/phonon/src/reverb_effect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub struct ReverbEffect {
num_tail_frames_remaining: i32,
}

#[expect(dead_code, reason = "ReverbEffect is a WIP")]
impl ReverbEffect {
pub fn new(audio_settings: AudioSettings) -> Self {
let delay_values = Self::calc_delays_for_reverb_time(2.0, audio_settings.sampling_rate);
Expand Down
8 changes: 4 additions & 4 deletions crates/phonon/src/scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use std::sync::{Arc, Mutex};
/// Objects can be added and removed from the scene at any time.
/// Objects can also be defined as instances of one another.
/// This class also allows rays to be traced through the scene.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct Scene {
/// Two lists of static meshes. The one at index 0 is used internally while
/// the one at index 1 can be changed by the user through `add_static_mesh`
Expand All @@ -39,15 +39,15 @@ pub struct Scene {
//todo: Only static_meshes[0] should be serialized/deserialized.
pub(crate) static_meshes: [Vec<Arc<StaticMesh>>; 2],

#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "serde-serialize", serde(skip))]
pub(crate) instanced_meshes: [Vec<Arc<Mutex<InstancedMesh>>>; 2],

/// Flag indicating whether the scene has changed in some way since the previous call to commit().
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "serde-serialize", serde(skip))]
has_changed: bool,

/// The change version of the scene.
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "serde-serialize", serde(skip))]
change_version: u32,
}

Expand Down
4 changes: 4 additions & 0 deletions crates/phonon/src/sphere.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ impl Sphere {
Self { center, radius }
}

#[expect(
dead_code,
reason = "Features that use this have not been implemented yet"
)]
pub(crate) fn contains(&self, point: Vec3) -> bool {
(point - self.center).length_squared() <= self.radius * self.radius
}
Expand Down
2 changes: 1 addition & 1 deletion crates/phonon/src/static_mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use parry3d::query::RayCast;

/// A static triangle mesh. The geometry of this mesh is assumed to never change at runtime. It is described in
/// world-space coordinates. Materials are specified for each triangle.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct StaticMesh {
mesh: Mesh,
material_indices: Array1<usize>,
Expand Down
2 changes: 1 addition & 1 deletion crates/phonon/src/triangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
//

/// An indexed triangle, which can only be interpreted relative to a vertex buffer.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Copy, Clone)]
pub struct Triangle {
pub indices: [usize; 3],
Expand Down

0 comments on commit 27e759d

Please sign in to comment.