SFML community forums

Help => Audio => Topic started by: Moonglum on May 17, 2023, 09:27:04 am

Title: multiple concurrent sound effects
Post by: Moonglum on May 17, 2023, 09:27:04 am
Hi All.

I am writing a game which requires the player to launch up to 9 missiles in quick succession. There is a sound effect for the launch of the missile and a sound effect for each explosion. The only way I can avoid the next sound effect cutting off the previous sound effect is for each missile to have two sound definitions, one for shoot and one for explosion. I cant use arrays as this will stop the sound playing and I cant use functions for the same reason. Relevant sections of code are as follows: This is for the explosions ...

    sf::SoundBuffer missileBuffer0;
    sf::SoundBuffer missileBuffer1;
    sf::SoundBuffer missileBuffer2;
    sf::SoundBuffer missileBuffer3;
    sf::SoundBuffer missileBuffer4;
    sf::SoundBuffer missileBuffer5;
    sf::SoundBuffer missileBuffer6;
    sf::SoundBuffer missileBuffer7;
    sf::SoundBuffer missileBuffer8;
    sf::SoundBuffer missileBuffer9;
    sf::Sound missile0;
    sf::Sound missile1;
    sf::Sound missile2;
    sf::Sound missile3;
    sf::Sound missile4;
    sf::Sound missile5;
    sf::Sound missile6;
    sf::Sound missile7;
    sf::Sound missile8;
    sf::Sound missile9;

... and this is the explosion hit sound effect playback.

                                    switch (i)
                                    {
                                    case 0:
                                        if (!missileBuffer0.loadFromFile("rockhit.flac"))
                                        {
                                            cout << "No sound file";
                                        }
                                        missile0.setBuffer(missileBuffer0);
                                        missile0.play();
                                        break;

                                    case 1:
                                        if (!missileBuffer1.loadFromFile("rockhit.flac"))
                                        {
                                            cout << "No sound file";
                                        }
                                        missile1.setBuffer(missileBuffer1);
                                        missile1.play();
                                        break;

                                    case 2:
                                        if (!missileBuffer2.loadFromFile("rockhit.flac"))
                                        {
                                            cout << "No sound file";
                                        ...

... and so on, you get the idea. It does work but seems to be terrible code. I feel I have missed something very important which will avoid the need for this. Please can someone tell me if there is a better way to get this done?

Many thanks

Moon.
Title: Re: multiple concurrent sound effects
Post by: eXpl0it3r on May 17, 2023, 09:36:09 am
What you're missing is that the assumption you've made about not being able to use arrays or functions is wrong, or rather the understanding of why you "can't" use them is wrong.

As a first step you probably want to use a class to run your application in, this allows you to have the sound and sound buffers as member variables and extend the lifetime scope beyond the current method, without using global variables.

Next I'd recommend using something like a ResourceHolder (https://github.com/SFML/SFML-Game-Development-Book/tree/master/02_Resources/Include/Book) to manage the loading of your sound buffers. So you have to only load it once and can reuse it, while the resource is being properly managed.

And finally, to handle sounds in a nice way, I can recommend to use a std::deque<sf::Sound>, which allows you to pop_front() sounds that have finished playing and push_back() new sound instances without disturbing other already playing sounds.
Alternatively you can also use some other container to hold multiple instances of a sound, but you need to understand how they work. A std::vector for example will be moved in memory if you just keep push_back()-ing new instances, which then can lead to pausing of the current sounds being played.
Title: Re: multiple concurrent sound effects
Post by: kojack on May 17, 2023, 10:39:17 am
Also, if you are using the same audio file in each one, you only need a single SoundBuffer. You can have many Sound objects all sharing a single SoundBuffer (that you can load at the beginning so it doesn't cause a delay during the game).
So if your game has 2 different sound effects to play, you only need 2 SoundBuffers, then as many Sounds as you'd like.

The way my sound manager used to work was I had a vector of Sound pointers. For each sound I played I'd push a new sound object into the vector (pointers aren't hurt by the vector reallocating as it grows). Every update I'd loop over the sound vector and check to see if each sound had finished playing. If they had finished, I'd delete them and remove them from the vector.

These days I do it similar, but using the Entt entity component system to store the sounds.
(That's getting a bit complicated if you aren't used to ECS style programming)
Title: Re: multiple concurrent sound effects
Post by: Hapax on May 19, 2023, 09:09:54 pm
Although it's not been updated for a bit, you could try this:
https://github.com/Hapaxia/SfmlSoundSystem

It was designed to make using sounds in SFML more intuitive than doing it all manually.