[crossfire] redoing sound

Mark Wedel mwedel at sonic.net
Mon Jun 18 02:01:01 CDT 2012


  This is mostly just a capturing of what was discussed on IRC - this is mostly 
a record of what was discussed just so there is a record.

  The basic problem is that the sound logic is mostly hard coded into the 
server, so adding a new sound is not a trivial matter - this attempts to fix 
that.  Note that this does not 100% of cases for sound, but hopefully gets 90%. 
  The other 10% are probably getting into fairly specific situations which are 
hard to generalize, and could be done with plugin scripts.

== Server/Arch sound definition ==

  Sounds we be specified in the archetype/object, in the format of:

sound <event type> <chance> <volume> <range> <name1>...<name n>

Multiple sound lines could be specified for different events.  If the same event 
is specified, the new line overrides the old one (this would typically be used 
in cases where an objects is overriding the archetype value)

  <event type> would match the events in plugin.h.  This keeps things simpler, 
as the different events are already defined, and also makes it easier to code as 
one knows where to look for the different events.  Only the events that 
correspond to objects could be specified - not sure what, if anything, to do for 
global events.  Note that a special event type like 'continuous' probably needs 
to be added for objects that constantly make sound, like fountains.

<chance> is the chance to play a sound when the event is triggered, in 
percentage.  If an object sets this to 0, that is basically saying to clear the 
event.  This can mostly be used to control the amount of sound - as an example, 
orcs are often used in large numbers, so sounds associated with them may have a 
20% chance value, on the basis that if there are a bunch of orcs, you get a few 
sounds played, not 20 sounds played.

<volume> is relative volume to play the sound out, with 100 being normal volume. 
  Where I see this being useful is where the same sound is being used for 
similar events.  For example, the small/medium/large fireball may all use the 
same sound, small being volume 75, medium 100, large 125.  Max value here would 
be 200.

<range> is how many spaces the sound can be heard for.  For simplicity, walls 
will be ignored, so it is just a simple 'is this object within X spaces'.  But 
this is also used by the client to determine how loud the object should be, for 
example, an object with a 20 sound range should be louder than an object with a 
5 sound range even if both objects are 5 spaces away.

<name> is the name of one or more sound files (excluding the suffix).  Which one 
played is determined randomly, with equal chance.  This is mostly used to add 
variety.

I can quickly think of a few cases this does not cover, but would probably be 
easy to do in scripts - ability to weigh the sounds differently, so that 99% the 
first sound is played for an event, and 1% the second sound.  Also, being very 
specific on when sounds are played, eg, every fifth time this object is applied, 
play a sound, not 20% of the time.  Specific combinations might be another - 
when this object is used against this monster, this special sound is used.  All 
of these are specialized enough that having general logic is overkill, but not 
that hard to do in scripts, and is likely uncommon enough that doing it in 
scripts would not be a big performance problem.

== Protocol to Client ==

  The sound2 command is currently defined in the protocol as:
S->C: sound2 <x><y><dir><volume><type><action><name>

x/y are offset from player, direction is direction the sound is moving/facing, 
volume is just that, type is major sound type, action is the action, and name is 
the name of the sound.

  I would suggest this for replacement:
S->C: sound3 <x><y><tag><dir><volume><range><name>

<tag> is added so that the client can keep track if the sound associated with an 
object is changing (for example, the sound associated with a monster).  It might 
also want to use it to sound elimination - for example, if just last tick that 
object attacked and that sound is still playing, you may not want to play it 
again - but this is really up to the client to determine what to do.

Range is needed, as the client has to know how far the sound can be heard to be 
able to determine what the volume is.  The volume attribute is passed through as 
is defined in the archetype (it is up to the client to determine actual value 
based on offset and max range).  The type and action go away - in the sound 2, 
the action would be something like 'turn handle' and the name would be the 
object name, and the client would then figure out appropriate sound to play in 
that case.  Since in this revised system, we know exactly what sound to play (it 
being specified in the object) and each action has a sound associated with it, 
having both of those seems unnecessary.

  Note that since all object defined sounds correspond to an object (by 
definition), these are all played only on the local map.

