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

Author Topic: Sounds stop playing too early when using std::vector  (Read 3928 times)

0 Members and 1 Guest are viewing this topic.

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Sounds stop playing too early when using std::vector
« on: June 13, 2016, 02:35:53 am »
Hi Folks,

So I am using sf::Sound for the first time and I am having a bit of trouble where sounds seem to stop playing before the entire wav file has finished playing.

What I have is:

- A std::vector of sf::Sound in my private section of my class.

vector<sf::Sound> soundVtr;
 

- When I play a sound I simply push_back a new sf::Sound to this std::vector

soundVtr.push_back(sf::Sound(*passed_SoundBuffer));
 

- During each game tick/loop, I call the below removeStoppedSounds() which goes through the std::vector of the sf::Sounds to check the status. If the status is sf::SoundSource::Stopped

However as stated, when I call the removeStoppedSounds() during the gameloop, I find that sounds don't finish, i.e. a 2 second wav file gets stopped withing a few milliseconds.

If I comment out the call to removeStoppedSounds() then it plays until the end. So I am assuming this method is something removing the sf::Sound before it can be played until the end of the wav file.

So is this something to do with using std::vector? If yes, then how I can store sf::sounds so that they can be played until the end of the wav file?

Or something to do with sf::Sound::getStatus()?

bool soundsList::isSoundPlaying(sf::Sound *passed_Sound)
{
        if (passed_Sound->getStatus() == sf::SoundSource::Stopped)
        {
                //cout << "stopped playing\n";
                return false;
        }
        else
        {
                cout << "still playing\n";
                return true;
        }
}


void soundsList::removeStoppedSounds()
{
        for (int i = 0; i < soundVtr.size(); i++)
        {
                if (!isSoundPlaying(&soundVtr[i]))
                {
                        soundVtr.erase(soundVtr.begin() + i);
                        cout << "erased sound at index " << i << "\n";
                        //i--;
                }
        }
}
 

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: Sounds stop playing too early when using std::vector
« Reply #1 on: June 13, 2016, 02:48:54 am »
Ok so I tried changing from a std::vector to a std::queue and this seems to have resolved the issue.

So my remove method is now

void soundsList::removeStoppedSounds()
{
        for (int i = 0; i < soundVtr.size(); i++)
        {
                if (!isSoundPlaying(&soundVtr.front()))
                {
                        //soundVtr.erase(soundVtr.begin() + i);
                        soundVtr.pop();
                        cout << "erased sound at front of queue " << i << "\n";
                        //i--;
                }
        }
}
 

I am assuming std::vector is doing something different when doing a erase than when a std::queue is doing a pop?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
AW: Sounds stop playing too early when using std::vector
« Reply #2 on: June 13, 2016, 11:49:23 am »
When you erase something in the middle of a vector, all the elements that follow will be copied back one position which will stop the playing.

A qeue or deqeue solves this problem.

Additionally pushing back elements can lead to all elements being copied to a new memory location when resizing the vector.
« Last Edit: June 13, 2016, 11:51:56 am by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Sounds stop playing too early when using std::vector
« Reply #3 on: June 13, 2016, 12:33:12 pm »
Quote
A qeue or deqeue solves this problem.
That's not accurate. A std::deque (?) may have to move its elements, and a std::queue itself doesn't guarantee anything, it all depends on its back-end (it's just an interface to another type of container), which is safe by default (std::list).

What you must avoid is the container moving its elements around, which causes copying and destructing them -- which is the root of your problem. std::list (or anything based on it) is safe because it's internally a linked-list with each node allocated dynamically. When you insert or remove something, the nodes don't need to move, there are just a few pointers to reassign.
Laurent Gomila - SFML developer

Ezekiel

  • Newbie
  • *
  • Posts: 23
    • View Profile
Re: Sounds stop playing too early when using std::vector
« Reply #4 on: August 03, 2016, 02:57:16 pm »
Greetings All:

I notice in the changed to queue section, &soundVtr.front() appears to look at the same position each loop, unless the last loop popped that one out.  So if a long sound is playing there, there could be many finished smaller sounds in the queue that didn't get checked and removed.  Keep in mind, if the longest sounds aren't very long, and there are few others following in that time, it may not be a large issue;

I have used other containers the odd time, but usually find they take some research to know them well, so I can't see if queues or lists also have to copy-paste-destruct issue that vectors have.

Most of the time I use the vector, so I suggest using vector<sf::Sound*>.  Create a "new" sf::sound and pushback the pointer, remove the '&' from "if (!isSoundPlaying(&soundVtr))" and add "delete soundVtr;" before the "erase" command.  The vector can move the pointers wherever it needs to, they will still be the pointers.

I hope this helps, though other containers could be much better.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Sounds stop playing too early when using std::vector
« Reply #5 on: August 03, 2016, 08:42:57 pm »
If you're dynamically creating and sounds as they're needed, use std::list (as stated above).

Another option, however, is to create a permanent vector of sounds that never gets modified and then use and re-use sounds.

Use whichever you prefer or require for the task; each method has its own pros and cons.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*