Forum

Ambient sounds

Discuss programming topics for the various GPL'd game engine sources.

Moderator: InsideQC Admins

Ambient sounds

Postby frag.machine » Mon Jun 24, 2013 1:36 am

Vanilla Quake supports 4 "ambient" sound loops (I think "content" sounds would be more correct): sky/wind, water, slime and lava. Only two of these ambient sounds are used in the game though (water and wind).
So, I got FitzQuake 0.85 source and altered it to read ambient sounds from 4 cvars (_sfx_envwind, _sfx_envlava, _sfx_envslime and _sfx_envwater). Added a small function to reload the sfx every time one of these cvars are changed, so I can change the sounds at my will. Also, I produced a small test map consisting of 4 isolated rooms, each one containing one of the "content" brushes that triggers ambient sounds (lava, slime, water, sky). And I noticed a funny thing that at first I thought was my fault messing something:

a) if you set _gfx_envlava or _gfxenvwind, they work as expected;
b) if you set _gfx_envslime, nothing changes;
c) water brushes don' t emit the water ambient sound or any sound at all;
d) slime brushes emit the _gfx_envwater sound instead the expected.

As I said, at first I thought I should have messed something, but then I tested the same map with vanilla GlQuake and the behavior persists. I double checked the FitzQuake source and was unable to find anything wrong. So, I want to ask if anyone already observed such behavior ? Could it be a bug in the QBSP/VIS/LIGHT tools I am using (Bengt Jardrup's Quake map utilities) ?

EDIT:

Yeah, it's a "feature" from the VIS tool, after all:
Code: Select all
void CalcAmbientSounds (void)
{
   int      i, j, k, l;
   dleaf_t   *leaf, *hit;
   byte   *vis;
   dface_t   *surf;
   vec3_t   mins, maxs;
   float   d, maxd;
   int      ambient_type;
   texinfo_t   *info;
   miptex_t   *miptex;
   int      ofs;
   float   dists[NUM_AMBIENTS];
   float   vol;
   
   for (i=0 ; i< portalleafs ; i++)
   {
      leaf = &dleafs[i+1];

   //
   // clear ambients
   //
      for (j=0 ; j<NUM_AMBIENTS ; j++)
         dists[j] = 1020;

      vis = &uncompressed[i*bitbytes];
      
      for (j=0 ; j< portalleafs ; j++)
      {
         if ( !(vis[j>>3] & (1<<(j&7))) )
            continue;
      
      //
      // check this leaf for sound textures
      //   
         hit = &dleafs[j+1];

         for (k=0 ; k< hit->nummarksurfaces ; k++)
         {
            surf = &dfaces[dmarksurfaces[hit->firstmarksurface + k]];
            info = &texinfo[surf->texinfo];
            ofs = ((dmiptexlump_t *)dtexdata)->dataofs[info->miptex];
            miptex = (miptex_t *)(&dtexdata[ofs]);

            if ( !Q_strncasecmp (miptex->name, "*water", 6) )
               ambient_type = AMBIENT_WATER;
            else if ( !Q_strncasecmp (miptex->name, "sky", 3) )
               ambient_type = AMBIENT_SKY;
            else if ( !Q_strncasecmp (miptex->name, "*slime", 6) )
               ambient_type = AMBIENT_WATER; // AMBIENT_SLIME;
            else if ( !Q_strncasecmp (miptex->name, "*lava", 6) )
               ambient_type = AMBIENT_LAVA;
            else if ( !Q_strncasecmp (miptex->name, "*04water", 8) )
               ambient_type = AMBIENT_WATER;
            else
               continue;

         // find distance from source leaf to polygon
            SurfaceBBox (surf, mins, maxs);
            maxd = 0;
            for (l=0 ; l<3 ; l++)
            {
               if (mins[l] > leaf->maxs[l])
                  d = mins[l] - leaf->maxs[l];
               else if (maxs[l] < leaf->mins[l])
                  d = leaf->mins[l] - mins[l];
               else
                  d = 0;
               if (d > maxd)
                  maxd = d;
            }
            
            maxd = 0.25;
            if (maxd < dists[ambient_type])
               dists[ambient_type] = maxd;
         }
      }
      
      for (j=0 ; j<NUM_AMBIENTS ; j++)
      {
         if (dists[j] < 100)
            vol = 1.0;
         else
         {
            vol = 1.0 - dists[2]*0.002;
            if (vol < 0)
               vol = 0;
         }
         leaf->ambient_level[j] = vol*255;
      }
   }
}


I wonder why the lava ambient sound was left untouched though.

EDIT2: just to clarify: it's working this way since the original VIS tool.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
User avatar
frag.machine
 
Posts: 2090
Joined: Sat Nov 25, 2006 1:49 pm

Re: Ambient sounds

Postby frag.machine » Tue Jun 25, 2013 2:29 am

Well, I digged a bit more and looks like I managed to fix this really old bug. (AFAIK it comes from the original tools - most id maps have this problem)

Besides the above mentioned CONTENTS_SLIME being replaced by CONTENTS_WATER, there was another bit of code messed up in the same file preventing things to work as expected, so I am posting here the patched soundpvs.c (from Bengt Jardrup's VIS source, but the fix can be applied to other versions of the tool without changes AFAIK).
As a bonus, now the VIS tool will detect water, slime, lava and sky textures with any capitalization and with the keywords starting in any position on the texture name (in other words, "*04awater" now can emit water sounds, too), provided the texture start with "*" (or "s" or "S" for skies). Here is the complete soundpvs.c:
Code: Select all

#include <string.h>
#include "vis.h"

void CalcAmbientSounds (void)
{
   int       i, j, k;
   dleaf_t       *leaf, *hit;
   byte       *vis;
   dface_t       *surf;
   float       maxd;
   int       ambient_type, *Ambient;
   texinfo_t   *info;
   miptex_t    *miptex;
   int       ofs, nummiptex;
   float       dists[NUM_AMBIENTS];
   float       vol;
   qboolean    AmbientUsed[NUM_AMBIENTS];

   // frag.machine / ambient sounds fix
   char      texname[64];
   int         r, len;

   nummiptex = ((dmiptexlump_t *)dtexdata)->nummiptex;
   Ambient = malloc (nummiptex * sizeof(int));

   // Any textures at all ?
   if (texdatasize != 0)
   {
      for (i = 0; i < NUM_AMBIENTS; ++i)
         AmbientUsed[i] = false;

      // Calculate ambient type only once
      for (i = 0; i < nummiptex; i++)
      {
         Ambient[i] = -1;

         if (NoAmbient)
            continue; // All sounds disabled

         ofs = ((dmiptexlump_t *)dtexdata)->dataofs[i];
         
         if (ofs == -1)
            continue; // Missing texture

         miptex = (miptex_t *)(&dtexdata[ofs]);

         if (miptex->name[0] != '*' && miptex->name[0] != 's' && miptex->name[0] != 'S')
            continue;

         // frag.machine: converts the texture name to lowercase
         len = strlen (miptex->name);
         if (len > 64) {len = 64;}
         memset (texname, '\0', 64);
         for (r = 0; r < len; r++)
         {
            texname[r] = tolower(miptex->name[r]);
         }

         // frag.machine - we check ocurrences of the keywords in any point of the texture name, so "*04awater" and other non-standard texture names will work now
         if (strstr (texname, "water") != NULL)
            Ambient[i] = NoAmbientWater ? -1 : AMBIENT_WATER;
         else if (strstr (texname, "sky") != NULL)
            Ambient[i] = NoAmbientSky ? -1 : AMBIENT_SKY;
         else if (strstr (texname, "slime") != NULL)            
            Ambient[i] = NoAmbientSlime ? -1 : AMBIENT_SLIME; // frag.machine - Used to be AMBIENT_WATER
         else if (strstr (texname, "lava") != NULL)
            Ambient[i] = NoAmbientLava ? -1 : AMBIENT_LAVA;
         
         if (Ambient[i] != -1)
            AmbientUsed[Ambient[i]] = true;
      }
      
      if (!NoAmbient)
      {
         for (i = 0; i < NUM_AMBIENTS; ++i)
         {
            if (AmbientUsed[i])
               break;
         }

         if (i == NUM_AMBIENTS)
            NoAmbient = true; // No ambients used; disable sounds
      }
   }
   
   for (i=0 ; i< portalleafs ; i++)
   {
      leaf = &dleafs[i+1];

   //
   // clear ambients
   //
      for (j=0 ; j<NUM_AMBIENTS ; j++)
         dists[j] = 1020;

      // Any textures at all ?
      if (texdatasize != 0 && !NoAmbient)
      {
         vis = &uncompressed[i*bitbytes];
         
         for (j=0 ; j< portalleafs ; j++)
         {
            if ( !(vis[j>>3] & (1<<(j&7))) )
               continue;
         
         //
         // check this leaf for sound textures
         //   
            hit = &dleafs[j+1];

            for (k=0 ; k< hit->nummarksurfaces ; k++)
            {
               surf = &dfaces[dmarksurfaces[hit->firstmarksurface + k]];
               info = &texinfo[surf->texinfo];
               
               if (Ambient[info->miptex] == -1)
                  continue;

               ambient_type = Ambient[info->miptex];

               maxd = 0.25; // Visible => very close
               if (maxd < dists[ambient_type])
                  dists[ambient_type] = maxd;
            }
            
            // NOTE: The logic below only works when maxd is fixed (as in original logic)
            for (k = 0; k < NUM_AMBIENTS; ++k)
            {
               if (AmbientUsed[k] && dists[k] == 1020)
                  break;
            }

            if (k == NUM_AMBIENTS)
               break; // All used ambient positions done
         }
      }
      
      for (j=0 ; j<NUM_AMBIENTS ; j++)
      {
         if (dists[j] < 100)
            vol = 1.0; // Very close => full volume
         else
         {
            vol = 1.0 - dists[j]*0.002; // frag.machine - used to be hardcoded to "vol = 1.0 - dists[2]*0.002;"
            if (vol < 0)
               vol = 0;
         }
         leaf->ambient_level[j] = vol*255;
      }
   }
   
   free (Ambient);
}
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
User avatar
frag.machine
 
Posts: 2090
Joined: Sat Nov 25, 2006 1:49 pm

Re: Ambient sounds

Postby frag.machine » Tue Jun 25, 2013 2:54 am

Oh yeah, almost forgot: there's a small work to do in the engine side. Open up snd_dma.c and find S_Init (). At this end, there's these 2 lines:
Code: Select all
   ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav");
   ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav");


You need to add precaches for slime and lava sounds, too:
Code: Select all
   ambient_sfx[AMBIENT_LAVA] = S_PrecacheSound ("ambience/lava1.wav");
   ambient_sfx[AMBIENT_SLIME] = S_PrecacheSound ("ambience/slime1.wav");


Where "ambience/lava1.wav" and "ambience/slime1.wav" are sounds you need to provide since they don't exist in regular Quake. I suggest a visit to freesound.org or any other public domain sound source.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
User avatar
frag.machine
 
Posts: 2090
Joined: Sat Nov 25, 2006 1:49 pm

Re: Ambient sounds

Postby r00k » Tue Jul 02, 2013 1:36 pm

if your precaches are hardcoded whats the point of cvars?

I was tinkering in snd.dma and changed this for shitz and grinz
Code: Select all
void S_UpdateAmbientSounds (void)
{
   mleaf_t      *l;
   float      vol;
   int         ambient_channel = 0;
   channel_t   *chan;

   if (!cl.worldmodel)
      return;

   if (!ambient_level.value)//R00k: if levels are off dont 'Mod_PointInLeaf' every frame!
   {
      if (channels[ambient_channel].sfx != NULL)//R00k, if there's an sfx in use then clear all...
      {
         for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
            channels[ambient_channel].sfx = NULL;
      }
      return;
   }

   l = Mod_PointInLeaf (listener_origin, cl.worldmodel);

   if (!l)
   {
      for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
         channels[ambient_channel].sfx = NULL;
      return;
   }
r00k
 
Posts: 1110
Joined: Sat Nov 13, 2004 10:39 pm

Re: Ambient sounds

Postby frag.machine » Wed Jul 03, 2013 2:32 am

r00k wrote:if your precaches are hardcoded whats the point of cvars?


I'm sorry, I should have made explicit I was using standard FitzQuake code as reference to the fix.
Of course they aren't fixed (at least, not in this way - the default values of _sfx_env* cvars are the original wav files, so things will work as expected without further intervention).
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
User avatar
frag.machine
 
Posts: 2090
Joined: Sat Nov 25, 2006 1:49 pm

Re: Ambient sounds

Postby mankrip » Thu Jul 04, 2013 11:27 am

I suggest adding a fallback for the engine to use the ambient water sound in the place of the slime/lava sound if the slime/lava sound file isn't found.

Also, frag.machine, dunno why you've used the names "slime1" and "lava1" instead of just "slime" and "lava".
"water1" and "wind2" have numbers, but for new files this doesn't seem necessary.

Would be nice to hunt some official ambient sounds for these in other Id games. Maybe from Q2, QIII or Doom 3.
Ph'nglui mglw'nafh mankrip Hell's end wgah'nagl fhtagn.
==-=-=-=-=-=-=-=-=-=-==
Dev blog / Twitter / YouTube
User avatar
mankrip
 
Posts: 915
Joined: Fri Jul 04, 2008 3:02 am

Re: Ambient sounds

Postby frag.machine » Thu Jul 04, 2013 9:53 pm

mankrip wrote:I suggest adding a fallback for the engine to use the ambient water sound in the place of the slime/lava sound if the slime/lava sound file isn't found.

Also, frag.machine, dunno why you've used the names "slime1" and "lava1" instead of just "slime" and "lava".
"water1" and "wind2" have numbers, but for new files this doesn't seem necessary.

Would be nice to hunt some official ambient sounds for these in other Id games. Maybe from Q2, QIII or Doom 3.


/d'oh!
You're correct, "lava1.wav" and "slime1.wav" are sounds I got from freesound.org for testing purposes, I should have changed that.
IMHO the sanest approach would be to use "misc/null.wav" as default for both cvars, since stock Quake doesn't provide useful sounds.
This would have the benefit of behaving exactly like stock Quake if unmodified.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
User avatar
frag.machine
 
Posts: 2090
Joined: Sat Nov 25, 2006 1:49 pm

Re: Ambient sounds

Postby revelator » Fri Jul 05, 2013 9:10 pm

Heh dunno but im thinking in terms of a parser that could change the abients based on numerical values :) so the idea is not exactly bad something nice might come out of it. Not quite sure how to get the environment data for say a cave so that the ambients have an Echo effect though. If someone knows how i think it might make for an interresting improvement to quake.
Productivity is a state of mind.
User avatar
revelator
 
Posts: 2567
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Ambient sounds

Postby mankrip » Fri Jul 05, 2013 10:25 pm

reckless wrote:Not quite sure how to get the environment data for say a cave so that the ambients have an Echo effect though.

That depends not only on the shape of the environment, but also on what it's made of. Individual resonance values would have to be assigned to each texture, and then the thickness and the shape of the walls would determine how to calculate the echo. But the BSP format also have infinitely thick walls (because everything outside of the map is solid), which there's no proper way to handle automatically.

At least, that's my guess.
Ph'nglui mglw'nafh mankrip Hell's end wgah'nagl fhtagn.
==-=-=-=-=-=-=-=-=-=-==
Dev blog / Twitter / YouTube
User avatar
mankrip
 
Posts: 915
Joined: Fri Jul 04, 2008 3:02 am

Re: Ambient sounds

Postby r00k » Fri Jul 05, 2013 10:48 pm

maybe add an echo to the wav file using audacity since say cave1.wav would always echo?
r00k
 
Posts: 1110
Joined: Sat Nov 13, 2004 10:39 pm

Re: Ambient sounds

Postby revelator » Sat Jul 06, 2013 1:42 am

Yep nothing quite as complicated but it would add some umph to it :)
Productivity is a state of mind.
User avatar
revelator
 
Posts: 2567
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Ambient sounds

Postby frag.machine » Sat Jul 06, 2013 4:00 am

I can't imagine a way to automatically switch to an "echo" effect; I suppose the easiest way to do that is using some kind of "trigger_environment" (or some sort of metadata added to the BSP format saying something like "if you're inside the volumetric area defined by coord1 and coord2 enviromental sounds use an echo effect". In other words, the map needs to have some "hint" about to activate the effect in the engine. Another solution would require some sort of shader support where you could hint about sound effects, and again it would be a task to the mapper to mark "echo" areas thru the use of shaders.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
User avatar
frag.machine
 
Posts: 2090
Joined: Sat Nov 25, 2006 1:49 pm

Re: Ambient sounds

Postby revelator » Sat Jul 06, 2013 12:24 pm

Hmm ill take a look at the bsp defines might be something we could use in them for it :)
Productivity is a state of mind.
User avatar
revelator
 
Posts: 2567
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Ambient sounds

Postby Spike » Sat Jul 06, 2013 12:41 pm

halflife had triggers for its EAX areas...
echo regions only really apply where you have a confined space, you can send out 6 tracelines or so, but you'd need to repeat that process at least one extra time to try to avoid it leaking too badly (distant open areas should be considered closed if they're the corner of pipes or whatever) . And you'd have quite a bit of error in that, so some temporal coherance wouldn't go a miss (weighting it over about 10 seconds with some randomized angles, monte carlo style), but you perhaps can't easily do that inside the vis tool.

need a mixer reverb effect or something. eax for xp users, or switch to openal for linux+vista+ users I guess, or write one in software that works in anything.
Spike
 
Posts: 2892
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Re: Ambient sounds

Postby revelator » Sat Jul 06, 2013 10:11 pm

I´nterresting so we can get the distances from tracelines (allbeit not completely error proof) and i seem to remember a worldtype spawn type from the entity definitions allthough i think its only used to tell the bsp parser to stop parsing gonna have a look.
Productivity is a state of mind.
User avatar
revelator
 
Posts: 2567
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Next

Return to Engine Programming

Who is online

Users browsing this forum: No registered users and 1 guest