Sound/Music

Everything related to the code /
Tout ce qui touche au code
Post Reply
User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Sound/Music

Post by Cire » Sat Dec 02, 2006 4:30 am

So i'am getting ready to start the new handler for sound/music, and this is one of my strong point areas. Having written my own media player and sound systems i'am quite experienced within this avenu, however sadly most of my experience lies within windows.

Starting out I begin using the most powerful audio system out there which is called 'FMOD', now 'FMOD' does support cross platform, so it will work under windows/linux/mac/ect, and I am experienced with this as well, last week I recommended it to zuff and he agreeed that we should use it.

Now there are some decessions that we need to address before we get too far into the project and wish we implemented them in the first place.

We can split audio into 2 parts, first thier is the music part, and then thier is the sound part. Music of course has not many settings besides what to play, and how loud to play it as well as a buffer size for playing it. Keep in mind that when writting this i'am also gona enable the ability to completly skip music or sound sources all together as well. Now like TA, we could have the engine signal some events to trigger music into playing something else, though the user could simply override this.

So for music we are looking at an event system which can trigger some files to be played, a master volume setting, a buffer size setting, with the ability to stop/pause/shutdown/startup music system, the ability to incrase/decress the volume level, and finally the ability to read in a playlist, eventually maybe even generate a playlist, or configure playlists in the engine. What needs to be decided however is what types of music we should support, obviously mp3, what others however? wma perhaps?

Nextup is sounds, it again needs a master volume level on its own, but sound can also take into effect attributes, mainly 3d sound that represents how far away the sound is, as well as how far we moved away from that sound in some cases. TA don't support this but I think we should, but it does require further calculations on our behalf in the game engine for each sound we are playing. Which brings up another question how many channels should we try to allocate for sound, I suggest 2, now if we try to play more then 2 sounds fmod will do mixing, so we will simply alternate channels to get the most outa play with minimal mixing. Now i'am gooing to assume that the only sound format that we are going to use is 'wav' files.

So for sound options, a master volume level, do we support 3d sound? Options for user to completely shutdown/startup the sound system, with 2 channels? There are alot of options we could add but right now I don't see any purpose in them. Such options include reverb, echo, and various forms of sound fx's, perhaps later we will support them.

Comments/suggestions?

P.S. once this system goes into play we will need to include a .so file for linux, and a .dll file for windows. I also suggest we start releasing just binaries for those who could give a rats ass about the source.


++Cire.

User avatar
Balthazar
Moderator
Posts: 2055
Joined: Wed Nov 01, 2006 4:31 pm
Location: Russian Federation
Contact:

Post by Balthazar » Sat Dec 02, 2006 8:56 am

1. It`s a nice idea with playlist, but I don`t think that it is usefull option. It would be more than enough just to be able to specify Music folder, where the music will be. Of course, the playlist option gives much more abilities to set in-game music, so it`s the question of willing and time.

2. About in-game sound in *.wav format. Why can`t we use *.mp3 or (what is better) *.ogg format. Many modern games using *.ogg vorbis format for in-game sounds. We must remember, that most all the people download ta3d via Internet and adding sounds - will increase size of project very much, especially using *.wav. I suggest to convert all in-game sounds in *.ogg or *.mp3 because of size.

If there are some serious problems with high-compressed sounds, we can compress all sounds in *.ogg or *.mp3 and while installing ta3d - decompress all nessesary sounds from *.mp3 to *.wav. (For example Mp3towav soft).

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Sat Dec 02, 2006 9:43 am

For music we should support at least mp3, ogg, wma since many users will use those formats. For game sounds, TA's sounds are .wav but we could allow playing mp3, ogg, wma as well, it will allow modders to reduce the size of their mods, and maybe allowing TA3D to run faster after converting those files. But converting TA's sounds is not a priority and not always necessary since it's mainly small sounds (explosions, ...) it will just introduce more calculations for nothing.

The playlist system should not be modified for now, we use the music/playlist.txt and it's enough for now, we will improve this later when we will focus on GUI.

3D sound is good and sound is already in 3D (stereo only) with all needed calculations but we don't need more effects since it would disturb players and add nothing to the game.

Like in TA, TA3D plays music depending on what's happening (set in the playlist.txt), you can improve that system if you want, and music control would be nice (pause, play, stop, skip this file, ...) but should be hidden during game and shown only when player decide to use it.

By 2 channels you mean stereo?? We could do more than that with fmod ?
=>;-D Penguin Powered

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Sat Dec 02, 2006 2:16 pm

MP3 for sounds is a very bad idea, you want something that the computer don't need to spend time decoding to play, think about how often a user is causing sound events, alot of that time should not be spent decoding, I don't know enuff about ogg to comment but wav requires little to no decoding, its ready to go and can pretty much be dumped directly to the sound card.

Playlist for now will be a simple text file, but future i will add to the gui to allow the user full configuration of the playlist.

I was pretty much at the same feeling with sound effects, 3d sound should be all we need.

In respects to channels no, that does not mean left/right ie stereo, it means an output sorta kinda, think of it like oh a cd player, that can output sound to a set of speakers, now the second cd player can also dump sound to those same speakers, the result is a mix of whatever each cd player is playing, so each is like an output, ie when ur playing something it takes awhile to play sometimes a few seconds, other times along time, if u tell that same channel to play another sound those two sounds become 'mixed', mixing if it has to be software preformed can take time.

