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

Author Topic: How to play several sound effects simultaneously?  (Read 16146 times)

0 Members and 1 Guest are viewing this topic.

mkalex777

  • Full Member
  • ***
  • Posts: 206
    • View Profile
How to play several sound effects simultaneously?
« on: October 23, 2015, 01:40:47 pm »
I need to play several sound effects simultaneously. Actually it's short ogg files which should be played on game events. Game events sometimes may happens very quickly, so there is need to play it simultaneously.
Currently I'm create 3 Sound objects and use first ready instance to play the effect.
But sometimes it happens that all 3 Sound objects is busy (already playing some effects) and in such case the next effect is just skipped.
I think it's not a good idea to create 5-10 Sound objects for such purposes.
So, is there any better way to play several sound effects simultaneously?
« Last Edit: October 23, 2015, 01:44:03 pm by mkalex777 »

Gambit

  • Sr. Member
  • ****
  • Posts: 283
    • View Profile
Re: How to play several sound effects simultaneously?
« Reply #1 on: October 23, 2015, 01:58:36 pm »
Store all of your sounds in a vector and play them then you can check if they are playing each tick and if they are then remove them.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: How to play several sound effects simultaneously?
« Reply #2 on: October 23, 2015, 02:04:22 pm »
Better even, use a queue. Push new sounds and constantly pop the sounds that have stopped.

Vectors are a bad choice because they relocate elements, stopping sounds in the process.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
How to play several sound effects simultaneously?
« Reply #3 on: October 23, 2015, 02:04:33 pm »
Nexus ninja-ed me :(

Rather use a std::deque. That way you can push back new sound objects and pop front ones that have stopped playing.
« Last Edit: October 23, 2015, 06:55:31 pm by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

mkalex777

  • Full Member
  • ***
  • Posts: 206
    • View Profile
Re: How to play several sound effects simultaneously?
« Reply #4 on: October 23, 2015, 05:59:14 pm »
Better even, use a queue. Push new sounds and constantly pop the sounds that have stopped.

Vectors are a bad choice because they relocate elements, stopping sounds in the process.

I don't need a queue, I need simultaneous (parallel) playback of several sound effects.
For example I have 3 sound effects - A, B and C.
I need to start playing effect A, then start effect B (while A is still playing) and then start effect C (while effects A and B is still playing). I don't need a sequence playback, I need to play it in parallel with no delay and queue.
The limit is to play for about 5-10 sound effects in parallel. And I don't need to be notified that playback is complete. It's just a sound events....
« Last Edit: October 23, 2015, 06:06:38 pm by mkalex777 »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: How to play several sound effects simultaneously?
« Reply #5 on: October 23, 2015, 06:55:23 pm »
Yes, that's why you use a std::deque. You for example emplace_back a new sf::Sound instance, then call play on it and move on. If a second effect gets triggered you just emplace_back a new sf::Sound instance, call play on it and move on. etc.
Every now and then you check the front item in the deque if it's still playing and if not, you remove it and check the next front element etc.

Just because you place it on a (double ended) queue doesn't mean that only one instance can be played at once. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

mkalex777

  • Full Member
  • ***
  • Posts: 206
    • View Profile
Re: How to play several sound effects simultaneously?
« Reply #6 on: October 23, 2015, 07:24:53 pm »
Yes, that's why you use a std::deque. You for example emplace_back a new sf::Sound instance, then call play on it and move on. If a second effect gets triggered you just emplace_back a new sf::Sound instance, call play on it and move on. etc.
Every now and then you check the front item in the deque if it's still playing and if not, you remove it and check the next front element etc.

Just because you place it on a (double ended) queue doesn't mean that only one instance can be played at once. ;)

I already implemented it with just an array of Sound and using the first Sound instance with status != playing to play a new effect. But I'm not sure... I think that create several Sound instances is not good, isn't it?

Currenly I'm using 3 instances of Sound. I can add some more Sound instances into array, so it will be able to play more sounds in parallel, but I'm not sure if there is any issue with memory consumption or something else...
« Last Edit: October 23, 2015, 07:37:32 pm by mkalex777 »

Arcade

  • Full Member
  • ***
  • Posts: 230
    • View Profile
Re: How to play several sound effects simultaneously?
« Reply #7 on: October 23, 2015, 07:46:54 pm »
Assuming I understand your question correctly, it is fine to have several sound instances. According to the SFML audio tutorial you just need to keep the number under 256.

If you are worried about memory consumption just give it a try and see what happens. Assuming your sound effects aren't very large you shouldn't have any issues with it.
« Last Edit: October 23, 2015, 07:49:14 pm by Arcade »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
How to play several sound effects simultaneously?
« Reply #8 on: October 23, 2015, 08:29:23 pm »
As Arcade said the limit (by OpenAL) is 256 instances and of course you can run multiple instances, that's the whole point of having a (non-static) class. ;)

And you should finally stop to prematurely think about performance when you a) don't even know how it works and b) you do not have a performance issue.

