Listener Position Deltas and Accurate Doppler Effect

As a Roblox developer, it is currently impossible to exclude the camera’s position delta for processing doppler effect.

As it stands now, when doppler effect is being processed, it takes into consideration the camera’s position delta as well as the listener’s velocity. While this is accurate behaviour (assuming the listener and the camera share the same position), some developers would welcome the option of having the position delta ignored in doppler processing. Personally, I’d like to increase the DopplerScale in one of my games without having minor camera movements heavily detune the audio.

Let’s say for example, I want the camera to tween in on the player when they spawn in. If that player has a boombox blasting tunes, then their song would appear to increase in pitch, since the position delta of the camera results in a net velocity towards the listener.

Another, more common example. Let’s say a sound is playing on the far edge of a map, and the players have their camera positioned really far away from them. If they were to revolve the camera around themselves, they’d hear large increases or decreases in that sound’s pitch, depending on weather the camera is moving closer to or further from the sound source.

Again, this is accurate behaviour, but only when assuming that the listener shares the same position as the camera. In many cases, the developer would opt for the player’s character to be the listener, meaning camera deltas won’t affect the doppler effect. SoundService:SetListener("ObjectPosition", workspace.CurrentCamera.CameraSubject) corrects the doppler effect in the sense that spinning the camera around doesn’t cause insane jumps in pitch, but then audio volume is computed from the listener’s position, meaning that moving the camera away from a sound source for example, won’t reduce that sound’s volume.

I’d propose a simple boolean property parented under the SoundService (“DopplerVelocityOnly” or “VelocityExclusive” perhaps). When true, the velocity of the listener is assumed to be 0 unless the listener is a BasePart (either through Camera.CameraSubject or SoundService:SetListener()), during which BasePart.Velocity is taken into account only. I believe this was how things used to work way (way, waaay) back when, so it’ll be nice if this were an optional feature.

There’s a somewhat-hacky fix to this issue here, but I’m sure we can all agree that the solution would be less complicated and more efficient if it were done natively.

4 Likes

When I made my script I discovered pretty early on that the character’s velocity doesn’t really matter, it’s only the camera’s dx/dt that matters for doppler. It’s easy to calculate that way, and I assume fmod isn’t easy to set up for weird things like ignoring the camera’s dx/dt while only taking into account the character’s velocity.

Like I said in my thread which you linked, 15 hz is approximately the threshold at which doppler is calculated when updating listener CFrame. Like I said in that thread, you can have two loops running at the same time; a fast loop for doppler, and a slow loop for no doppler. The slow loop updates the camera offset value, and the fast loop applies the offset value, offset from the HumanoidRootPart. This seems to create the exact kind of conditional doppler you want.

My script doesn’t take into account when the camera is targeting things that aren’t the character, but that’s easily remedied.

2 Likes