I am trying to simulate the doppler effect in a game (a car racing game). I am not using a specific sound library that simulate the effect, I only have a callback function where I mix the data.
I already figured out how to change frequency of a sample in the mixer function.
What I dont know is how much the frequency should change depending player and emitter position and velocity.
Here is what i have in the game :
//player
vec3 p.pos;
vec3 p.vel;
//emitter
vec3 e.pos;
vec3 e.vel;
1) According to wikipedia, the relation between emitted frequency and observed frequency is given by :
float f = (c + vr) / (c + vs) * fo
where c is a constant, the velocity in medium (typically a big number) vs and vr are source and receiver velocities relative to medium.
so i guess :
float vr = p.vel.length; //player speed
float vs = e.vel.length; //emitter speed
but i think its wrong, it wont produce any change in frequency, for eg: if vr = 0
(player dont move) and emitter have constant speed, then vr
and vs
wont change (while they should).
maybe should i calculate velocity of player relatively to velocity of emitter ?
like this :
relative_speed = distance(p.pos + p.vel, e.pos + e.vel) -
distance(p.pos, e.pos);
then how vr
and vs
should be feed ?
2) wikipedia also give another formula to simulate the effect of a vehicle that vehicle passes by the observer :
vr = vs * cos(theta);
//theta is angle between observer and emitter
//theta = atan2(e.pos.y-p.pos.y, e.pos.x-p.pos.x); ?
however, this formula suppose the receiver dont move, which is not the case here. if player and emitter move at same speed (or small difference), there should be no doppler effect. this function is also specific to one case, i suppose the final formula should be the same no mater the situation.
EDIT: i'm trying to find correct formula, using SkimFlux post :
vr,r = vr.vel * cos(shortest_angle_between ( vr.vel , vs.pos - vr.pos));
vs,r = vs.vel * cos(shortest_angle_between ( vs.vel , vr.pos - vs.pos));
//is there a easier/faster way to find them out ?
//note: vr.vel and vs.vel are vectors, the green and red arrows on SkimFlux picture.
EDIT2 :
For those interested, here is final formula :
vec2 dist = vs.pos - vr.pos;
vr,r = dotproduct(vr.vel, dist) / length(dist)
vs,r = dotproduct(vs.vel, dist) / length(dist)
NOTE : it use vector projection, described here :
then vr,s
and vs,r
should be injected in first wikipedia formula :
I tested it and it works sucessfully, providing great results.