Topo1st Posted October 11, 2014 Share Posted October 11, 2014 I've been having hard time figuring out how to script doppler effect for a sound (element). Can't figure it out myself, so I need help with it. Those are the sources I've been investigating: This and this. Link to comment
MTA Team botder Posted October 11, 2014 MTA Team Share Posted October 11, 2014 Interesting. Well, you should begin with having a mapping, which vehicle (or model) is using a sound. Then go ahead and make a onClientRender handler. In this handler you get the localPlayer's velocity and position (check for localPlayer's vehicle and use it if available), go through the mapping with a loop and get each vehicle's velocity and position aswell. In this loop you do the calculation as written on the sources you provided (shouldn't be too hard) and set the sound properties (create the sound if not done before). Play with the fPitch and fTempo values to get a nice effect. PlaySound SetSoundVolume SetSoundProperties OnClientRender Link to comment
Topo1st Posted October 11, 2014 Author Share Posted October 11, 2014 Interesting.Well, you should begin with having a mapping, which vehicle (or model) is using a sound. Then go ahead and make a onClientRender handler. In this handler you get the localPlayer's velocity and position (check for localPlayer's vehicle and use it if available), go through the mapping with a loop and get each vehicle's velocity and position aswell. In this loop you do the calculation as written on the sources you provided (shouldn't be too hard) and set the sound properties (create the sound if not done before). Play with the fPitch and fTempo values to get a nice effect. PlaySound SetSoundVolume SetSoundProperties OnClientRender The point is that I can't figure out how to take advantage of those formulas. The sound element with the vehicle it's attached to, along with the listener (in fact, the camera element) is known. I need help at the point where I have to do those calculations. Link to comment
MTA Team botder Posted October 11, 2014 MTA Team Share Posted October 11, 2014 Try this code: addEventHandler("onClientRender", root, function () -- Get every sound local sounds = getElementsByType("sound") -- Abort if there is no sound active if (#sounds == 0) then return end -- Get if possible my vehicle local me = getPedOccupiedVehicle(localPlayer) -- Else use my ped if (not isElement(me)) then me = localPlayer end -- Get our position local mpX, mpY, mpZ = getElementPosition(me) -- Get our velocity local mvX, mvY, mvZ = getElementVelocity(me) -- Loop through the sounds for index = 1, #sounds do -- Get the current sound by index local sound = sounds[index] -- Get the element, which the sound is attached to local attachedto = getElementAttachedTo(sound) -- Continue if the sound is attached to a vehicle if (isElement(attachedto) and getElementType(attachedto) == "vehicle") then -- Get the vehicle's position local tpX, tpY, tpZ = getElementPosition(attachedto) -- Calculate the distance between him and us local dX, dY, dZ = distance(mpX, mpY, mpZ, tpX, tpY, tpZ) -- Get the actual length from the distance local distance = getDistanceBetweenPoints3D(mpX, mpY, mpZ, tpX, tpY, tpZ) -- Get the vehicle's velocity local tvX, tvY, tvZ = getElementVelocity(attachedto) -- Calculate the dotproduct from velocity and distance for the sender local dpS = dotproduct(tvX, tvY, tvZ, dX, dY, dZ) -- Calculate the dotproduct from velocity and distance for the receiver local dpR = dotproduct(mvX, mvY, mvZ, dX, dY, dZ) -- Calculate teh vs value for the sender local vr = dpR / distance -- Calculate the vr value for the receiver local vs = dpS / distance -- Calculate the frequency (modified formula to improve the effect in GTA) local f = ((1 + vr) / (1 + vs)) * (4.5 * (vs - vr)) -- Adjust the sound volume setSoundVolume(sound, 1 - math.min(1, (distance + distance * 0.25) / 300)) -- Adjust the sound speed and effect local samplerate, _, _, reverse = getSoundProperties(sound) setSoundProperties(sound, samplerate, f, f, reverse) end end end ) function distance(x, y, z, a, b, c) return math.abs(a - x), math.abs(b - y), math.abs(c - z) end function dotproduct(x, y, z, a, b, c) return math.abs(x * a) + math.abs(y * b) + math.abs(z * c) end Link to comment
Topo1st Posted October 12, 2014 Author Share Posted October 12, 2014 I modified the code to fit my purpose. Though it should look fine, the result is '-1.#IND'. Note that applyDopplerEffectToSound is called by another function called by onClientRender. function setSoundProperty(sound, property, value) if (sound) and (getElementType(sound) == "sound") then local samplerate, tempo, pitch, reversed = getSoundProperties(sound) if (property == "SampleRate") then local success = setSoundProperties(sound, tonumber(value), tempo, pitch, reversed) if (success) then return true end elseif (property == "Tempo") then local success = setSoundProperties(sound, samplerate, tonumber(value), pitch, reversed) if (success) then return true end elseif (property == "Pitch") then local success = setSoundProperties(sound, samplerate, tempo, tonumber(value), reversed) if (success) then return true end elseif (property == "Reversed") then if (value == true) or (value == false) then success = setSoundProperties(sound, samplerate, tempo, pitch, value) if (success) then return true end end end end end function applyDopplerEffectToSound(sound) local veh = getPedOccupiedVehicle(localPlayer) local soundveh = getElementAttachedTo(sound) local tpX, tpY, tpZ = getElementPosition(soundveh) local tvX, tvY, tvZ = getElementVelocity(soundveh) if (veh) then local mpX, mpY, mpZ = getElementPosition(veh) local mvX, mvY, mvZ = getElementVelocity(veh) local dX, dY, dZ = distance(mpX, mpY, mpZ, tpX, tpY, tpZ) local distance = getDistanceBetweenPoints3D(mpX, mpY, mpZ, tpX, tpY, tpZ) local dpS = dotproduct(tvX, tvY, tvZ, dX, dY, dZ) local dpR = dotproduct(mvX, mvY, mvZ, dX, dY, dZ) local vr = dpR / distance local vs = dpS / distance local f = ((1 + vr) / (1 + vs)) * (4.5 * (vs - vr)) setSoundProperty(sound, "Pitch", f) else local mpX, mpY, mpZ = getElementPosition(localPlayer) local mvX, mvY, mvZ = getElementVelocity(localPlayer) local dX, dY, dZ = distance(mpX, mpY, mpZ, tpX, tpY, tpZ) local distance = getDistanceBetweenPoints3D(mpX, mpY, mpZ, tpX, tpY, tpZ) local dpS = dotproduct(tvX, tvY, tvZ, dX, dY, dZ) local dpR = dotproduct(mvX, mvY, mvZ, dX, dY, dZ) local vr = dpR / distance local vs = dpS / distance local f = ((1 + vr) / (1 + vs)) * (4.5 * (vs - vr)) setSoundProperty(sound, "Pitch", f) end end function distance(x, y, z, a, b, c) return math.abs(a - x), math.abs(b - y), math.abs(c - z) end function dotproduct(x, y, z, a, b, c) return math.abs(x * a) + math.abs(y * b) + math.abs(z * c) end Link to comment
MTA Team botder Posted October 12, 2014 MTA Team Share Posted October 12, 2014 I changed your code, here: local map_setSoundProperty = {["SampleRate"] = 1, ["Tempo"] = 2, ["Pitch"] = 3, ["Reversed"] = 4} function setSoundProperty(sound, property, value) -- Only handle sound elements if (not isElement(sound) or getElementType(sound) ~= "sound") then return end -- Get the current properties local properties = { getSoundProperties(sound) } -- Get the index by using the property parameter local index = map_setSoundProperty[property] -- Apply the value if there is an index for it if (index) then properties[index] = tonumber(value) end -- Return the property-success boolean return setSoundProperties(sound, unpack(properties)) end function applyDopplerEffectToSound(sound) -- Get the receiver (use localPlayer if we have no vehicle) local receiver = { e = getPedOccupiedVehicle(localPlayer) } if (not receiver.e) then receiver.e = localPlayer end -- Get the sender (abort if it's invalid or if it equals to the receiver) local sender = { e = getElementAttachedTo(sound) } if (not sender.e or sender.e == receiver.e) then return end -- Receiver information receiver.p = { getElementPosition(receiver.e) } receiver.v = { getElementVelocity(receiver.e) } -- Sender information sender.p = { getElementPosition(sender.e) } sender.v = { getElementVelocity(sender.e) } -- Distance calculation (abort if there is no distance) local dx, dy, dz, d = getDistanceBetweenPoints(receiver.p, sender.p) if (d < 1) then return end -- Calculate velocity dotproduct for receiver and sender sender.vs = getVelocityDotproduct(sender.v, dx, dy, dz, d) receiver.vr = getVelocityDotproduct(receiver.v, dx, dy, dz, d) -- Calculate pitch local p = ((1 + receiver.vr) / (1 + sender.vs)) * (4.5 * math.max(0, sender.vs - receiver.vr)) setSoundProperty(sound, "Pitch", p) end function getDistanceBetweenPoints(pointA, pointB) local x, y, z = math.abs(pointB[1] - pointA[1]), math.abs(pointB[2] - pointA[2]), math.abs(pointB[3] - pointA[3]) local distance = getDistanceBetweenPoints3D(pointA[1], pointA[2], pointA[3], unpack(pointB)) return x, y, z, distance end function getVelocityDotproduct(point, dx, dy, dz, d) if (d == 0) then return 1 end return (math.abs(point[1] * dx) + math.abs(point[2] * dy) + math.abs(point[3] * dz)) / d end Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now