Now the idea is, when we need to play sound 1, the sound manager class would select channel 1, and start playing it, then increment its 'mixing vlaue' to 1, when sound 2 needs to be played we examine channel 1 see that it would be mixing, and thus jump to channel 2 and see its free and repeat the process, start playing, increment mix value, when sound 4 needs to be played it would select the mixing value of the channels with the lowest, and increment its mixing by 1, as a sound finishes or is stopped, it would decrease that channels mixing vlaue by 1. The end result is that mixing would be kept to a min in most respects.

We really don't wana grab too many channels since it would just eat up resources, and sounds are pretyt short, 2 or 3 seconds at most, and it would also work on nearly all sound cards as nearly ever sound card has at least 4 channels (newer cards have many more channels, or support hardware mixing.

++Cire.

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Sat Dec 02, 2006 2:34 pm

I was thinking to mp3/ogg (it's the same compression principle) in order to allow modders to add long sounds to the game, not for explosions or those things. It could be used for end of game sound, if we want to play some music there.

We will need a channel for music, so 2 might not be enough. I think 4 channels should be used: 1 for music, 3 for other sounds, because during heavy battle you have more than 3 sounds played at a time: explosions, shots, units hits, ...

Of course wav remains the best choice for small sounds.
=>;-D Penguin Powered

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Sat Dec 02, 2006 3:07 pm

You had best run with 2, i know from experience, unless u start getting into complex enumerations and what not and doing prioritiazation and what not you will end up requesting all channels that a card supports, leaving none for os, which can be bad, and u may not always get that many.

2 channels will be plenty, as for mp3/ogg ect in music, the engine could/can/willl be able to request that 'this' music be played in which case the stream would be paused and the requested file be played (unless user has music turned off), when it finishes the users file would be reopended and continued from where it left off.

Thier really isn't much of a difference between music/sounds, except that music will 'stream' where sounds will be loaded into memory and kept there till the class is destroyed, so music could still play wav, ogg, and all other streamable formats, where sound is loaded played and then unloaded when not needed, i havn't exactly figured out how i will hand sound handles but that will come in time.

++Cire.

Neuralize
Posts: 13
Joined: Wed Nov 01, 2006 9:04 pm

Post by Neuralize » Thu Dec 07, 2006 7:09 am

CD mp3 and Ogg for music.
Wav for game sounds.

Make sure that at some point you implement the dynamic music functionality that Spring forgot, and appropriate playlist customization so that you can specify what songs to play when the battle gets epic, and what songs to play when it cools down...etc

User avatar
Balthazar
Moderator
Posts: 2055
Joined: Wed Nov 01, 2006 4:31 pm
Location: Russian Federation
Contact:

Post by Balthazar » Thu Dec 07, 2006 7:50 am

Yes, music ajustment is very nice idea. What about in-game sound, there are should be wav support, because of OTA sounds are in wav format.
But if there`ll be new sounds, to download with TA3D, they should be high-compressed within installation file and can be converted back to wav after installation is complete. We should try not to make TA3D installer a REAL BIG...

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Thu Dec 07, 2006 9:08 am

mp3/ogg support for the installer, why not? sure it will be smaller and that's good. We can also use jpeg pictures for stuff that is preloaded or loaded during a non critical part of the game.
=>;-D Penguin Powered

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Tue Dec 19, 2006 4:34 am

I finally started to work on the new classes/interface for sound/music support, which will free us of AllgeroMP3, and give us more control over our options.

There are a couple of questions that should now start to be addressed, the first and formost is focus mode, now normally most games run full screen, and i'am sure we will be full screen later as well, and undre some extreme conditions we will run it in a window, but i'am expecting that as we near a true release we will shift over to full screen rather then windowed. Others may ask why and the answer is of course speed, when you shift to full screen you leave behind alot of windows gui, maybe not important under linux, but very important in windows as it will nearly tripple if not better the speed at which gfx routines run.

However, during the meantime we are and will probably be in a 'window', so this brings up an important question and that is to 'global focus' sound/music, that is to say, that when the window is minized should sound/music still be heard, or should it only be heard when the window is in focus, obviously if the screen is set to full screen and minized then it should be silent while minimized.

And if it is to be normal focus mode (not heard while window in focus) should I 'pause' music streams while not in focus or let it continue only unheard.

To start I am going to implement a very simple playlist for mp3 support only, and sounds, ocne its running well I will improve mp3 support to support nearly all other music types known. And finally I will add support for cd audio.

User avatar
Balthazar
Moderator
Posts: 2055
Joined: Wed Nov 01, 2006 4:31 pm
Location: Russian Federation
Contact:

Post by Balthazar » Tue Dec 19, 2006 7:26 am


User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Tue Dec 19, 2006 5:24 pm

I'am beging to make some decent progress with the new sound/music handler, and expanded it above and beyond what I orginally started with.

Once this code is placed into the build The features will include...

Playlist:
[1] Support for ogg, wav, raw, mp2, mp3, aiff, asf, wma, to start.

[2] Mutliple battle tunes, when battle triggers a battle tune, a 'random' one will be selected in the case that you have multiple battle tunes.

[3] Console output so that you can see excactly why a tune or fmod isn't working as expected (ie failed to find a tune).

[4] Future support for different tunes to accompany ta3d's mood, ie building tunes when one is doing mostly building, 2)Post clash tunes, for when things are building up to some climax, and so on.

[5] Future support for s3m, it, xm, mod. For those of the old school these are tracked modules that are somewhat like midi but superior in almost every aspect, millions of them can be found at http://www.modarchive.com and these acutally are more suited in most respects to music that should be in a game. They are also extremely easy to decode/play and thus use much less operations to play.

[6] Future config menu for sound/music including, sound levels for music/sound, driver, and mixer, frequency, and much more. Possibly the ability to use DSP's from winamp or other 3rd party to improve music sounding, or preset equalizer or sound effects.

++Cire.

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Tue Dec 19, 2006 6:24 pm

ok, good job. I think it won't be easy to include this module in the next release but can start working on that.

some comments:
First, concerning windowed mode, this is an option, TA3D can already run in full screen mode, just ask it to do it. I never use full screen mode when developing because it hides my desktop and everything running on it like my text editor (the one I use to write TA3D's code), or firefox. So I can't do any thing else while loading or if I want to look at something in the code, or somewhere else. Debugging is easier in windowed mode so it won't disappear, but full screen mode exists, we will set it as default mode when TA3D gets ready for a really playable version with at least skirmish or multi-player games.

I think we should pause music when minimized but not when loosing focus in windowed mode (expect if the game is paused), when pausing music TA3D must be silent, so other sounds must be paused as well.

Now do what you can, it will help us using fewer libs to get a better result. (as far as I am concerned I play TA3D with original TA's music or SupCom music...)
=>;-D Penguin Powered

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Tue Dec 19, 2006 7:15 pm

Yes I agree right now TA3D default mode shoudl be windowed, but as you said already once its ready default shoudl be full screen.

For now I set it as 'global focus' its easy enuff for us to change, this means that regardless music/sound will be heard.

As i near completing the class for its first appearance things may change, but i'am opting for some easy stuff at first and then more complex as it evolves.

The next lib I would like to see us drop is AllegroGL, and I understand that we use this pretty extensivly right now, but most of what you do use can easilly be written into our own function calls, GL is already very portable, and all AllegroGL is relaly doing is wrapping itself around GL with some helper functions here and there. In essence rather then us working directly with GL you added a layer between us, which is good for rapid developement but bad because you have those extra code to execute that is not always needed.

Even Allegro itself is nothing more then some code that wraps itself around various platforms providing a kinda 'translating' layer between platforms. We don't even really need this as most of what we are going to require we could write the functions ourselves, thus freeing ourselves of even more code page.

If you exaimine the process space of TA3D closely allegro/gl is useing up almost a 3rd of what makes TA3D, but if you step it, we are barely using functions from Allegro core, though we are using lots from AllegroGL.

Now don't take this wrong, i'am not saying lets immeatly drop this, i'am saying lets slowly start examining functions that we could replace with our own code, and as we come to areas that are using allegro start redirecting these to our own code, in time you will be able to simply drop these libs with little to no work.

++Cire.

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Wed Dec 20, 2006 6:10 am

I've begun testing the new sound managing class now. It don't yet support sounds for 'in game' but as I write this it is streaming a mp3,already streamed a ogg, and preparing the next tune will tell me if it successfully wraps around and restarts the list.

It should require next to no handling from the engine itself, ie don't require the engine to 'poll' to see if the tune is over ect. It uses a callback when the stream is completed, the callback in turn calls to the sound manager class and tells it to play the next tune.

In fact the only calls the engine should need to send to the sound manager is state changes in battle for example, perhaps some user input commands for next tune or previous and perhaps a pause/unpause call when the game is paused/unpaused.

The playlist format has changed slightly, it no longer will be stored in a directory called music\playlist.txt instead its stored in the root of where ta3d.exe is located and is still called playlist.txt. It does not require an entry for the number of tunes in the playlist (it will figure that out itself), each tune is then stored on its own line with a signal return seperating tunes. Blank lines will be ignored, lines starting with # or ; will be ignored. Any songs that start with a * are deamed 'battle tunes'. These will not be played unless the engine calls to the sound manager and sets the manager to battle mode, at which time the sound manager will select one of the battle tunes at random to be played, they will be continued to be played until battle mode is set to false. You may have as many tunes for battle and regular as you wish.

I do plan on adding a bunch of console input commands to make it easier to handle music, such as +setvolume 255, to set the volume, +ptune to select previous tune, +ntune to select next tune, +musicrandom true or false to have it select regular music randomly as well.

Now its important to note, that on some slower systems during startup sequenc you may notice a stutter or two. This is normal, the sound manager is streaming the tune using as little cpu/memory as possible, in fact it streams using only a 200ms buffer, in contrast, WMP uses 5000ms buffer, same as winamap. Streams are run in a seperate optomized thread, thus shouln't block any TA3D operations.

++Cire.

User avatar
Balthazar
Moderator
Posts: 2055
Joined: Wed Nov 01, 2006 4:31 pm
Location: Russian Federation
Contact:

Post by Balthazar » Wed Dec 20, 2006 6:32 am

Perfffect :) Cire - best regards for adding *.sm *.mod support. These are really awesome formats, there are so many nice music from the dear old past :)

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Wed Dec 20, 2006 6:08 pm

ok good job, we might add it for Christmas release :wink: !
=>;-D Penguin Powered

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Thu Dec 21, 2006 5:16 am

I won't have it ready for xmas release, unless you don't want actual in game sounds, though I am getting ready to add support for that now.

++Cire.

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Thu Dec 21, 2006 7:17 am

I've started primary design of the sound interface and some questions come to mind, none of these are concering hardware issues but more so from an 'engine' point of view.

Now to load sound will be rather simple, its just a matter of calling SoundManager->LoadSound( "file.wav" ); It will use the hpi manager class and call to it to atain the wave data, at which point it starts to get complicated. The return result will likely be some integer handle.

Now this handle can be used to play the sound. Since we are going to be using 3d sound, which I should take a moment to explain. With 3d sound, the user may be looking at a certain posistion on the map, we will call this place the listener location, now a unit moving around at another location on the map and firing its weapons is generating some noise, so the sound this unit is generating must be scaled first by where the unit is in portion to the user, that is to say the right and left channels need scaled in volume. However we must also scale the sound based on distance, that is to say the farther away the unit is from us, the harder it is to hear.

That is fairly easy to handle with FMOD, but there are some issues that need to be addressed, as sound manager does not have access to this and they must be passed by the engine in order for true 3d sound to be correctly handled, furthermore they will also need updated should the engine notice a camera movement.

So when the engine wishes to play a sound it will need to pass a number of parmeters to the function, including...the mindistance, this should be thought of as the mindistance away that the unit will no longer continue to get louder as we apprach it. For example, a bertha explosion set to a min distance of say 100.0f, would stay at full volume until we were 100 meters away, every sound played could have its own min distance, this is something to keep in mind when building unit data that will play sounds.

Now in order to work correctly, and because maps are scalled differently and what not, the first thing the engine will need to do after creating the sound manager is to set the distance factor. I dunno what zuff is measuring in be it meters or feet. FMOD defaults to 1.0 which is 1 meter.
So
SoundManager->Set3DScale( 1.0f );

Next and optional is to set the Dooplar scale factor
Like so:
SoundManager->Set3DDopplerFactor( 1.0f );
This is a general scaling factor for how much the pitch varies due to doppler shifting.
Increasing the value above 1.0 exaggerates the effect, whereas lowering it reduces the effect.
0 removes the effect all together.
FMOD's speed of sound at a DopplerFactor of 1.0 is 340 m/s.

Think of this like delaying the sound for units that are very very very far away, it may take a short period of time before the sound reachs us.

Next is to set the Roll off fector Like So:
SoundManager->Set3DRolloffFactor( 1 );
Sets the global attenuation rolloff factor.
Normally volume for a sample will scale at 1 / distance. This gives a logarithmic attenuation of volume as the source gets further away (or closer).
Setting this value makes the sound drop off faster or slower. The higher the value, the faster volume will fall off.
The lower the value, the slower it will fall off.
For example a rolloff factor of 1 will simulate the real world, where as a value of 2 will make sounds attenuate 2 times quicker.


The above 3 must be set and should not be changed once the game acutally starts.

Next we need to specify the listern attributes, and this will need updated as the listener moves about (camera).

SoundManager->Set3DListner( const vector *pos,
const vector *vel,
float fx, float fy, float fz,
float tx, float ty, float tz );

pos Pointer to a position vector (xyz float triplet), of the listener in world space, measured in distance units.
This can be NULL to ignore it.

vel Pointer to a velocity vector (xyz float triplet), of the listener measured in distance units PER SECOND.
This can be NULL to ignore it.

fx x component of a FORWARD unit length orientation vector

fy y component of a FORWARD unit length orientation vector

fz z component of a FORWARD unit length orientation vector

tx x component of a TOP or upwards facing unit length orientation vector

ty y component of a TOP or upwards facing unit length orientation vector

tz z component of a TOP or upwards facing unit length orientation vector

FSOUND treats +X as right, +Y as up, and +Z as forwards. (left handed)
To map to your own coordinate system, flip and exchange these values. For example if you wanted to use right handed coordinates, you would negate the Z value of your own direction vector.

Orientation vectors are expected to be of UNIT length. This means the magnitude of the vector should be 1.0f.

Please remember to use units PER SECOND, NOT PER FRAME as this is a common mistake. Do not just use (pos - lastpos) from the last frame's data for velocity, as this is not correct. You need to time compensate it so it is given in units per SECOND. You could alter your pos - lastpos calculation to something like this.
vel = (pos-lastpos) / (time taken since last frame in seconds). Ie at 60fps the formula would look like this vel = (pos-lastpos) / 0.0166667.

Once the engine is capalbe of updating this then playing a sound shoudl be relatifly easy work on the engines behalf. Since most sounds in TA that you will hear are unit selection and orders these could be simply passed as 2d sounds (no 3d data needed) and pretty much played and forgotten, where 3d sounds will require passing the pos,velocity of the sound,

That it.

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Thu Dec 21, 2006 5:36 pm

The above 3 constant functions I have removed, mainly due to fear of toying with the functions while a game is in play. These are now part of the constructor. Since they should be set and forgot; its probably for the better.

So to construct the Sound manager we now have a defination that looks like...

Code: Select all

cAudio::cAudio( const float DistanceFactor,
				const float DopplerFactor,
				const float RolloffFactor ) : 
		m_FMODRunning( false ), 
		m_InBattle( false ),
		m_lpMusicStream( NULL ),
		m_iMusicChan( -1 ),
		m_curPlayIndex( -1 )

{
	StartUpAudio();

	if( !m_FMODRunning )
		return;

	FSOUND_3D_SetDistanceFactor( DistanceFactor );
	FSOUND_3D_SetDopplerFactor( DopplerFactor );
	FSOUND_3D_SetRolloffFactor( RolloffFactor );
}

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Thu Dec 21, 2006 6:26 pm

Loading a sound is rather simple.

Code: Select all

   A = SoundManager->LoadSound( B, C );
A = The index the sound was stored at, when playing a sound this is the fastest way to play it, SoundManager->PlaySound( A, ... ); You will still be able to pass the 'filename' as a play parmater, but index is the fastest way. The index will not change unless SoundManager is reconstructed or is told to purge all sounds.

BIs a const std::string, which is the filename to be loaded from hpi data, example SoundManager->LoadSound( "sounds\\annigun1.wav", true ); Note that a sound file can be loaded 2x, depending if its loaded as a 3d sound or as a 2d sound. See next parm.

CIf this parm is true the sound is loaded as a 3D sample, otherwize its loaded as a 2D sample. When playing sounds 2D samples and 3D samples are not itnermixable, that is to say you can not tell a 2D sampleto be played as 3D and visa versa.

*Note: Unit Fire sounds, explosion sounds should be loaded as 3D sounds, all other sounds shoudl be loaded as 2D sounds, as thier is no need in playing a unit acknowledgement or unit move sound as '3D'.

*Note I do not yet have final details worked out for the play member function, and will probably make 1 function with default parms on 3D data, so that we have only 1 play function. For playing 3D sounds it will require additional parms filed out such as position, velocity.

++Cire.

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Fri Dec 22, 2006 5:09 am

I've just about completed the class but playing sounds in 3D requires 2 additional arguments, and i'am not sure we really need both of them
they are float arrays for position and veloctiy of the sound, I can't really see velocity of any use at all since sounds in TA are so short that velocity shouln't really matter so i'am thinking of using velocity of { 0.0, 0.0, 0.0 } (all floats of course), though if the engine has no problems passing these that i could use them, but again most sounds in TA are sooo short that velocity shouln't really matter.

Now another thing 3d sounds need is to know 'where' the sound is located, and i need to know if you want to pass this as a vector, or a float array, its upto you, but you must follow FMODS quard system which is
{ x, y, z } broke down into:

FSOUND treats +X as right, +Y as up, and +Z as forwards. (left handed), if this is not how TA3D Works then simply passing me the vector and i can flip these how FMOD wants.

Secondly I changed LoadSound slightly, by adding 2 optional parms which only effect if its a 3d sound, and that is MinDistance and MaxDistance, which are defaulted too 1.0f and 10000.0f. Some sound may wish to change these values.

I have tested loading and playing 2d sounds, as well as the playlist, and once I have the final data I need from you that the engine will pass to me I will test sounds in 3d. So should i fix velocity as above to 0.0f, 0.0f, 0.0f or do you wish to pass that along, keep in mind thiere is no function later to 'change' this, though it could be easilly added, and also do you want to pass these as a vector or a float pointer with 3 elements, whatever is easier and fastest for the engine, and finally is the quard system makeup that TA3D uses the same as fmod or do i need to flip these if you pass a vector?

++Cire.

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Fri Dec 22, 2006 5:18 am

Oh I also need to know which is the better sound output under linux, Open Audio System, Enlightment Sound Daemon, or ALSA 0.9 - Advanced Linux Sound Architecture


Mac and windows Direct Sound is the best.

++Cire.

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Fri Dec 22, 2006 12:33 pm

for Linux, use ALSA, it's better, and OSS is disappearing from the kernel.

The engine works with its own VECTOR/POINT/MATRIX classes so I will be faster using a VECTOR. I agree that speed should be 0 since it's a RTS it would disturb the player if this is noticeable.
=>;-D Penguin Powered

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Fri Dec 22, 2006 2:43 pm

Never mind on the output driver, I managed to get the 'default' output working on platforms.

Now the vector that you will pass is that the one that is in vector.h? And did you confirm that your x,y,z system is the same format that fmod uses, or must i modify them.

++Cire.

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Fri Dec 22, 2006 3:49 pm

I am finished the new SoundManager classe. I tried to wrap it as neatly as possible in one class with as little methods exposed to the engine as possible. The engine should only need call a few minor functions within, and does not need to worry about cleaning up, except perhaps at the end of a game, to purge sounds, however destructing the sound manager class will do that anyhow, but would clear the playlist.

This is the first draft, there are still a few issues I need to resolve yet, mainly should an error occur within playlist ie system was busy or some such then playlist comes to a halt.

The key function the engine needs to call is the update function which should be called 1x per frame to order fmod to update its 3d sound handling, it is non blocking so no worries about it eating up too much time.

The code will require my new tools dir, for both 'linux' and win32, it also will require linux linking the cpp file against libfmod-3.75.so (i.e. gcc file.c -lfmod-3.75), which is in my tools dir, it will also require the libfmod-3.75.so to be present with executable for linux builds.

For other builds it will require fmod.dll present. One issue that may cause issues is that fmod provides builds for 32 and 64 bit cpus, we probably should update our platform support for these so that correct libs are used, the downside to this is that we would need to provide mutliple releases for each platform 1 for32 bit, other for 64 bit, but we knew it would come to this anyhow.

Once I have cleaned up the code, and resynced my code with zuffs and made any changes needed I will provide him new code for changes I have made. I have also made some changes to my new ocnfig classes to make it more compatable with older config files, by having it examine variable types it reads in more closesly.

Here is the .h file

Code: Select all

/*
**  File: TA3D_Audio.h
** Notes:
**
*/

#pragma once

#if defined TA3D_PLATFORM_LINUX
    #include "tools/linux/fmod/inc/wincompat.h"
	#include ""tools/linux/fmod/inc/fmod.h"
#elif defined TA3D_PLATFORM_WINDOWS
	#include "tools/win32/fmod/fmod.h"
	#pragma comment(lib, "tools/win32/libs/fmodvc.lib")
#endif

namespace TA3D {
	namespace AUDIO
	{
		class cAudio
		{
		private:
			typedef struct m_PlayListItem
			{
				String			m_Filename;
				bool			m_BattleTune;

				m_PlayListItem()
				{
					m_Filename = String( "" );
					m_BattleTune = false;
				}
			};

		private:
			typedef std::vector< m_PlayListItem * >		Playlist;
			typedef Playlist::iterator					plItor;

		private:
			bool		m_FMODRunning;		// Is fmod running
			bool		m_InBattle;			// Are we in battle
			sint32      m_BattleTunes;      // Number of battle tunes;
			Playlist	m_Playlist;			// Vector of PlayList.

			FSOUND_STREAM	*m_lpMusicStream; // current music stream
			sint16			m_iMusicChan;     // chan handle to music stream.
			sint16			m_curPlayIndex;   // current play index.

		public:
			void ShutdownAudio( bool PurgeLoadedData );
			bool StartUpAudio( void );

			cAudio( const float DistanceFactor,
					const float DopplerFactor,
					const float RolloffFactor );
			~cAudio();

			// PlayList Members
		private:
			void LoadPlayList( void );
			const String SelectNextMusic( void );
			void PlayMusic( const String &FileName );

		public:
			 void SetMusicMode( bool battleMode );

			 void PurgePlayList( void );
			 void PlayMusic( void );
			 void TogglePauseMusic( void );
			 void StopMusic( void );

			 // Sound Members
		private:
			typedef struct m_SoundListItem
			{
				String			m_Filename;
				bool			m_3DSound;
				FSOUND_SAMPLE	*m_SampleHandle;

				m_SoundListItem()
				{
					m_Filename = String( "" );
					m_3DSound = false;
					m_SampleHandle = NULL;
				}
			};

		private:
			typedef std::vector< m_SoundListItem * >	SoundList;
			typedef SoundList::iterator					slItor;

		private:
			SoundList	m_Soundlist;			// Vector of Sounds

		public:
			const sint32 LoadSound( const String &Filename, const bool LoadAs3D,
				const float MinDistance = 1.0f, const float MaxDistance = 10000.0f  );
			void PlaySound( const sint32 SoundIndex, const VECTOR3D *vec = NULL );
			void PlaySound( const std::string &FileName, const VECTOR3D *vec = NULL );

			void SetListenerPos( const VECTOR3D *vec );

			void Update3DSound( void );

			void PurgeSounds( void );
		}; // class cAudio
	} // namespace AUDIO
} // namespace TA3D
and the .cpp file

Code: Select all

/*
**  File: TA3D_hpi.cpp
** Notes:
*/
#include "stdafx.h"
#include "vector.h"
#include "TA3D_Namespace.h"   //"TA3D_Audio.h" is in our namespace.

using namespace TA3D::AUDIO;

TA3D::AUDIO::cAudio *TA3D::VARS::SoundManger;

/*
** Function: MusicFinished
**    Notes: FMOD call back function when a stream finishes.
**           Goal is simply to call PlayMusic() which will select
**           another tune from g_liPlayList
*/
signed char F_CALLBACKAPI MusicFinished( FSOUND_STREAM *stream, void *buff, int len, void *userdata )
{
	SoundManger->PlayMusic();

	return 1;
};

void cAudio::LoadPlayList()
{
	String FileName = GetClientPath() + String( "playlist.txt" );
	std::ifstream file( FileName.c_str(), ios::in );

	if( !file.is_open() ) 
		return;

	String line;
	bool isBattle;

	m_BattleTunes = 0;

	while( !file.eof() )
	{
		std::getline( file, line, '\n' );

		line = TrimString( line ); // strip off spaces, linefeeds, tabs, newlines

		if( !line.length() ) continue;
		if (line[0] == '#' || line[0] == ';' ) continue;

		if( line[0] == '*' )
		{
			isBattle=true;

			line = line.erase( 0,1 );
			m_BattleTunes++;
		}
		else
			isBattle = false;

		m_PlayListItem *m_Tune = new m_PlayListItem();

		m_Tune->m_BattleTune = isBattle;
		m_Tune->m_Filename = line;

		m_Playlist.push_back( m_Tune );
	}

	file.close();

	Console->AddEntry( "FMOD: Playlist size is: %d", m_Playlist.size() );

	for( plItor cur = m_Playlist.begin(); cur != m_Playlist.end(); cur++ )
		Console->AddEntry( "FMOD PlayListItem (%s)", (*cur)->m_Filename.c_str() );

	if( m_Playlist.size() > 0 )
		PlayMusic();
}

void cAudio::ShutdownAudio( bool PurgeLoadedData )
{
	if( m_FMODRunning ) // only execute stop if we are running.
	{ 
			StopMusic();   // stop music if playing.
		//  StopSounds();  // stop any playing sounds.
	}

	if( PurgeLoadedData )
	{
		 PurgeSounds(); // purge sound list.
		 PurgePlayList(); // purge play list
	}

	if( m_FMODRunning )
	{
		FSOUND_Close();  // stop FMOD.
		m_FMODRunning = false;

		Console->AddEntry( "FMOD: has been shutdown." );
	}
}

bool cAudio::StartUpAudio( void )
{
	if( m_FMODRunning )
		return true;

	FSOUND_SetBufferSize( 200 );		// 200 ms buffer
/*
#if defined TA3D_PLATFORM_LINUX
    FSOUND_SetOutput(FSOUND_OUTPUT_OSS);   // Open Sound System
//	FSOUND_SetOutput(FSOUND_OUTPUT_ESD);   // Enlightment Sound Daemon
//	FSOUND_SetOutput(FSOUND_OUTPUT_ALSA);  // ??
#else
    FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); // Direct Sound
//	FSOUND_SetOutput(FSOUND_OUTPUT_WINMM);  // Windows Multimedia Waveout
//	FSOUND_SetOutput(FSOUND_OUTPUT_ASIO);   // ?

#endif
*/
	FSOUND_SetOutput( -1 ); // Sound System Output (Autodetect).
	FSOUND_SetDriver(0);				// Default sound driver
	FSOUND_SetMixer(FSOUND_MIXER_QUALITY_AUTODETECT);	// Autodetect
	FSOUND_SetSFXMasterVolume( 255 );	// full volume baby!

	// 44khz, 128 channels, global focus
	if( !FSOUND_Init( 44100, 128, FSOUND_INIT_GLOBALFOCUS ) )
	{
		Console->AddEntry( "FMOD: Failed to startup." );
		return false;
	}

	Console->AddEntry( "FMOD: is now running." );

	m_FMODRunning = true;

	LoadPlayList();

	return true;
}

cAudio::cAudio( const float DistanceFactor,
				const float DopplerFactor,
				const float RolloffFactor ) : 
		m_FMODRunning( false ), 
		m_InBattle( false ),
		m_lpMusicStream( NULL ),
		m_iMusicChan( -1 ),
		m_curPlayIndex( -1 )

{
	StartUpAudio();

	if( !m_FMODRunning )
		return;

	FSOUND_3D_SetDistanceFactor( DistanceFactor );
	FSOUND_3D_SetDopplerFactor( DopplerFactor );
	FSOUND_3D_SetRolloffFactor( RolloffFactor );
}

cAudio::~cAudio()
{
	ShutdownAudio( true );
}

void cAudio::StopMusic( void )
{
	if( !m_FMODRunning )
		return;

	if( m_lpMusicStream != NULL )
	{
		FSOUND_Stream_SetEndCallback( m_lpMusicStream, NULL, 0 );
		FSOUND_Stream_Stop( m_lpMusicStream );
		FSOUND_Stream_Close( m_lpMusicStream );
			
		m_lpMusicStream = NULL;
	}
}

void cAudio::PurgePlayList( void )
{
	StopMusic();

	m_curPlayIndex = -1; // we don't change this in stop music in case
	                     // we want to do a play and contine through our list, so
	                     // we change it here to refelect no index.

	if( m_Playlist.size() < 1 ) // nothing in our list.
		return;

	// walk through vector and delete all the items.
	for( plItor k_Pos = m_Playlist.begin(); k_Pos != m_Playlist.end(); k_Pos++ )
		delete( *k_Pos );

	m_Playlist.clear();	// now purge the vector.
}

void cAudio::TogglePauseMusic( void )
{
	if( m_lpMusicStream == NULL )
		return;

	if( FSOUND_GetPaused( m_iMusicChan  ) == TRUE )
		FSOUND_SetPaused( m_iMusicChan, FALSE );
	else
		FSOUND_SetPaused( m_iMusicChan, TRUE );
}

const String cAudio::SelectNextMusic( void )
{
	plItor cur;
	sint16 cIndex = -1;
	sint16 mCount = 0;
	string szResult = "";


	if( m_Playlist.size() == 0 )
		return szResult;

	if( m_InBattle && m_BattleTunes > 0 )
	{
		srand( (unsigned)time( NULL ) );
		cIndex =  (sint16)(rand() % m_BattleTunes ) +1;
		mCount = 1;

		for( cur = m_Playlist.begin(); cur != m_Playlist.end(); cur++ )
		{
			if( (*cur)->m_BattleTune && mCount == cIndex )
			{
				szResult = String( (*cur)->m_Filename );
				break;
			}
		}

		return szResult;
	}

	mCount = 0;
	if( m_curPlayIndex > (sint32)m_Playlist.size() )
		m_curPlayIndex = -1;

	for( cur = m_Playlist.begin(); cur != m_Playlist.end(); cur++ )
	{
		mCount++;
		
		if( (*cur)->m_BattleTune )
			continue;

		if( m_curPlayIndex == mCount || m_curPlayIndex == -1 ) 
		{
			szResult = (*cur)->m_Filename;
			m_curPlayIndex = mCount+1;
			break;
		}
	}

	return szResult;
}
			 
void cAudio::SetMusicMode( bool battleMode )
{
	if( m_InBattle == battleMode )
		return;

	m_InBattle = battleMode;
	PlayMusic();
}


void cAudio::PlayMusic( const String &FileName )
{
	StopMusic();

	if( !m_FMODRunning )
		return;

	if( !file_exists( FileName.c_str() ,FA_RDONLY | FA_ARCH,NULL ) )
	{
		Console->AddEntry( "FMOD:Failed to find file: %s for play.", FileName.c_str() );
		return;
	}

	Console->AddEntry( "FMOD: Preparing to play (%s)", FileName.c_str() );

	m_lpMusicStream = FSOUND_Stream_Open( FileName.c_str(), 
			FSOUND_STEREO | FSOUND_LOOP_OFF | FSOUND_16BITS | FSOUND_IGNORETAGS, 0, 0 );
		
	if( !m_lpMusicStream )
	{
		Console->AddEntry( "FMOD: stream yielded NULL." );
		return;
	}
		
	m_iMusicChan = FSOUND_Stream_Play( FSOUND_FREE, m_lpMusicStream );
		
	if( m_iMusicChan == -1 )
	{
		Console->AddEntry( "FMOD: channel result was -1" );

		StopMusic();
		return;
	}
		
	FSOUND_Stream_SetEndCallback( m_lpMusicStream, MusicFinished, 0 );

	Console->AddEntry( "FMOD: Now playing (%s) (%d)", FileName.c_str(),
		FSOUND_GetVolume( m_iMusicChan ) );
}

void cAudio::PlayMusic()
{
	if( !m_FMODRunning )
		return;

	if( m_lpMusicStream != NULL )
	{
		if( FSOUND_GetPaused( m_iMusicChan ) == TRUE )
		{
			FSOUND_SetPaused( m_iMusicChan, FALSE );
			return;
		}

		StopMusic();
	}

	PlayMusic( SelectNextMusic() );
}

// Begin sound managing routines.

void cAudio::PurgeSounds( void )
{
	if( m_Soundlist.size() < 1 ) // nothing in our list.
		return;

	// walk through vector and delete all the items.
	for( slItor k_Pos = m_Soundlist.begin(); k_Pos != m_Soundlist.end(); k_Pos++ )
	{
		if( (*k_Pos)->m_SampleHandle )
		{
			FSOUND_Sample_Free( (*k_Pos)->m_SampleHandle );
			(*k_Pos)->m_SampleHandle = NULL;
		}

		delete( *k_Pos );
	}

	m_Soundlist.clear();	// now purge the vector.
}
const sint32 cAudio::LoadSound( const String &Filename, const bool LoadAs3D,
							   const float MinDistance, const float MaxDistance )
{
	uint32 Length;
	byte *data;
	sint32 Result = -1;

	data=HPIManager->PullFromHPI( Filename, &Length );

	if( !data )
	{
		Console->AddEntry( "FMOD: LoadSound(%s), no such sound found in HPI.", Filename.c_str() );
		return Result;
	}

	Result = (sint32)m_Soundlist.size();

	m_SoundListItem *m_Sound = new m_SoundListItem();

	m_Sound->m_3DSound = LoadAs3D;
	m_Sound->m_Filename = String( Filename );

	if( m_Sound->m_3DSound )
		m_Sound->m_SampleHandle = FSOUND_Sample_Load( FSOUND_UNMANAGED, 
			(const char *)data, FSOUND_HW3D | FSOUND_LOADMEMORY, 0, Length );
	else
		m_Sound->m_SampleHandle = FSOUND_Sample_Load( FSOUND_UNMANAGED, 
			(const char *)data, FSOUND_HW2D | FSOUND_LOADMEMORY, 0, Length );

	free( data );

	if( !m_Sound->m_SampleHandle )
	{
		Result = -1;
		delete m_Sound;
		m_Sound = NULL;

		Console->AddEntry( "FMOD: LoadSound(%s), Failed to construct sample.", Filename.c_str() );
		return Result;
	}

	if( m_Sound->m_3DSound )
		FSOUND_Sample_SetMinMaxDistance(m_Sound->m_SampleHandle, MinDistance, MaxDistance);

	m_Soundlist.push_back( m_Sound );

	Console->AddEntry( "FMOD: LoadSound(%s), Loaded and ready for use.", Filename.c_str() );

	return Result;
}

void cAudio::PlaySound( const sint32 SoundIndex, const VECTOR3D *vec )
{
	sint32 ch;

	if( m_Soundlist[ SoundIndex ]->m_3DSound )
	{
		if( !vec ) return;
		
        real32 pos[3] = { vec->x, vec->y, vec->z };
        real32 vel[3] = { 0,0,0 };
		
		ch = FSOUND_PlaySoundEx(FSOUND_FREE, m_Soundlist[ SoundIndex ]->m_SampleHandle, NULL, TRUE);
        FSOUND_3D_SetAttributes( ch, pos, vel );

		if( !FSOUND_SetPaused( ch, FALSE) )
			Console->AddEntry( "Failed to play 3D sound (%s).", m_Soundlist[ SoundIndex ]->m_Filename );
	}
	else
		FSOUND_PlaySound( FSOUND_FREE,
			m_Soundlist[ SoundIndex ]->m_SampleHandle );
}

void cAudio::PlaySound( const std::string &FileName, const VECTOR3D *vec )
{
	sint32 SoundIndex = 0;

	for( slItor k_Pos = m_Soundlist.begin(); k_Pos != m_Soundlist.end(); k_Pos++ )
	{
		if( (*k_Pos)->m_Filename == FileName )
		{
			PlaySound( SoundIndex, vec );
			break;
		}
		SoundIndex++;
	}
}

void cAudio::SetListenerPos( const VECTOR3D *vec )
{
	real32 pos[3] = { vec->x, vec->y, vec->z };
	real32 vel[3] = { 0,0,0 };

	FSOUND_3D_Listener_SetAttributes( pos, vel, 0, 0, 1.0f, 0, 1.0f, 0 );
}

void cAudio::Update3DSound( void )
{
	FSOUND_Update();
}


User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Fri Dec 22, 2006 6:29 pm

yes I use the VECTOR in vector.h, TA3D's coordinate system is the same as fmod's, so we don't need conversion here.

For builds on different platforms (32 & 64 bits), on Linux the configure script can autodetect this and configure for building with the right lib, on windows with msvc I think it should be 2 project files (but since I didn't manage to install a 64bits msvc environment I can't build win64 exes).
=>;-D Penguin Powered

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Fri Dec 22, 2006 9:51 pm

I think we really should just modify ta_platform.h, and add a

Code: Select all

#define TA3D_PLATFORM_ARCH_64

#define TA3D_PLATFORM_ARCH_32
then we just undef whatever once we are not building for, in my enviroment for windows that should do it, I can use these to adjust whatever function calls I make.

of course this would mean editing it each time i wana build for 64 or 32 bit, but thats no big issue, or i coudl set this up in my soulation file to support this, don't really matter but its aloter easier for me to have a define to know what to link against.

++Cire.

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Fri Dec 22, 2006 11:05 pm

then use it in windows specific code, the Linux configure script doesn't need that, I will add an autodetection code so it links to proper libs without touching the code.

Is it possible to set a define in the compiler command line with msvc?? if it's the case then just add the proper define in the command line for each build config.
=>;-D Penguin Powered

Post Reply

Who is online

Users browsing this forum: No registered users and 26 guests