-
Hi, just a quick question on whether this is the intentional behavior or if I am doing something wrong.
When I position a sound very slightly left of the listener, it plays exclusively from the left speaker. This can be jarring when a sound or the listener moves from one side to the other. Ideally it would play from both speakers if it was close to the listener and slowly move to being just left/right as it got further away. Is this always the expected behavior or are my sound/listener parameters incorrect?
-
Can you provide a minimal example that reproduces the issue?
-
Sounds like you're saying that my issue is not the intended behavior. Maybe my values are incorrect (I haven't touched attenuation yet), I will play with them and make a minimal example if I still can't fix it. Thanks!
-
Hmm, I am still hearing this issue, here is a minimal example. Even if I put the sound 0.0001f to the right, it is only audible through the right speaker. Either something is wrong with my sound driver or this is intended?
#include <SFML\Graphics.hpp>
#include <SFML\Audio.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(640, 480), "SFML Window");
sf::SoundBuffer buffer;
buffer.loadFromFile("bullet.wav");
sf::Sound sound;
sound.setBuffer(buffer);
while(true)
{
sf::Event e;
while (window.pollEvent(e))
{
if (e.type == sf::Event::KeyPressed)
{
switch (e.key.code)
{
case sf::Keyboard::Left:
sound.setPosition(-1.0f, 0, 0);
break;
case sf::Keyboard::Right:
sound.setPosition(1.0f, 0, 0);
break;
case sf::Keyboard::Space:
sound.setPosition(0, 0, 0);
break;
case sf::Keyboard::Escape:
return 0;
}
sound.play();
}
}
}
return 0;
}
Also, unrelated, I hear something that may be a bug. Using the above program it seems that setPosition doesn't immediately take effect. That is, if I press left to position it on the left, then press right, I do hear a little blip out of the left speaker. Pressing right further times won't produce anything from the left speaker.
-
Seems like this is intended. I guess there can be arguments for and against this behavior. In the end SFML just uses OpenAL which does the 3D spatial audio (afaik).
I quickly recreated an audio "spinning" example as you mentioned in the beginning.
#include <SFML/Audio.hpp>
#include <cmath>
#include <iostream>
int main()
{
sf::SoundBuffer buffer;
buffer.loadFromFile("mono.wav");
sf::Sound sound;
sound.setBuffer(buffer);
sound.setLoop(true);
sound.setMinDistance(5.f);
sound.setAttenuation(1.f);
sound.play();
sf::Vector3f pos;
float radius = 10.f;
float t = 0;
float angular_velocity = 0.8f;
sf::Clock clock;
while(true)
{
sf::Time dt = clock.restart();
t += dt.asSeconds() * angular_velocity;
pos.x = radius * std::cos(t);
pos.y = radius * std::sin(t);
pos.z = 0.f;
sound.setPosition(pos);
std::cout << pos.x << ", " << pos.y << ", " << pos.z << "\n";
}
sound.stop();
}
-
Thanks, your example shows the issue more clearly. Yeah I figured this was just an OpenAL thing. It's too bad there isn't a way to simply specify the volume of the left/right channels but I suppose OpenAL isn't made for that. I guess I'll work around this by not spatializing sounds until they're further from the player in my game. Not ideal but having sounds switch from one mode to the other will be less common.
-
If it's on the left (even just a little bit) then it's fully on the left. Same for right. If you intend to hear in both speakers with more in the left than right, it needs to be somewhere in front and to the left. Similar for right.
Ideally, then, pan would be a circular arc from one side around the front to the other side.
However, a very simple (and rather quick) pan can be created like this:
sf::Vector3f stereoPanPosition(const float panAmount)
{
// ensure that panAmount is in the range [-1, 1] (-1 is left; 1 is right)
if (panAmount > 1.f) panAmount = 1.f;
if (panAmount < -1.f) panAmount = -1.f;
return{ panAmount, 0.f, panAmount < 0.f ? -panAmount - 1.f : panAmount - 1.f };
}
That code is using a triangle instead of a circular arc and the pan therefore doesn't transition evenly but can work well for known pan amounts.
You could use a sin/cos combination (as used in eXpl0it3r's code above) in the function instead; only the return line would need modifying...
-
Oh, thanks Hapax! That works perfectly. I should have realized it would need to work that way since it's designed for 3D scenes.