New Sound Engine
From Armagetron Advanced Wiki
The sound engine is coming along nicely, but with the semester starting, I'm not going to be able to get it finished right now. Hopefully it's somewhat stable or relatively easy to troubleshoot if something's wrong with it.
Music gets installed to ::Data() /music . That's also where the default ingame playlist will be placed. The following tracks exist:
- Title Track (Thrown together by Lucifer as a placeholder, needs to be reworked into a real title track)
- Gui Track (When the Glass Breaks, by Raoul Duke. This is getting a good response and will probably stay)
- In-game tracks
- Only Fortress Walk, by Lucifer, which needs more work, is currently played ingame.
- Do I Know You?, also by Lucifer, is there, but a weird bug prevented it from playing.
No work is planned to fix the ingame playlist as it stands, until the aatrack format is created and supported by the eMusicTrack object. Then the ingame playlist using bundled music needs to be made to work.
There's a UI for this now. You can specify the complete path to a custom playlist, and then set it to use the custom playlist. Your custom playlist should be m3u format, but we're only loosely parsing it anyway. All you really need is a text file with one music file per line, complete path to the file. Lines that start with # are ignored, but in an m3u playlist those lines contain additional information we may want to parse for at some point. Playlists made in XMMS work fine.
The title track and gui track will still be played from bundled music! There is no plan to change this until we have support for some sort of music pack. Even then these tracks will be played from internal locations, and if the user wants his own custom tracks, he'll need to build a music pack to play them, when we have those ready to build.
Controlling the music player
There are some new global keybinds that you can use to control the media player ingame. These functions normally expected from a media player are supported by the keybinds:
- Play (will restart the current track if it's already playing)
- Previous (will always go to the previous track)
- Volume Up/Down (only controls music volume, sound effect volume is unaffected)
There are no default keybinds for these functions, you will need to go to Global Input Configuration and set them yourself.
There are mysterious crashes that are likely happening in the playlist class, or near it and happen when a new track is selected to play. It can happen when you join a server, or it can happen when you've been playing for awhile. There was a previous crash associated with the current song pointer, which is an iterator for the std::deque class, where it was unitialized, causing a segfault when the music player tried to play the first song. The playlist class and eMusicTrack have recently been factored a bit, so this is probably dust from that.
There is another mysterious crash with the bundled playlist. If all three lines are uncommented, the game will play two tracks and crash. No idea why, I have no intention of fixing this until the aatrack format is worked out and implemented.
- I believe these two issues are fixed now, and it was a problem with GetFileMimeExtension when the string contains only whitespace (a bug caused by the playlist accepting empty strings, the playlist still accepts empty strings, which is still a bug to be fixed, but tString shouldn't fail because of it). If they are fixed, these two paragraphs can be removed.
In order to keep download size small and still be able to have full-size songs, I'm planning the aatrack format to allow us to take several clips and chain them together into a complete song. The format is based on the Windows INI file format, but the parser isn't written. There's a place in the code for it, but it's not finished.
Here is what it should look like:
[header] author = Dave Fancella title = Fortress Walk record = None year = 2006 genre = Rock [tracks] 1 = fortresswalk.ogg [sequence] 1
The header will contain information like what you'd expect to see in id3 tags in mp3 and ogg vorbis files. This is for the entire song, but the song itself is broken down into several tracks. The tracks section will list each track and give it an identifier. Here, the identifier for the only track is "1", but it's intended that any arbitrary identifier can be used. The sequence section will then list the sequence of the tracks, by identifier.
The sequence section deviates from the Windows INI file format, but the rest doesn't. The sequence section should contain on each line a track to be played. I'd like to have the idiom "1*4" supported, where sequence "1" will be repeated 4 times.
eMusicTrack should support this format, and there is already a placeholder method to handle it. It needs to be hidden from the callers, so the caller and indeed the playlist object shouldn't care what format the files are, and eMusicTrack will just do the right thing for any file.
Sound effects are partially implemented. Here's what works:
There are two kinds of pushbutton effects. There's a simple pushbutton, which just plays the effect at its volume, with no effects processing. There's a 3d pushbutton effect which takes an eCoord and plays the effect in 3d. This is handled by function overloading, so to play any kind of pushbutton effect, you will always use eSoundMixer::PushButton, but the argument list changes if you want to have a 3d effect.
All sound effects are mapped as enums, so you will say "PushButton(CYCLE_MOTOR);", for example, to play the cycle motor sound. Check eSoundMixer.h for a complete list. This enum mapping is likely only temporary! But it's easy to find, so don't be shy about supporting more sound effects.
- Enter the game
- Leave the game (both will be played when joining a server and also when entering a local game)
- Begin of round
- End of round
- Begin of match (supersedes round start)
- End of match
- Man death sound (to go with an explosion, should have these options:
- Team killed
...since those options are alread in the code)
- Wall drop (nothing complex, for now...)
- Sound when a new player joins (for players already there)
- Zone spawn (I have one already)
- Zone collapse
- Player kicked
- 10 minute warning
- 5 minute warning
- 2 minute warning
- 1 minute warning
- 30 second warning
- 10 second warning
- You have been kicked
- You have been banned (please keep these two clean :) )
This includes the cycle motor and the grind effect. This is unimplemented, although I've tried several methods to make it work. Here is how it should look:
Whenever the eGameObject of camera focus is changed, eSoundMixer gets a new owner. When an eGameObject spawns, if it has a continuous effect, it should direct eSoundMixer to start playing it. In the PlayContinuous argument list is the eGameObject that generates the sound. Using an effect callback, the mixer should compute the 3d effect for that sound based on the eGameObject that owns the sound and the eGameObject that has camera focus.
So, when a gCycle spawns, it needs to give the cycle motor sound. This part works. But when the cycle dies, it needs to end the sound, and this part doesn't work.
I don't know how the grind is handled now, but it needs to be a single sound file looped, and whenever a grind is detected, PlayContinuous should be used to play it. This will allow a cycle to get grinding noises from both sides when it's in a tunnel!
Standard Effects Processing
We need to have several effect processors that we use on all effects. None of them are implemented, but two of them need to be implemented for continuous effects to work at all.
- Speed variation (only used for cycle motor and grind, and any other sound that needs to vary it's speed)
- 3d effect (we might be able to use SDL_Mixer's, as we are now, but I'm not counting on it)
- Doppler effect
The reason I don't think we can rely on SDL_mixer's 3d effects is because it's a one-off call. We need something that will be able to compute loosely in realtime based on the cycle's changing position, so if an explosion happens immediately in front and to the right of a fast moving cycle, that explosion effect needs to be doppler shifted, and it also needs to feel like the cycle is driving past it. I intend to do this first by copying and pasting the SDL_Mixer effect into our own callback and then tweaking it to work with our own data structures.
Speed variation is a complex topic that I won't get into, except to say that we need to support varying the motor speed in the same way armagetron has traditionally done it. The doppler effect is separate from this, but similar. I expect z-man has the formulas we need to implement it, once a basic effect callback system is implemented.
The reverb effect is only a possibility, not a plan. The idea is that we could vary the reverb of any given effect based on it's position in the grid. So on a really large grid, for sound effects in the middle that are also heard in the middle, no reverb makes sense. But sound effects in the middle that are heard by the walls should have a bit of an echo. There are some good, low-cpu-draining ladspa reverbs we can use here if need be, but we may not do it at all. If we do it, it's intended only for sound effects that will have a 3d effect applied.
The problem I'm having with PlayContinuous is that one or the other or both of the eGameObjects involved, either the sound owner or the mixer owner, are being deleted, and the mixer is not finding out about it in time, so it segfaults trying to compute the 3d effect on one or more eGameObjects that don't exist. This is probably a simple fix, but it's something someone who knows more about how the eGameObjects are managed could give the right comment or something to point me in the right direction. :) Hopefully after the 0.2.8 release we can get this straightened out.
No speed variance effects means there's currently no way to confirm the 3d effect on the cycle motor works. So this needs to be implemented, along with the effects callback system.
I really like the idea of supporting LADSPA plugins to some extent, so I'd like the effects plugin architecture to be open-ended enough that we can add support for ladspa, but there's no ladspa requirement in the initial implementation. This is the only part of the sound engine that has yet to be laid out, so if you work on it, you'll be on new ground.
I'd like to support sound skins with this new setup, but that's as far as I've gotten in working it out. After I get the music engine working properly, and cycle motor and grind sounds, then I'll look at sound skins and spec them out, unless someone beats me to it.