== Client Sound Retrieval ==

Ideally, most sounds the client needs should be included in the client bundle or 
one that goes with it.  But if a server adds a sound, the client has to know how 
to get it.

Through a requestinfo made by the client, the server will return a URL (perhaps 
several) were the sound can be retrieved from.  I'm not quite sure the exact 
format of this - ideally, there should be some primary/secondary method.

What I mean by that is that if I am running my own server at home with limited 
bandwidth, I might want to say a global repository (which has fast connection 
and all the base sounds) is where the client should go first, but if the sound 
isn't found there (because I have added a custom sound), than try this URL which 
is on my home system.

  But it also seems likely that a setup might be several fast but basic servers, 
and several slow but complete servers for sounds, so it might be nice to be able 
to note that somehow.

  The one thing I would note is that if one has those 2 classes of servers, it 
should be considered that all servers in class have the same data.  What I mean 
by that is that if the sound file isn't found on the first fast but incomplete 
server, there is no reason trying the second, third, etc fast but incomplete 
servers, you should just move directly to the slow be complete.  But if the 
first slow but complete server does not have the file, it should be assumed that 
none of them have it (note that if it gets an error connecting to the server, or 
a bandwidth exceeded or something, then trying the next one may make sense)

So perhaps the requestinfo has something like:
basic_sound_urls=http://host1/... http://host2/...
complete_sound_url=http://myhost3/... http://myhost4/...

  and the client will just take a basic line and complete one at random to use. 
  I don't really want to make this complicated for retrieval of files, but I 
also want to try to cover what I think is a fairly likely scenario.

  Note that the URL should probably include a %s to note where to put the sound 
file, as I could see some URL like:

http://myhost3/crossfire/svn/sounds/%s&fetchfile

  or the like.

  For first phase, sound files will be wav format.  It is up to the client to 
put the .wav suffix on the name when requesting the file.  If other formats are 
added in the future (.ogg, .mp3, .whatever), the client would just request its 
preferred format, perhaps using some fallback mechanism if that first format is 
not available.

  The client will use URL attributes (hash, file size, last modification time) 
to try and detect if new versions of the sound files are available.  This needs 
further investigation to see what is easy to do.

== Other Thoughts ==

These are perhaps something for phase 2 or maybe never.

Global Sounds: There are several global events define which you probably want to 
be able to tie to sounds.  Tying in hard coded values is easy enough, but 
ideally you want these set in objects like everything else.  So maybe have an 
archetype whose sole purpose is to hold the sound information for those events.

  That said, looking at the global events, I'm not sure how many I would want 
sounds tied to sounds (or at least not played universally).  Login/logout might 
be worthwhile, but things like mapload/mapunload make little sense to emit 
sounds (that is server work which in theory should be invisible to the player)

Continuous Sounds: Continuous sounds probably get played in the map protocol - 
that is convenient in that one does not have to track if it has been sent to the 
client or the server sending it repeated for no good reason - the same logic 
that is used for images can be used for sounds.  The one limitation is that I 
think this would limit one continuous sound/space, but I don't see that as much 
an issue.

Sound Merging: As the code stands now, each time a sound is generated on a tick, 
based on the random chance, that sound is set to the client, with a limit of the 
number of sounds sent.  However, in a more ideal world, if there are 20 of the 
same sound be generated to the east, rather than send 20 sound3 protocol notes, 
the server should catch that and send just 1 much lounder sound3 for that sound. 
  But adding this does increase the complexity quite a bit, and unless too many 
sounds is an issue, doesn't seem much point to work on it.

Client Sound Management:  I could see the client having a file like
<sound name> <file to play> <volume> <text description>

This would allow the client to specify alternative sound files to play.  The 
volume would allow the player to turn off certain sounds (volume 0). The text 
descriptions could be used for players who do not want sound, but still want the 
information that conveys (you hear a dragon breathing in the distance) - these 
could get displayed in the text window.  The clients could ship with some 
skeleton version, or perhaps updates it as it gets the information, and provides 
some interface for the player to change it.  To me, this is also fairly 
specialized and of limited value, hence put in the 'perhaps never' area.




More information about the crossfire mailing list