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)