use gizmo_audio::{AudioManager, AudioSource};
use gizmo_core::World;
use gizmo_math::Vec3;
use gizmo_physics_core::Transform;
use gizmo_physics_rigid::components::Velocity;
pub fn audio_spatial_system(world: &mut World, _dt: f32) {
let audio_opt = world.get_resource_mut::<AudioManager>();
let mut audio = match audio_opt {
Some(m) => m,
None => return,
};
audio.update();
let transforms = world.borrow::<Transform>();
let mut listener_pos = Vec3::ZERO;
let mut listener_vel = Vec3::ZERO;
let mut listener_right = Vec3::new(1.0, 0.0, 0.0);
if let Some(mut query) = world.query::<(&gizmo_renderer::Camera, &Transform)>() {
for (e, (cam, t)) in query.iter_mut() {
if cam.primary {
listener_pos = t.position;
listener_right = t.rotation.mul_vec3(Vec3::new(1.0, 0.0, 0.0)).normalize();
if let Some(v) = world.borrow::<Velocity>().get(e) {
listener_vel = v.linear;
}
break;
}
}
}
let ear_distance = 0.2;
let left_ear = listener_pos - (listener_right * (ear_distance / 2.0));
let right_ear = listener_pos + (listener_right * (ear_distance / 2.0));
let left_ear_arr = [left_ear.x, left_ear.y, left_ear.z];
let right_ear_arr = [right_ear.x, right_ear.y, right_ear.z];
let sources = world.borrow_mut::<AudioSource>();
let velocities = world.borrow::<Velocity>();
let mut source_ids = Vec::new();
for (id, _) in sources.iter() {
source_ids.push(id);
}
for id in source_ids {
let mut source = if let Some(s) = sources.get_mut(id) {
s.clone()
} else {
continue;
};
let t = if let Some(t) = transforms.get(id) {
t
} else {
continue;
};
if source._internal_sink_id.is_none() && source.is_3d {
let sink_id = if source.loop_sound {
audio.play_3d_looped(
&source.sound_name,
[t.position.x, t.position.y, t.position.z],
left_ear_arr,
right_ear_arr,
)
} else {
audio.play_3d(
&source.sound_name,
[t.position.x, t.position.y, t.position.z],
left_ear_arr,
right_ear_arr,
)
};
source._internal_sink_id = sink_id;
if let Some(mut s) = sources.get_mut(id) {
s._internal_sink_id = sink_id;
}
}
if let Some(sink_id) = source._internal_sink_id {
if !audio.is_playing(sink_id) {
if !source.loop_sound {
if let Some(mut s) = sources.get_mut(id) {
s._internal_sink_id = None;
}
}
continue;
}
audio.update_spatial_sink(
sink_id,
[t.position.x, t.position.y, t.position.z],
left_ear_arr,
right_ear_arr,
source.max_distance,
source.volume,
);
let emitter_vel = if let Some(v) = velocities.get(id) {
v.linear
} else {
Vec3::ZERO
};
let speed_of_sound = 343.0;
let diff = t.position - listener_pos;
let dist = diff.length();
if dist > 0.1 {
let dir = diff / dist;
let listener_speed_towards_emitter = listener_vel.dot(dir);
let emitter_speed_towards_listener = emitter_vel.dot(-dir);
let mut doppler_factor: f32 = (speed_of_sound + listener_speed_towards_emitter)
/ (speed_of_sound - emitter_speed_towards_listener).max(1.0);
doppler_factor = doppler_factor.clamp(0.5, 2.0);
let final_pitch = source.pitch * doppler_factor;
audio.set_pitch(sink_id, final_pitch);
} else {
audio.set_pitch(sink_id, source.pitch);
}
}
}
}