Read this. ;)
« Last Edit: October 23, 2015, 08:51:31 pm by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

mkalex777

  • Full Member
  • ***
  • Posts: 206
    • View Profile
Re: How to play several sound effects simultaneously?
« Reply #9 on: October 24, 2015, 12:30:36 am »
As Arcade said the limit (by OpenAL) is 256 instances and of course you can run multiple instances, that's the whole point of having a (non-static) class. ;)

And you should finally stop to prematurely think about performance when you a) don't even know how it works and b) you do not have a performance issue.

Read this. ;)

if it's designed to use 256 instances, then ok.

About performance, I'm optimizing key points found with profiler and performance logger. If some code eats 95% of time, it definitely should be optimized. So, if you're talking about 205 vertices issue, I think it's a problem, because code consumes 100% of cpu core time instead of expected max 1%
« Last Edit: October 24, 2015, 12:38:17 am by mkalex777 »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: How to play several sound effects simultaneously?
« Reply #10 on: October 24, 2015, 04:31:11 pm »
I already implemented it with just an array of Sound and using the first Sound instance with status != playing to play a new effect. But I'm not sure... [...] Currenly I'm using 3 instances of Sound. I can add some more Sound instances into array, so it will be able to play more sounds in parallel, but I'm not sure if there is any issue with memory consumption or something else...
Why would you use a static array if you need a dynamic number of sounds? That's the whole reason why STL containers exist in the first place. eXpl0it3r already explained why a queue is appropriate in this case.

I think that create several Sound instances is not good, isn't it?
Of course it's good, how would you play multiple sounds in parallel otherwise? Don't just assume things that are nowhere written in the documentation and make everything more complicated with crazy designs ;)
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

mkalex777

  • Full Member
  • ***
  • Posts: 206
    • View Profile
Re: How to play several sound effects simultaneously?
« Reply #11 on: October 24, 2015, 08:56:33 pm »
I already implemented it with just an array of Sound and using the first Sound instance with status != playing to play a new effect. But I'm not sure... [...] Currenly I'm using 3 instances of Sound. I can add some more Sound instances into array, so it will be able to play more sounds in parallel, but I'm not sure if there is any issue with memory consumption or something else...
Why would you use a static array if you need a dynamic number of sounds? That's the whole reason why STL containers exist in the first place. eXpl0it3r already explained why a queue is appropriate in this case.

 Actually I'm using sfml from c# and using List<Sound> instead of array, so there is no problem to add a new Sound, but I'm using fixed amount of Sound instances to avoid delays to create new Sound instance.
I increased the amount of Sound instances to 8 and it seems that all works ok.

By the way, I don't think that queue will be a good choice for such purposes. It will be a complicated logic to create, enqueue, dequeue, peek, check state and destruct Sound instances on each sound event. And it will works slower. Using just a list of Sound instances is much easy and faster solution. Because you will not need to create, enqueue, dequeue, peek and destruct. You're just looking for a ready Sound instance in the list and using it.
« Last Edit: October 24, 2015, 09:06:30 pm by mkalex777 »

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
Re: How to play several sound effects simultaneously?
« Reply #12 on: October 25, 2015, 01:57:30 am »
A C# List<T> is just a wrapper around an array... For most intents and purposes, it's equivalent to a C++ std::vector<T>.

