1
Audio / Problems with 3d sound!
« on: December 25, 2016, 04:12:05 pm »
Hi,
Im building a 2d roguelite engine with sfml with the help of books.
Im going to make a summary of my code pretending that you can understand the problem without try to compile anything (the whole code is a mess) if u guys are not be able to understand the problem i will try to make a prototype.
So, im new to Sfml but i have had a lot of problems with sounds and buffers (we need to have both in the same context!!!) but finally i decided to create a static class to store the two pointers in the same space.
The class that handles sound:
This class works! im already using it, i can get the pointers to sounds and play, but... im having problem with these:
sound->setAttenuation(5.0f);
sound->setMinDistance(80.0f);
when i try to make a sound 3d this dont work, Im Highlighting setAttenuations and setMinDistance methods because it might be the problem, 4 example: sound->setRelativeToListener(true) works perfetly but the two next instructions seems that not cause i cannot hear any sound in the moment that i bind the sound to a position.
To understand the problem completely im going to show u how i call this class, and a alternative that works!
this setup can be stupid but its only to express the problem.
the method that play the sound:
well now im going to show the failed code and the "sucess" code, all the code belongs to a class name GAME, is the main class of my engine and handles all the loops.
This fails:
If i save the sf::Sound as an attribute of game :
This works perfectly.
What can i do to get working my class with 3d sounds and without variables like sf::Sound m_enemyDieSound stored in my game class?
Sorry 4 my english, thanks.
Im building a 2d roguelite engine with sfml with the help of books.
Im going to make a summary of my code pretending that you can understand the problem without try to compile anything (the whole code is a mess) if u guys are not be able to understand the problem i will try to make a prototype.
So, im new to Sfml but i have had a lot of problems with sounds and buffers (we need to have both in the same context!!!) but finally i decided to create a static class to store the two pointers in the same space.
The class that handles sound:
std::map<std::string, std::tuple<int, std::unique_ptr<sf::SoundBuffer>, std::unique_ptr<sf::Sound>>> SoundBufferManager::m_soundBuffers;
int SoundBufferManager::m_currentId = 0;
int SoundBufferManager::AddSoundBuffer(std::string filePath, float attenuation, float distance)
{
// First check if the sound has already been created. If so, simply return that one.
auto it = m_soundBuffers.find(filePath);
if (it != m_soundBuffers.end())
{
return std::get<0>(it->second);
}
// At this point the texture doesn't exists, so we'll create and add it.
m_currentId++;
std::unique_ptr<sf::SoundBuffer> buffer = std::make_unique<sf::SoundBuffer>();
if (!buffer->loadFromFile(filePath))
{
return -1;
}
std::unique_ptr<sf::Sound> sound = std::make_unique<sf::Sound>();
sound->setBuffer(*buffer);
sound->setRelativeToListener(true);
sound->setAttenuation(5.0f);
sound->setMinDistance(80.0f);
m_soundBuffers.insert(std::make_pair(filePath, std::make_tuple(m_currentId, std::move(buffer), std::move(sound))));
// Return the texture.
return m_currentId;
}
sf::Sound & SoundBufferManager::GetSoundbyKey(std::string key)
{
// TODO: insert return statement here
return *std::get<2>(m_soundBuffers[key]);
}
// Gets a texture from the texture manager from an ID.
sf::SoundBuffer& SoundBufferManager::GetSoundBuffer(int textureId)
{
for (auto it = m_soundBuffers.begin(); it != m_soundBuffers.end(); ++it)
{
if (std::get<0>(it->second) == textureId)
return *std::get<1>(it->second);
}
}
int SoundBufferManager::m_currentId = 0;
int SoundBufferManager::AddSoundBuffer(std::string filePath, float attenuation, float distance)
{
// First check if the sound has already been created. If so, simply return that one.
auto it = m_soundBuffers.find(filePath);
if (it != m_soundBuffers.end())
{
return std::get<0>(it->second);
}
// At this point the texture doesn't exists, so we'll create and add it.
m_currentId++;
std::unique_ptr<sf::SoundBuffer> buffer = std::make_unique<sf::SoundBuffer>();
if (!buffer->loadFromFile(filePath))
{
return -1;
}
std::unique_ptr<sf::Sound> sound = std::make_unique<sf::Sound>();
sound->setBuffer(*buffer);
sound->setRelativeToListener(true);
sound->setAttenuation(5.0f);
sound->setMinDistance(80.0f);
m_soundBuffers.insert(std::make_pair(filePath, std::make_tuple(m_currentId, std::move(buffer), std::move(sound))));
// Return the texture.
return m_currentId;
}
sf::Sound & SoundBufferManager::GetSoundbyKey(std::string key)
{
// TODO: insert return statement here
return *std::get<2>(m_soundBuffers[key]);
}
// Gets a texture from the texture manager from an ID.
sf::SoundBuffer& SoundBufferManager::GetSoundBuffer(int textureId)
{
for (auto it = m_soundBuffers.begin(); it != m_soundBuffers.end(); ++it)
{
if (std::get<0>(it->second) == textureId)
return *std::get<1>(it->second);
}
}
This class works! im already using it, i can get the pointers to sounds and play, but... im having problem with these:
sound->setAttenuation(5.0f);
sound->setMinDistance(80.0f);
when i try to make a sound 3d this dont work, Im Highlighting setAttenuations and setMinDistance methods because it might be the problem, 4 example: sound->setRelativeToListener(true) works perfetly but the two next instructions seems that not cause i cannot hear any sound in the moment that i bind the sound to a position.
To understand the problem completely im going to show u how i call this class, and a alternative that works!
this setup can be stupid but its only to express the problem.
the method that play the sound:
// Plays the given soiund effect, with randomized parameters
void Game::PlaySound(sf::Sound & sound, sf::Vector2f position)
{
// Generate and set a random pitch.
float pitch = (rand() % 11 + 95) / 100.f;
sound.setPitch(pitch);
// Set the position of the sound.
sound.setPosition(position.x, position.y, 0.f);
// Play the sound.
sound.play();
}
this works!void Game::PlaySound(sf::Sound & sound, sf::Vector2f position)
{
// Generate and set a random pitch.
float pitch = (rand() % 11 + 95) / 100.f;
sound.setPitch(pitch);
// Set the position of the sound.
sound.setPosition(position.x, position.y, 0.f);
// Play the sound.
sound.play();
}
well now im going to show the failed code and the "sucess" code, all the code belongs to a class name GAME, is the main class of my engine and handles all the loops.
This fails:
SoundBufferManager::AddSoundBuffer("../resources/sounds/snd_enemy_dead.wav", 5.0f, 80.0f);
//later in the part of the code that need to play th sound
PlaySound(SoundBufferManager::GetSoundbyKey("../resources/sounds/snd_enemy_dead.wav"), position);
this code does not work, only works with position 0,0.//later in the part of the code that need to play th sound
PlaySound(SoundBufferManager::GetSoundbyKey("../resources/sounds/snd_enemy_dead.wav"), position);
If i save the sf::Sound as an attribute of game :
soundBufferId = SoundBufferManager::AddSoundBuffer("../resources/sounds/snd_enemy_dead.wav", 5.0f, 80.0f);
m_enemyDieSound.setBuffer(SoundBufferManager::GetSoundBuffer(soundBufferId));
m_enemyDieSound.setAttenuation(5.f);
m_enemyDieSound.setMinDistance(80.f);
//later
PlaySound(m_enemyDieSound, position);
m_enemyDieSound.setBuffer(SoundBufferManager::GetSoundBuffer(soundBufferId));
m_enemyDieSound.setAttenuation(5.f);
m_enemyDieSound.setMinDistance(80.f);
//later
PlaySound(m_enemyDieSound, position);
This works perfectly.
What can i do to get working my class with 3d sounds and without variables like sf::Sound m_enemyDieSound stored in my game class?
Sorry 4 my english, thanks.