SFML community forums

Help => Audio => Topic started by: GarrickW on June 06, 2013, 09:13:58 pm

Title: Sounds stop playing when other Sounds are deleted?
Post by: GarrickW on June 06, 2013, 09:13:58 pm
So I'm not 100% sure what is going wrong here, but the following code is not working as expected.

void Cycle(float Time, float Pitch)
{
    //Reduce the timer
    m_PlayTimer -= Time;

    //If it's zero, play the sample
    if (m_PlayTimer <= 0.0)
    {
        //Add the sound!
        m_SoundList.push_back(sf::Sound());
        unsigned short NewSound = m_SoundList.size() - 1;
        m_SoundList[NewSound].setBuffer(*SoundManager::GetSoundBuffer(1));
        m_SoundList[NewSound].setVolume(30.0);
        m_SoundList[NewSound].setPitch(Pitch);
        m_SoundList[NewSound].play();

        //Restore a positive value to the timer
        m_PlayTimer = 1.0;
    }

    //Cull finished sounds
    for (unsigned int ii = 0; ii < m_SoundList.size(); ++ii)
    {
        //Test whether the sound is finished or not; if so, remove it
        if (m_SoundList[ii].getStatus() == sf::Sound::Status::Stopped)
        {
            m_SoundList.erase(m_SoundList.begin() + ii);
            std::cout << "Sound deleted!\n";

            //If ii is the same as the size, there are no further sounds
            if (ii == m_SoundList.size())
            {
                break;
            }
            //Otherwise, there are further sounds!  Decrement ii so as not to skip any
            else
            {
                --ii;
            }
        }
    }
}

What happens is that sometimes, when one Sound finishes after another has started (I also modify the pitch of the sound, so the lengths of each sf::Sound are slightly different), both sounds are deleted in the same call, which kills the newer sound before it has had a chance to play out.  It's as though the algorithm thinks that both sf::Sound objects return Stopped upon calling getStatus().

Any idea what might be causing this, and how I can get things to work as expected?
Title: Re: Sounds stop playing when other Sounds are deleted?
Post by: GarrickW on June 07, 2013, 12:11:14 pm
Hm, so I solved the problem by using an std::vector<sf::Sound*> as a container, so pointers instead of objects.  Otherwise everything remained the same (obviously, I delete the object before disposing of its pointer in the culling loop, too).  Not sure why that worked, but it did.
Title: Re: Sounds stop playing when other Sounds are deleted?
Post by: Nexus on June 07, 2013, 12:43:30 pm
When std::vector grows, it may relocate all its objects in memory. This is not good for sf::Sound objects, they must stay alive while they are played.

std::vector<sf::Sound*> is a bad idea because you introduce manual memory management. If you really needed that, std::vector<std::unique_ptr<sf::Sound>> would be more appropriate, since it takes care of the memory.

However, you should rather consider a different STL container which does not have this problem, or use reserve(). The container adapter std::queue is quite appropriate for sounds, if you need more features you can directly use the underlying std::deque.