A queue works quite well for Sounds. You push things to a queue that you want to be played. Check the queue, pop off x amount of sounds, and play them. And for the amount of sounds that you would have playing at any time, performance of a queue really shouldn't be much of an issue vs an array.

mkalex777

  • Full Member
  • ***
  • Posts: 206
    • View Profile
Re: How to play several sound effects simultaneously?
« Reply #13 on: October 25, 2015, 02:41:09 am »
A C# List<T> is just a wrapper around an array... For most intents and purposes, it's equivalent to a C++ std::vector<T>.

A queue works quite well for Sounds. You push things to a queue that you want to be played. Check the queue, pop off x amount of sounds, and play them. And for the amount of sounds that you would have playing at any time, performance of a queue really shouldn't be much of an issue vs an array.

Actually List<T> is not a wrapper at all and if you naming it "array" (this is incorrect, at least in terms of .net), then you should name it "dynamic array", because it's growing collection, you can add and remove items into it. By the way .net has separate internal implementation for arrays (fixed arrays in your terms). It allows to improve performance when you work with array in compare to other collections. So, List<T> is not array at all.

Here is example on how I'm using List<T> to play the sound:
        private readonly List<IDisposable> _disposables = new List<IDisposable>();
        private readonly List<Sound> _sound = new List<Sound>();

        public void Init()
        {
            for (var i=0; i < 8; i++)  // create 8 sound instances
                _sound.Add(new Sound());
            _disposables.AddRange(_sound);
            // ...
        }

        public void Dispose()
        {
            foreach (var disposable in _disposables.ToArray().Reverse())
            {
                var sound = disposable as Sound;
                if (sound != null)
                {
                    sound.Stop();
                }
                disposable.Dispose();
                _disposables.Remove(disposable);
            }
        }

        private void PlaySound(SoundEffect sfx)
        {
            if (_sound.Count == 0 || !_sndMap.ContainsKey(sfx))
                return;
            var sound = _sound
                .FirstOrDefault(arg => arg.Status != SoundStatus.Playing);
            if (sound == null)
                return;
            sound.SoundBuffer = _sndMap[sfx];
            sound.Play();
        }
 

This code works fast, because there is no need to create/dispose new Sound instance to play the sound.
And it allows to control maximum amount of parallel sounds.

And it extensible, if you want to add a new Sound instance on the fly (to avoid skip of some sounds when all Sound instances are busy), you can modify it in the following way:
        private void PlaySound(SoundEffect sfx)
        {
            if (!_sndMap.ContainsKey(sfx))
                return;
            var sound = _sound
                .FirstOrDefault(arg => arg.Status != SoundStatus.Playing);
            if (sound == null)
            {
                // all existing Sound instances are busy, so create new one on the fly
                if (_sound.Count >= 256) return;  // check OpenAL limit first
                sound = new Sound();
                _disposables.Add(sound);
            }
            sound.SoundBuffer = _sndMap[sfx];
            sound.Play();
        }
 

With such modification a new Sound instance will be created on the fly in case when all existing instances are busy. It works like Sound cache, already created Sound instance which is not busy will be reused for a new sound play instead of create new one.

Can you show the example on how you can implement so simple, extensible and fast solution for sound with Queue<T>? (you can show it in C++, there is no confusing with Queue<T> between C# and C++, it means the same thing and works in the same way)
« Last Edit: October 25, 2015, 02:01:49 am by mkalex777 »

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
Re: How to play several sound effects simultaneously?
« Reply #14 on: October 25, 2015, 05:31:31 am »
Actually List<T> is not a wrapper at all and if you naming it "array" (this is incorrect, at least in terms of .net), then you should name it "dynamic array", because it's growing collection, you can add and remove items into it. By the way .net has separate internal implementation for arrays (fixed arrays in your terms). It allows to improve performance when you work with array in compare to other collections. So, List<T> is not array at all.

Read the reference code yourself. It is essentially a wrapper. It handles the reallocations for you.