Is volume done per sound or managed by the renderer or player?
Ohh, that's why we need playFx, playAmbient and playMusic!
So perhaps the correct solution is to retain those functions, only make them accept type Sound instead of StaticSound or StreamSound (formerly StrSound by the way) and then implement them under the covers using the name/player pair idea. Then, we can also have arbitrary sounds with arbitrary volumes. Finally, I would like the engine to support sounds that are attenuated (optionally) so that the volume is based upon the sound level for fx, ambient or music, but is attenuated, if that is the desire.
Lastly, I want the design to support multiple sounds of the same category (i.e, fx, ambient or music) -- this doesn't make that much sense for music, but it can for ambient. With the new Selection library, very interesting combinations can be glued together to create much more versatile ambient sounds. For it to be effective, we'll need to add the ability for Selections to have a delay between sounds, possibly random and probably implemented as a Selection object. Then, sounds can be added with random delays in between. Then, multiples of these can "play" at once, even though they will often be silent. Example:
- Bird Chirps - a random bird chirp from a list of birds followed by a delay of 1 to 30 seconds.
- Animal Sounds - a random sound from various (non-bird) animals followed by a delay of 60 to 120 seconds
- Wind Sounds - a random wind blowing sound with no delay
Then, you can have 3x Bird Chirps, and 1x of the other two for a more dynamic ambient daytime forest sound (just an example). The downside is the consumption of audio voices and I'm not entirely sure if OpenAL mixes sounds on its own or leaves that up to the hardware. I'm also not sure how many voices modern sound cards have these days.
But none of this has to work for now, I just want it to be considered and the design implemented in a way so that it can be supported later on with minimal changes (preferably, without changing the interface). So for now, I'm thinking of modifying all of the play functions to accept an optional string value specifying a named player to use and returning a string value specifying the actual player that's used with a default of an empty string meaning "any" for playXx() functions and "all" for stopXx() functions. So if I say soundRenderer.playAmbient(mySound) then it will return the name of the sound player, which will be "ambient0" if no other ambient sounds are playing. Then, if I later say playAmbient(myOtherSound, "ambient0") it will stop the current ambient sound and play the new one. However, if I want to play an additional ambient sound, I can say playAmbient(myOtherSound) and it will return "ambient1". Alternately, I can say soundRenderer.playAmbient(myOtherSound, "mySpecialAmbient") and the return value will always be "mySpecialAmbient".
Thanks hailstone!
Does this mean it might lead to multiple animations for the same action?
Precisely. In addition, you will have a fairly insane level of control (in your mod's definition) of how this will take place. Currently, my design does not support Star/Warcraft-style unit acknowledgments (i.e., complete with easter eggs if you continue to click on it and do not allow more than X milliseconds to pass between clicks (otherwise it starts over), but the "start over if more than X milliseconds pass between invcations is the only thing that's missing. You can currently have a collection of sounds that will play 3 random sounds, followed by a series of 5 sounds and then loops back to the begnning.
SerialSelection<Sound> mySounds(true); // loop = true
RandomSelect<Sound> someRandomSounds;
someRandomSounds.add(mySoundA, 1.f);
someRandomSounds.add(mySoundB, 2.f); // this one is twice as likely to play as the others
someRandomSounds.add(mySoundC, 1.f);
someRandomSounds.add(mySoundD, 1.f);
mySounds.add(someRandomSounds, 3); // add the someRandomSounds list as the 1st element of mySounds and have it repeat 3 times.
// This will actually cause someRandomSounds to be invoked 3 times and thus, produce
// a random selection each time
mySounds.add(someOtherSoundA);
mySounds.add(someOtherSoundB);
mySounds.add(someOtherSoundC);
mySounds.add(someOtherSoundD);
mySounds.add(someOtherSoundE);
The same is true for animations. For instance, for a martial artist warrior, you can have them attack using a few random attacks, but then have them execute a series of other attacks in a similar fashion, like a martial arts form. I'm only proposing this visually, but I suppose it's possible to have skills behave the same way, so that a smaller attack skill can be executed, followed by a more powerful one and finally the most powerful one if the attack on the same unit is continuing. Just an idea there.