The "help" I'm looking for is really a request to double-check I used SFML as it was intended to be used for my case, and then the request would be to make this clearer in the documentation in one or two places, if so.
I post this as I have just gotten all to work as expected / intended, but the route to get here was painful, so I'm hoping to see changes to documentation that help others in a similar situation.
The subject is using the static Listener and setting properties on Sound object instances to achieve spatial audio in a 2D environment, where the Listener is to match the View position, and sounds would therefore really only register as "to the left" or "to the right" in relation to the center of the view, with proper attenuation.
All audio used is mono, so spatial audio is possible. Some of the audio used in the project is not meant to be spatial (music, ui sfx) and so there are different configurations that were needed.
References used in this effort include the
SoundSource doc https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1SoundSource.php and static
Listener doc https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1Listener.php.
Additionally, the
Spatialization tutorial https://www.sfml-dev.org/tutorials/2.5/audio-spatialization.php and then
this forum thread https://en.sfml-dev.org/forums/index.php?topic=14566.0 helped to highlight where I was having problems understanding the API intent, so ultimately it helps to reference all these.
With all that said, and understanding that we're all careful, we (largely) read documentation before making assumptions, and we (largely) make mistakes from time to time, worthy of improvement, I humbly suggest we revisit how this kind of effort is documented. There are a couple of things to point out in terms of how the documentation presents the tools available.
The Spatialization tutorial says this:
(in General) By default, sounds and music are played at full volume in each speaker; they are not spatialized. ... (for Audio Sources) The main property is the position of the audio source. ... This position is absolute by default, but it can be relative to the listener if needed. ... This can be useful for sounds emitted by the listener itself (like a gun shot, or foot steps). It also has the interesting side-effect of disabling spatialization if you set the position of the audio source to (0, 0, 0). Non-spatialized sounds can be required in various situations: GUI sounds (clicks), ambient music, etc.
The concern here is simply that the sound results are defined in two states: absolute and relative (to listener); however if you read this carefully, you are hearing "default = absolute = full volume both speakers" and then "relative = emitted by listener itself = examples: foot steps, gui sounds, ambient music". Which, are actually describing the same results: full volume both speakers. This could be carefully cleaned up in the documentation to avoid confusion by clearly defining two states of the sound source: absolute and relative.
I suggest that without clearing it up, absolute sound by default apparently means the sound seems emitted at the listener location.
But that conflicts with what the SoundSource class documentation has to say:
void sf::SoundSource::setRelativeToListener(bool relative)
Make the sound's position relative to the listener or absolute.
Making a sound relative to the listener will ensure that it will always be played the same way regardless of the position of the listener. This can be useful for non-spatialized sounds, sounds that are produced by the listener, or sounds attached to it. The default value is false (position is absolute).
Parameters
relative True to set the position relative, false to set it absolute
Here is where the solution to my particular setup fell into place, but only by realizing that the word "relative", as in, "this sound source position relative to the listener position", actually is used in an inverse meaning. Based on the explanation, rather than the word "relative", it was clear what was meant is the SoundSource position will seem as if it is following the Listener position, as if it is the same position as the Listener with no difference, no delta.
"Relative", I'm suggesting, actually infers a difference between two, with a delta that in this case would make sense for spatialization. In other words, if a sound is relative to the listener, the suggested meaning is that this enables spatialization between sound and listener. But in practice, the opposite is true.
So I'm suggesting a) the word "relative" was used in a misleading way (if not opposite), and b) the description of the results called for with relative = true matches what the Spatialization tutorial says is already default (absolute) behavior; in other words, this documentation again conflicts.
That was my first point, the use of the word "relative" in the method name, property name conflicts with the actual results. My suggestion is documentation can call this out more clearly, and help others in the future. (I'm not suggesting you change the API to fit the language, I know that's too much to ask at this point)
The second point has to do with the practical use for spatialization of audio in 2D, and without a clear example, the development was more painful than necessary, and a short example in the documentation would be excellent. So this calls for another sanity check: did I do this as the API expects I would, because it seemed as intuitive as I could get it.
Again, there is a brief mention in the Spatialization tutorial
If you have a 2D world you can just use the same Y value everywhere, usually 0.
So, to be honest, that threw me off for a while. Converting my moving view center position to (x, 0, y) for the 3D vector needed by the listener was not intuitive and did not yield expected results. And setting SourceSource locations to match this space was tried in many different attempts to follow this guidance. All this didn't turn out to be necessary in the end.
In fact, here is what worked:
sf::Listener::setDirection(0.f,0.f,-1.f);
sf::Listener::setUpVector(0.f,1.f,0.f);
while (gameLoop) {
sf::Listener::setPosition( myView.getCenter().x, myView.getCenter().y, 0.f );
}
This configuration is what worked for a simple 2D view game, where the view travels with my local player in the x,y 2D space, and all sound emitting objects likewise live on the same x,y 2D space. So, when a sound object was set for spatialization the position was set as
mySound.setRelativeToListener(false);
mySound.setMinDistance(50.f);
mySound.setAttenuation(0.1f);
mySound.setPosition(sPos.x,sPos.y,0.f);
(Individual configurations for minDistance and Attenuation will vary) But, notice two things here: first, the space is simply using z=0, with x & y the same, and second, to make this spatialized, the sound is set to be absolute, not relative (opposite meaning of "relative to listener"). And, following this new understanding, the non-attenuated / non-spatialized sounds needed for this project are defined like this:
mySound.setPosition(0.f,0.f,0.f);
mySound.setRelativeToListener(true);
mySound.setMinDistance(1.f);
mySound.setAttenuation(1.f);
(while the position, minDistance and Attenuation are irrelevant if not spatialized, I set it this way for tidy-ness)So, my second point is: This clear example, with a 1 to 1 relationship to the 2D visual space a simple project works in, would be so helpful to have in the documentation, and it would have saved a lot of time. Clearing up the "y=0" idea, as well, would be helpful, as that was not the intuitive way to go.
The results with the above example are as one would expect of a simple 2D audio space. Sounds from the left are heard on the left, etc. Note the direction of the Listener is pointing to negative Z. Up vector is positive Y. And all positions are using the 2D space with a Z of zero.
With all this, I'm hoping the two points are well taken in the spirit of making the documentation better for the next person.
- All documentation surrounding relativity to listener ("isRelativeToListener", "setRelativeToListener", etc) needs clarification to ensure the reader understands the two states of the sound: absolute means it lives in a spatialized sound space, and the listener position will matter (even if default is origin and if you do nothing to the listener, it will play at full volume in both speakers), while relative actually means the sound will emit from the listener regardless of its position or the sound source position, and will always play at full volume in both speakers.
- A clear example for a simple 2D spatialized audio setup would be extremely helpful. Translate sound positions to 3D sound space for listener as (x,y,0) and position listener likewise as (x,y,0). Set direction of listener to point toward negative Z. Set up vector for listener to positive Y.
I do hope that helps. And of course, if I've misunderstood any/all this, I think that also helpful to be corrected.
(love SFML btw, thanks!)