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
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);
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.
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 :
vs,r should be injected in first wikipedia formula :
I tested it and it works sucessfully, providing great results.