3D Sound in Wrapping 2D Map

Hi all,

First-off, this is related to the Core API, than the Studio API.

I’m working on a 2D, side-view game and recently put 3D sound into place for sound panning when effects happen to the left or right of the player. It works wonderfully, but I’ve run into an unfortunate difficulty. The game can have wrapping maps, i.e. the map goes from 0 - n, and when you pass n (when going in the positive direction), your position loops back around to ~0.
Unfortunately, this presents a challenge with 3D sound because, as far as I know, I can’t specify the calculation used to determine the distance (and direction) between the listener and a given sound (if I could this would be straightforward to solve).

I’ve tried searching for this and looked through the docs but had no luck, and I’d like to know if anyone’s had to deal with this issue, or if anyone has suggestions that could help.

For what it’s worth, I’ve come up with 2 possible solutions, but I can’t say I love either of them:

  1. Play a copy of every sound at soundPosition + (soundPosition > mapWidth/2 ? mapWidth : -mapWidth) and rely on attenuation to quiet the sound appropriately. That way the sound will always be playing in the more appropriate direction, e.g. if the map width is 2000 and the listener is at 1800, a sound played at 200 will also play at 2200, which will be 400 away to the right, which is correct.
    The downside here is that copies of each sound get created and, if the map wraps in X and Y (which can theoretically happen though it’d be rare), this can mean 4 copies for each sound.

  2. Change any playing sound’s positions according to the listener’s position. Whenever the listener moves more than half of the map away from a sound, that sound would be shifted to its reverse position. So, given the example above, while the listener is < 1200 the sound would stay where it is, but once they go past 1200, the sound would move to 2200, so it’d play on the right side.
    The first downside here is the extra iteration over every sound every frame, though that could be optimized to not be a big problem. The second downside is that the game can be played in 2, 3 or 4-player splitscreen, so this process would have to be done for up to 4 players, since any of those 4 players could be close enough to trigger a position shift in a given sound.

Also, this is fairly unrelated, but while I’m asking questions I want to confirm that I’m correct in my understanding; using ChannelControl::set3DLevel(<1) to lessen the sound panning strength removes automatic distance attenuation right?

Thanks for your time,

It won’t remove the distance attenuation, all the 3D level does is set a mix between 3D and 2D pans. If the level is < 1.0 then we do the full 3D calculations and then we do 2D panning independently and we mix the twi using 3DLevel as the mix factor.

As for the map wrapping, I am not too sure about a way to do what you are wanting to, but maybe some people from the community will have some ideas.

My only idea, after reading your dilema, would be to use a second listener.

This listener could track the player’s position but be PlayerPosition - MapWidth to the left.

In my head, this would easily simulate sounds on the other side of the map sounding like they’re in front of the player. And with FMOD’s 8 listener limit, 4 player splitscreen will still work.

Hi guys,

Thanks a lot for the answers! I guess, unfortunately, I was right and there’s no way to override the distance calculation between listeners and sounds. Too bad, but I guess this is a pretty niche problem, so I get why that’s the case.

Regarding 3d level, I guess I have to do a bit more testing - based on this thread and what I’ve seen, setting a 3d level of anything < 1 disables 3d attenuation, at least with inverse rolloff. I’m in the process of trying out using a custom rolloff for this, to see if it’ll sort this problem out.

Regarding using another listener, that’s a really clever idea, and one that I didn’t think of, but I’m not sure it’ll work. According to the docs, “If the number of listeners is set to more than 1, then panning and doppler are turned off.”

I’m currently reading through the DSP callback stuff to see if I can figure out a way to do everything with that, but I don’t know if it’s actually an appropriate solution to either of my problems.