Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: How to properly remove sfml::sound/music (AL lib: (EE) alc_cleanup: 1 device...)  (Read 6657 times)

0 Members and 1 Guest are viewing this topic.

Retrorage

  • Newbie
  • *
  • Posts: 2
    • View Profile
So all the sounds and music work, however when I exit the program I get this warning (AL lib: (EE) alc_cleanup: 1 device not closed).

So I was able to resolve this warning for sfml::music by using "GameData->assets.music.~SoundSource();" before I exited the window. However I am not sure that is proper.

I cannot resolve this warning for sound objects.
This is how I load sound buffers in a class called assetManager.

void AssetManager::LoadSoundBuffer(const string name, std::string fileName) {
        sf::SoundBuffer sB;
        if (sB.loadFromFile(fileName))
            this->_soundBuffers[name] = sB;
        else
            std::cout << "\n Failed to load sound!";
   }
   //Music cannot be loadedaccroding to SFML documentation (due to music being long it will eat up a bunch of memory and this must
    //be loaded on the go in small chucks during runtime

   void AssetManager::RemoveSoundBuffer(const string name) {
      if (this->_soundBuffers.find(name) != _soundBuffers.end())
         _soundBuffers.erase(name);
   }

And I hold a sf::sound object as a private member in a class called menuState.

According to some of the other post I read, possible issues for this is that I am not letting the new thread sounds create, exit and remove their resources, before the program closes, or that my sound buffers are being removed before the sound gets removed.

Any suggestions on how I should go about this!
« Last Edit: December 20, 2019, 09:06:00 pm by Retrorage »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
So I was able to resolve this warning for sfml::music by using "GameData->assets.music.~SoundSource();" before I exited the window. However I am not sure that is proper.
I'm sure it's not proper. ;)
In fact, calling destructors manually is undefined behavior (UB), if they are called again automatically.

        void AssetManager::RemoveSoundBuffer(const string name) {
                if (this->_soundBuffers.find(name) != _soundBuffers.end())
                        _soundBuffers.erase(name);
        }
I don't know what data structure _soundBuffers is -- but if it's a std::vector or std::deque, erasing one element will invalidate pointers to the erased element and all subsequent elements. Since every sf::Sound stores a pointer to a sf::SoundBuffer, you may trigger UB here as well, due to dangling pointers. A std::list or std::map would not have this problem, they are stable data structures.

It's relatively simple to get sound lifetimes right, you need to consider the following rules:
  • Use automatic memory for all the objects (STL containers and smart pointers). Do not use new/delete, manual destructor calls or other unnecessarily low-level techniques.
  • Every sf::SoundBuffer must outlive all the sf::Sound instances that refer to it.
  • A sf::SoundBuffer must not be moved/copied while it's in use (e.g. by erasing from a container).
  • Don't allocate any SFML objects globally (this obviously includes other objects that are global and contain SFML objects). Initialization and destruction order of global variables is a big mess in C++.
In case you want a readily available solution for managing resources like sf::SoundBuffer, you might be interested in my library Thor (here's a tutorial which shows some examples).
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Retrorage

  • Newbie
  • *
  • Posts: 2
    • View Profile
So I had the soundbuffers stored in a std::map, and it turns out I did not need to call GameData->assets.music.~SoundSource(); at all.

But I was rolling through code thinking about

  • Every sf::SoundBuffer must outlive all the sf::Sound instances that refer to it.


And I found the error, and a pretty big one at that.
I had a dynamic object that had sf::sound member that was not being properly removed. Which was why, like you said, a sound object was outliving the soundbuffer it was refering too. Thanks a lot! Really big help!