File: client\snd_dma.c

    1 /*
    2 Copyright (C) 1997-2001 Id Software, Inc.
    3 
    4 This program is free software; you can redistribute it and/or
    5 modify it under the terms of the GNU General Public License
    6 as published by the Free Software Foundation; either version 2
    7 of the License, or (at your option) any later version.
    8 
    9 This program is distributed in the hope that it will be useful,
   10 but WITHOUT ANY WARRANTY; without even the implied warranty of
   11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
   12 
   13 See the GNU General Public License for more details.
   14 
   15 You should have received a copy of the GNU General Public License
   16 along with this program; if not, write to the Free Software
   17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   18 
   19 */
   20 // snd_dma.c -- main control for any streaming sound output device
   21 
   22 #include "client.h"
   23 #include "snd_loc.h"
   24 
   25 void S_Play(void);
   26 void S_SoundList(void);
   27 void S_Update_();
   28 void S_StopAllSounds(void);
   29 
   30 
   31 // =======================================================================
   32 // Internal sound data & structures
   33 // =======================================================================
   34 
   35 // only begin attenuating sound volumes when outside the FULLVOLUME range
   36 #define         SOUND_FULLVOLUME        80
   37 
   38 #define         SOUND_LOOPATTENUATE     0.003
   39 
   40 int                     s_registration_sequence;
   41 
   42 channel_t   channels[MAX_CHANNELS];
   43 
   44 qboolean        snd_initialized = false;
   45 int                     sound_started=0;
   46 
   47 dma_t           dma;
   48 
   49 vec3_t          listener_origin;
   50 vec3_t          listener_forward;
   51 vec3_t          listener_right;
   52 vec3_t          listener_up;
   53 
   54 qboolean        s_registering;
   55 
   56 int                     soundtime;              // sample PAIRS
   57 int             paintedtime;    // sample PAIRS
   58 
   59 // during registration it is possible to have more sounds
   60 // than could actually be referenced during gameplay,
   61 // because we don't want to free anything until we are
   62 // sure we won't need it.
   63 #define         MAX_SFX         (MAX_SOUNDS*2)
   64 sfx_t           known_sfx[MAX_SFX];
   65 int                     num_sfx;
   66 
   67 #define         MAX_PLAYSOUNDS  128
   68 playsound_t     s_playsounds[MAX_PLAYSOUNDS];
   69 playsound_t     s_freeplays;
   70 playsound_t     s_pendingplays;
   71 
   72 int                     s_beginofs;
   73 
   74 cvar_t          *s_volume;
   75 cvar_t          *s_testsound;
   76 cvar_t          *s_loadas8bit;
   77 cvar_t          *s_khz;
   78 cvar_t          *s_show;
   79 cvar_t          *s_mixahead;
   80 cvar_t          *s_primary;
   81 
   82 
   83 int             s_rawend;
   84 portable_samplepair_t   s_rawsamples[MAX_RAW_SAMPLES];
   85 
   86 
   87 // ====================================================================
   88 // User-setable variables
   89 // ====================================================================
   90 
   91 
   92 void S_SoundInfo_f(void)
   93 {
   94         if (!sound_started)
   95         {
   96                 Com_Printf ("sound system not started\n");
   97                 return;
   98         }
   99         
  100     Com_Printf("%5d stereo\n", dma.channels - 1);
  101     Com_Printf("%5d samples\n", dma.samples);
  102     Com_Printf("%5d samplepos\n", dma.samplepos);
  103     Com_Printf("%5d samplebits\n", dma.samplebits);
  104     Com_Printf("%5d submission_chunk\n", dma.submission_chunk);
  105     Com_Printf("%5d speed\n", dma.speed);
  106     Com_Printf("0x%x dma buffer\n", dma.buffer);
  107 }
  108 
  109 
  110 
  111 /*
  112 ================
  113 S_Init
  114 ================
  115 */
  116 void S_Init (void)
  117 {
  118         cvar_t  *cv;
  119 
  120         Com_Printf("\n------- sound initialization -------\n");
  121 
  122         cv = Cvar_Get ("s_initsound", "1", 0);
  123         if (!cv->value)
  124                 Com_Printf ("not initializing.\n");
  125         else
  126         {
  127                 s_volume = Cvar_Get ("s_volume", "0.7", CVAR_ARCHIVE);
  128                 s_khz = Cvar_Get ("s_khz", "11", CVAR_ARCHIVE);
  129                 s_loadas8bit = Cvar_Get ("s_loadas8bit", "1", CVAR_ARCHIVE);
  130                 s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE);
  131                 s_show = Cvar_Get ("s_show", "0", 0);
  132                 s_testsound = Cvar_Get ("s_testsound", "0", 0);
  133                 s_primary = Cvar_Get ("s_primary", "0", CVAR_ARCHIVE);  // win32 specific
  134 
  135                 Cmd_AddCommand("play", S_Play);
  136                 Cmd_AddCommand("stopsound", S_StopAllSounds);
  137                 Cmd_AddCommand("soundlist", S_SoundList);
  138                 Cmd_AddCommand("soundinfo", S_SoundInfo_f);
  139 
  140                 if (!SNDDMA_Init())
  141                         return;
  142 
  143                 S_InitScaletable ();
  144 
  145                 sound_started = 1;
  146                 num_sfx = 0;
  147 
  148                 soundtime = 0;
  149                 paintedtime = 0;
  150 
  151                 Com_Printf ("sound sampling rate: %i\n", dma.speed);
  152 
  153                 S_StopAllSounds ();
  154         }
  155 
  156         Com_Printf("------------------------------------\n");
  157 }
  158 
  159 
  160 // =======================================================================
  161 // Shutdown sound engine
  162 // =======================================================================
  163 
  164 void S_Shutdown(void)
  165 {
  166         int             i;
  167         sfx_t   *sfx;
  168 
  169         if (!sound_started)
  170                 return;
  171 
  172         SNDDMA_Shutdown();
  173 
  174         sound_started = 0;
  175 
  176         Cmd_RemoveCommand("play");
  177         Cmd_RemoveCommand("stopsound");
  178         Cmd_RemoveCommand("soundlist");
  179         Cmd_RemoveCommand("soundinfo");
  180 
  181         // free all sounds
  182         for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
  183         {
  184                 if (!sfx->name[0])
  185                         continue;
  186                 if (sfx->cache)
  187                         Z_Free (sfx->cache);
  188                 memset (sfx, 0, sizeof(*sfx));
  189         }
  190 
  191         num_sfx = 0;
  192 }
  193 
  194 
  195 // =======================================================================
  196 // Load a sound
  197 // =======================================================================
  198 
  199 /*
  200 ==================
  201 S_FindName
  202 
  203 ==================
  204 */
  205 sfx_t *S_FindName (char *name, qboolean create)
  206 {
  207         int             i;
  208         sfx_t   *sfx;
  209 
  210         if (!name)
  211                 Com_Error (ERR_FATAL, "S_FindName: NULL\n");
  212         if (!name[0])
  213                 Com_Error (ERR_FATAL, "S_FindName: empty name\n");
  214 
  215         if (strlen(name) >= MAX_QPATH)
  216                 Com_Error (ERR_FATAL, "Sound name too long: %s", name);
  217 
  218         // see if already loaded
  219         for (i=0 ; i < num_sfx ; i++)
  220                 if (!strcmp(known_sfx[i].name, name))
  221                 {
  222                         return &known_sfx[i];
  223                 }
  224 
  225         if (!create)
  226                 return NULL;
  227 
  228         // find a free sfx
  229         for (i=0 ; i < num_sfx ; i++)
  230                 if (!known_sfx[i].name[0])
  231 //                      registration_sequence < s_registration_sequence)
  232                         break;
  233 
  234         if (i == num_sfx)
  235         {
  236                 if (num_sfx == MAX_SFX)
  237                         Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
  238                 num_sfx++;
  239         }
  240         
  241         sfx = &known_sfx[i];
  242         memset (sfx, 0, sizeof(*sfx));
  243         strcpy (sfx->name, name);
  244         sfx->registration_sequence = s_registration_sequence;
  245         
  246         return sfx;
  247 }
  248 
  249 
  250 /*
  251 ==================
  252 S_AliasName
  253 
  254 ==================
  255 */
  256 sfx_t *S_AliasName (char *aliasname, char *truename)
  257 {
  258         sfx_t   *sfx;
  259         char    *s;
  260         int             i;
  261 
  262         s = Z_Malloc (MAX_QPATH);
  263         strcpy (s, truename);
  264 
  265         // find a free sfx
  266         for (i=0 ; i < num_sfx ; i++)
  267                 if (!known_sfx[i].name[0])
  268                         break;
  269 
  270         if (i == num_sfx)
  271         {
  272                 if (num_sfx == MAX_SFX)
  273                         Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
  274                 num_sfx++;
  275         }
  276         
  277         sfx = &known_sfx[i];
  278         memset (sfx, 0, sizeof(*sfx));
  279         strcpy (sfx->name, aliasname);
  280         sfx->registration_sequence = s_registration_sequence;
  281         sfx->truename = s;
  282 
  283         return sfx;
  284 }
  285 
  286 
  287 /*
  288 =====================
  289 S_BeginRegistration
  290 
  291 =====================
  292 */
  293 void S_BeginRegistration (void)
  294 {
  295         s_registration_sequence++;
  296         s_registering = true;
  297 }
  298 
  299 /*
  300 ==================
  301 S_RegisterSound
  302 
  303 ==================
  304 */
  305 sfx_t *S_RegisterSound (char *name)
  306 {
  307         sfx_t   *sfx;
  308 
  309         if (!sound_started)
  310                 return NULL;
  311 
  312         sfx = S_FindName (name, true);
  313         sfx->registration_sequence = s_registration_sequence;
  314 
  315         if (!s_registering)
  316                 S_LoadSound (sfx);
  317 
  318         return sfx;
  319 }
  320 
  321 
  322 /*
  323 =====================
  324 S_EndRegistration
  325 
  326 =====================
  327 */
  328 void S_EndRegistration (void)
  329 {
  330         int             i;
  331         sfx_t   *sfx;
  332         int             size;
  333 
  334         // free any sounds not from this registration sequence
  335         for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
  336         {
  337                 if (!sfx->name[0])
  338                         continue;
  339                 if (sfx->registration_sequence != s_registration_sequence)
  340                 {       // don't need this sound
  341                         if (sfx->cache) // it is possible to have a leftover
  342                                 Z_Free (sfx->cache);    // from a server that didn't finish loading
  343                         memset (sfx, 0, sizeof(*sfx));
  344                 }
  345                 else
  346                 {       // make sure it is paged in
  347                         if (sfx->cache)
  348                         {
  349                                 size = sfx->cache->length*sfx->cache->width;
  350                                 Com_PageInMemory ((byte *)sfx->cache, size);
  351                         }
  352                 }
  353 
  354         }
  355 
  356         // load everything in
  357         for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
  358         {
  359                 if (!sfx->name[0])
  360                         continue;
  361                 S_LoadSound (sfx);
  362         }
  363 
  364         s_registering = false;
  365 }
  366 
  367 
  368 //=============================================================================
  369 
  370 /*
  371 =================
  372 S_PickChannel
  373 =================
  374 */
  375 channel_t *S_PickChannel(int entnum, int entchannel)
  376 {
  377     int                 ch_idx;
  378     int                 first_to_die;
  379     int                 life_left;
  380         channel_t       *ch;
  381 
  382         if (entchannel<0)
  383                 Com_Error (ERR_DROP, "S_PickChannel: entchannel<0");
  384 
  385 // Check for replacement sound, or find the best one to replace
  386     first_to_die = -1;
  387     life_left = 0x7fffffff;
  388     for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++)
  389     {
  390                 if (entchannel != 0             // channel 0 never overrides
  391                 && channels[ch_idx].entnum == entnum
  392                 && channels[ch_idx].entchannel == entchannel)
  393                 {       // always override sound from same entity
  394                         first_to_die = ch_idx;
  395                         break;
  396                 }
  397 
  398                 // don't let monster sounds override player sounds
  399                 if (channels[ch_idx].entnum == cl.playernum+1 && entnum != cl.playernum+1 && channels[ch_idx].sfx)
  400                         continue;
  401 
  402                 if (channels[ch_idx].end - paintedtime < life_left)
  403                 {
  404                         life_left = channels[ch_idx].end - paintedtime;
  405                         first_to_die = ch_idx;
  406                 }
  407    }
  408 
  409         if (first_to_die == -1)
  410                 return NULL;
  411 
  412         ch = &channels[first_to_die];
  413         memset (ch, 0, sizeof(*ch));
  414 
  415     return ch;
  416 }       
  417 
  418 /*
  419 =================
  420 S_SpatializeOrigin
  421 
  422 Used for spatializing channels and autosounds
  423 =================
  424 */
  425 void S_SpatializeOrigin (vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
  426 {
  427     vec_t               dot;
  428     vec_t               dist;
  429     vec_t               lscale, rscale, scale;
  430     vec3_t              source_vec;
  431 
  432         if (cls.state != ca_active)
  433         {
  434                 *left_vol = *right_vol = 255;
  435                 return;
  436         }
  437 
  438 // calculate stereo seperation and distance attenuation
  439         VectorSubtract(origin, listener_origin, source_vec);
  440 
  441         dist = VectorNormalize(source_vec);
  442         dist -= SOUND_FULLVOLUME;
  443         if (dist < 0)
  444                 dist = 0;                       // close enough to be at full volume
  445         dist *= dist_mult;              // different attenuation levels
  446         
  447         dot = DotProduct(listener_right, source_vec);
  448 
  449         if (dma.channels == 1 || !dist_mult)
  450         { // no attenuation = no spatialization
  451                 rscale = 1.0;
  452                 lscale = 1.0;
  453         }
  454         else
  455         {
  456                 rscale = 0.5 * (1.0 + dot);
  457                 lscale = 0.5*(1.0 - dot);
  458         }
  459 
  460         // add in distance effect
  461         scale = (1.0 - dist) * rscale;
  462         *right_vol = (int) (master_vol * scale);
  463         if (*right_vol < 0)
  464                 *right_vol = 0;
  465 
  466         scale = (1.0 - dist) * lscale;
  467         *left_vol = (int) (master_vol * scale);
  468         if (*left_vol < 0)
  469                 *left_vol = 0;
  470 }
  471 
  472 /*
  473 =================
  474 S_Spatialize
  475 =================
  476 */
  477 void S_Spatialize(channel_t *ch)
  478 {
  479         vec3_t          origin;
  480 
  481         // anything coming from the view entity will always be full volume
  482         if (ch->entnum == cl.playernum+1)
  483         {
  484                 ch->leftvol = ch->master_vol;
  485                 ch->rightvol = ch->master_vol;
  486                 return;
  487         }
  488 
  489         if (ch->fixed_origin)
  490         {
  491                 VectorCopy (ch->origin, origin);
  492         }
  493         else
  494                 CL_GetEntitySoundOrigin (ch->entnum, origin);
  495 
  496         S_SpatializeOrigin (origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol);
  497 }           
  498 
  499 
  500 /*
  501 =================
  502 S_AllocPlaysound
  503 =================
  504 */
  505 playsound_t *S_AllocPlaysound (void)
  506 {
  507         playsound_t     *ps;
  508 
  509         ps = s_freeplays.next;
  510         if (ps == &s_freeplays)
  511                 return NULL;            // no free playsounds
  512 
  513         // unlink from freelist
  514         ps->prev->next = ps->next;
  515         ps->next->prev = ps->prev;
  516         
  517         return ps;
  518 }
  519 
  520 
  521 /*
  522 =================
  523 S_FreePlaysound
  524 =================
  525 */
  526 void S_FreePlaysound (playsound_t *ps)
  527 {
  528         // unlink from channel
  529         ps->prev->next = ps->next;
  530         ps->next->prev = ps->prev;
  531 
  532         // add to free list
  533         ps->next = s_freeplays.next;
  534         s_freeplays.next->prev = ps;
  535         ps->prev = &s_freeplays;
  536         s_freeplays.next = ps;
  537 }
  538 
  539 
  540 
  541 /*
  542 ===============
  543 S_IssuePlaysound
  544 
  545 Take the next playsound and begin it on the channel
  546 This is never called directly by S_Play*, but only
  547 by the update loop.
  548 ===============
  549 */
  550 void S_IssuePlaysound (playsound_t *ps)
  551 {
  552         channel_t       *ch;
  553         sfxcache_t      *sc;
  554 
  555         if (s_show->value)
  556                 Com_Printf ("Issue %i\n", ps->begin);
  557         // pick a channel to play on
  558         ch = S_PickChannel(ps->entnum, ps->entchannel);
  559         if (!ch)
  560         {
  561                 S_FreePlaysound (ps);
  562                 return;
  563         }
  564 
  565         // spatialize
  566         if (ps->attenuation == ATTN_STATIC)
  567                 ch->dist_mult = ps->attenuation * 0.001;
  568         else
  569                 ch->dist_mult = ps->attenuation * 0.0005;
  570         ch->master_vol = ps->volume;
  571         ch->entnum = ps->entnum;
  572         ch->entchannel = ps->entchannel;
  573         ch->sfx = ps->sfx;
  574         VectorCopy (ps->origin, ch->origin);
  575         ch->fixed_origin = ps->fixed_origin;
  576 
  577         S_Spatialize(ch);
  578 
  579         ch->pos = 0;
  580         sc = S_LoadSound (ch->sfx);
  581     ch->end = paintedtime + sc->length;
  582 
  583         // free the playsound
  584         S_FreePlaysound (ps);
  585 }
  586 
  587 struct sfx_s *S_RegisterSexedSound (entity_state_t *ent, char *base)
  588 {
  589         int                             n;
  590         char                    *p;
  591         struct sfx_s    *sfx;
  592         FILE                    *f;
  593         char                    model[MAX_QPATH];
  594         char                    sexedFilename[MAX_QPATH];
  595         char                    maleFilename[MAX_QPATH];
  596 
  597         // determine what model the client is using
  598         model[0] = 0;
  599         n = CS_PLAYERSKINS + ent->number - 1;
  600         if (cl.configstrings[n][0])
  601         {
  602                 p = strchr(cl.configstrings[n], '\\');
  603                 if (p)
  604                 {
  605                         p += 1;
  606                         strcpy(model, p);
  607                         p = strchr(model, '/');
  608                         if (p)
  609                                 *p = 0;
  610                 }
  611         }
  612         // if we can't figure it out, they're male
  613         if (!model[0])
  614                 strcpy(model, "male");
  615 
  616         // see if we already know of the model specific sound
  617         Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1);
  618         sfx = S_FindName (sexedFilename, false);
  619 
  620         if (!sfx)
  621         {
  622                 // no, so see if it exists
  623                 FS_FOpenFile (&sexedFilename[1], &f);
  624                 if (f)
  625                 {
  626                         // yes, close the file and register it
  627                         FS_FCloseFile (f);
  628                         sfx = S_RegisterSound (sexedFilename);
  629                 }
  630                 else
  631                 {
  632                         // no, revert to the male sound in the pak0.pak
  633                         Com_sprintf (maleFilename, sizeof(maleFilename), "player/%s/%s", "male", base+1);
  634                         sfx = S_AliasName (sexedFilename, maleFilename);
  635                 }
  636         }
  637 
  638         return sfx;
  639 }
  640 
  641 
  642 // =======================================================================
  643 // Start a sound effect
  644 // =======================================================================
  645 
  646 /*
  647 ====================
  648 S_StartSound
  649 
  650 Validates the parms and ques the sound up
  651 if pos is NULL, the sound will be dynamically sourced from the entity
  652 Entchannel 0 will never override a playing sound
  653 ====================
  654 */
  655 void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs)
  656 {
  657         sfxcache_t      *sc;
  658         int                     vol;
  659         playsound_t     *ps, *sort;
  660         int                     start;
  661 
  662         if (!sound_started)
  663                 return;
  664 
  665         if (!sfx)
  666                 return;
  667 
  668         if (sfx->name[0] == '*')
  669                 sfx = S_RegisterSexedSound(&cl_entities[entnum].current, sfx->name);
  670 
  671         // make sure the sound is loaded
  672         sc = S_LoadSound (sfx);
  673         if (!sc)
  674                 return;         // couldn't load the sound's data
  675 
  676         vol = fvol*255;
  677 
  678         // make the playsound_t
  679         ps = S_AllocPlaysound ();
  680         if (!ps)
  681                 return;
  682 
  683         if (origin)
  684         {
  685                 VectorCopy (origin, ps->origin);
  686                 ps->fixed_origin = true;
  687         }
  688         else
  689                 ps->fixed_origin = false;
  690 
  691         ps->entnum = entnum;
  692         ps->entchannel = entchannel;
  693         ps->attenuation = attenuation;
  694         ps->volume = vol;
  695         ps->sfx = sfx;
  696 
  697         // drift s_beginofs
  698         start = cl.frame.servertime * 0.001 * dma.speed + s_beginofs;
  699         if (start < paintedtime)
  700         {
  701                 start = paintedtime;
  702                 s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
  703         }
  704         else if (start > paintedtime + 0.3 * dma.speed)
  705         {
  706                 start = paintedtime + 0.1 * dma.speed;
  707                 s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
  708         }
  709         else
  710         {
  711                 s_beginofs-=10;
  712         }
  713 
  714         if (!timeofs)
  715                 ps->begin = paintedtime;
  716         else
  717                 ps->begin = start + timeofs * dma.speed;
  718 
  719         // sort into the pending sound list
  720         for (sort = s_pendingplays.next ; 
  721                 sort != &s_pendingplays && sort->begin < ps->begin ;
  722                 sort = sort->next)
  723                         ;
  724 
  725         ps->next = sort;
  726         ps->prev = sort->prev;
  727 
  728         ps->next->prev = ps;
  729         ps->prev->next = ps;
  730 }
  731 
  732 
  733 /*
  734 ==================
  735 S_StartLocalSound
  736 ==================
  737 */
  738 void S_StartLocalSound (char *sound)
  739 {
  740         sfx_t   *sfx;
  741 
  742         if (!sound_started)
  743                 return;
  744                 
  745         sfx = S_RegisterSound (sound);
  746         if (!sfx)
  747         {
  748                 Com_Printf ("S_StartLocalSound: can't cache %s\n", sound);
  749                 return;
  750         }
  751         S_StartSound (NULL, cl.playernum+1, 0, sfx, 1, 1, 0);
  752 }
  753 
  754 
  755 /*
  756 ==================
  757 S_ClearBuffer
  758 ==================
  759 */
  760 void S_ClearBuffer (void)
  761 {
  762         int             clear;
  763                 
  764         if (!sound_started)
  765                 return;
  766 
  767         s_rawend = 0;
  768 
  769         if (dma.samplebits == 8)
  770                 clear = 0x80;
  771         else
  772                 clear = 0;
  773 
  774         SNDDMA_BeginPainting ();
  775         if (dma.buffer)
  776                 memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
  777         SNDDMA_Submit ();
  778 }
  779 
  780 /*
  781 ==================
  782 S_StopAllSounds
  783 ==================
  784 */
  785 void S_StopAllSounds(void)
  786 {
  787         int             i;
  788 
  789         if (!sound_started)
  790                 return;
  791 
  792         // clear all the playsounds
  793         memset(s_playsounds, 0, sizeof(s_playsounds));
  794         s_freeplays.next = s_freeplays.prev = &s_freeplays;
  795         s_pendingplays.next = s_pendingplays.prev = &s_pendingplays;
  796 
  797         for (i=0 ; i<MAX_PLAYSOUNDS ; i++)
  798         {
  799                 s_playsounds[i].prev = &s_freeplays;
  800                 s_playsounds[i].next = s_freeplays.next;
  801                 s_playsounds[i].prev->next = &s_playsounds[i];
  802                 s_playsounds[i].next->prev = &s_playsounds[i];
  803         }
  804 
  805         // clear all the channels
  806         memset(channels, 0, sizeof(channels));
  807 
  808         S_ClearBuffer ();
  809 }
  810 
  811 /*
  812 ==================
  813 S_AddLoopSounds
  814 
  815 Entities with a ->sound field will generated looped sounds
  816 that are automatically started, stopped, and merged together
  817 as the entities are sent to the client
  818 ==================
  819 */
  820 void S_AddLoopSounds (void)
  821 {
  822         int                     i, j;
  823         int                     sounds[MAX_EDICTS];
  824         int                     left, right, left_total, right_total;
  825         channel_t       *ch;
  826         sfx_t           *sfx;
  827         sfxcache_t      *sc;
  828         int                     num;
  829         entity_state_t  *ent;
  830 
  831         if (cl_paused->value)
  832                 return;
  833 
  834         if (cls.state != ca_active)
  835                 return;
  836 
  837         if (!cl.sound_prepped)
  838                 return;
  839 
  840         for (i=0 ; i<cl.frame.num_entities ; i++)
  841         {
  842                 num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
  843                 ent = &cl_parse_entities[num];
  844                 sounds[i] = ent->sound;
  845         }
  846 
  847         for (i=0 ; i<cl.frame.num_entities ; i++)
  848         {
  849                 if (!sounds[i])
  850                         continue;
  851 
  852                 sfx = cl.sound_precache[sounds[i]];
  853                 if (!sfx)
  854                         continue;               // bad sound effect
  855                 sc = sfx->cache;
  856                 if (!sc)
  857                         continue;
  858 
  859                 num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
  860                 ent = &cl_parse_entities[num];
  861 
  862                 // find the total contribution of all sounds of this type
  863                 S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
  864                         &left_total, &right_total);
  865                 for (j=i+1 ; j<cl.frame.num_entities ; j++)
  866                 {
  867                         if (sounds[j] != sounds[i])
  868                                 continue;
  869                         sounds[j] = 0;  // don't check this again later
  870 
  871                         num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1);
  872                         ent = &cl_parse_entities[num];
  873 
  874                         S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE, 
  875                                 &left, &right);
  876                         left_total += left;
  877                         right_total += right;
  878                 }
  879 
  880                 if (left_total == 0 && right_total == 0)
  881                         continue;               // not audible
  882 
  883                 // allocate a channel
  884                 ch = S_PickChannel(0, 0);
  885                 if (!ch)
  886                         return;
  887 
  888                 if (left_total > 255)
  889                         left_total = 255;
  890                 if (right_total > 255)
  891                         right_total = 255;
  892                 ch->leftvol = left_total;
  893                 ch->rightvol = right_total;
  894                 ch->autosound = true;   // remove next frame
  895                 ch->sfx = sfx;
  896                 ch->pos = paintedtime % sc->length;
  897                 ch->end = paintedtime + sc->length - ch->pos;
  898         }
  899 }
  900 
  901 //=============================================================================
  902 
  903 /*
  904 ============
  905 S_RawSamples
  906 
  907 Cinematic streaming and voice over network
  908 ============
  909 */
  910 void S_RawSamples (int samples, int rate, int width, int channels, byte *data)
  911 {
  912         int             i;
  913         int             src, dst;
  914         float   scale;
  915 
  916         if (!sound_started)
  917                 return;
  918 
  919         if (s_rawend < paintedtime)
  920                 s_rawend = paintedtime;
  921         scale = (float)rate / dma.speed;
  922 
  923 //Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend);
  924         if (channels == 2 && width == 2)
  925         {
  926                 if (scale == 1.0)
  927                 {       // optimized case
  928                         for (i=0 ; i<samples ; i++)
  929                         {
  930                                 dst = s_rawend&(MAX_RAW_SAMPLES-1);
  931                                 s_rawend++;
  932                                 s_rawsamples[dst].left =
  933                                     LittleShort(((short *)data)[i*2]) << 8;
  934                                 s_rawsamples[dst].right =
  935                                     LittleShort(((short *)data)[i*2+1]) << 8;
  936                         }
  937                 }
  938                 else
  939                 {
  940                         for (i=0 ; ; i++)
  941                         {
  942                                 src = i*scale;
  943                                 if (src >= samples)
  944                                         break;
  945                                 dst = s_rawend&(MAX_RAW_SAMPLES-1);
  946                                 s_rawend++;
  947                                 s_rawsamples[dst].left =
  948                                     LittleShort(((short *)data)[src*2]) << 8;
  949                                 s_rawsamples[dst].right =
  950                                     LittleShort(((short *)data)[src*2+1]) << 8;
  951                         }
  952                 }
  953         }
  954         else if (channels == 1 && width == 2)
  955         {
  956                 for (i=0 ; ; i++)
  957                 {
  958                         src = i*scale;
  959                         if (src >= samples)
  960                                 break;
  961                         dst = s_rawend&(MAX_RAW_SAMPLES-1);
  962                         s_rawend++;
  963                         s_rawsamples[dst].left =
  964                             LittleShort(((short *)data)[src]) << 8;
  965                         s_rawsamples[dst].right =
  966                             LittleShort(((short *)data)[src]) << 8;
  967                 }
  968         }
  969         else if (channels == 2 && width == 1)
  970         {
  971                 for (i=0 ; ; i++)
  972                 {
  973                         src = i*scale;
  974                         if (src >= samples)
  975                                 break;
  976                         dst = s_rawend&(MAX_RAW_SAMPLES-1);
  977                         s_rawend++;
  978                         s_rawsamples[dst].left =
  979                             ((char *)data)[src*2] << 16;
  980                         s_rawsamples[dst].right =
  981                             ((char *)data)[src*2+1] << 16;
  982                 }
  983         }
  984         else if (channels == 1 && width == 1)
  985         {
  986                 for (i=0 ; ; i++)
  987                 {
  988                         src = i*scale;
  989                         if (src >= samples)
  990                                 break;
  991                         dst = s_rawend&(MAX_RAW_SAMPLES-1);
  992                         s_rawend++;
  993                         s_rawsamples[dst].left =
  994                             (((byte *)data)[src]-128) << 16;
  995                         s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16;
  996                 }
  997         }
  998 }
  999 
 1000 //=============================================================================
 1001 
 1002 /*
 1003 ============
 1004 S_Update
 1005 
 1006 Called once each time through the main loop
 1007 ============
 1008 */
 1009 void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
 1010 {
 1011         int                     i;
 1012         int                     total;
 1013         channel_t       *ch;
 1014         channel_t       *combine;
 1015 
 1016         if (!sound_started)
 1017                 return;
 1018 
 1019         // if the laoding plaque is up, clear everything
 1020         // out to make sure we aren't looping a dirty
 1021         // dma buffer while loading
 1022         if (cls.disable_screen)
 1023         {
 1024                 S_ClearBuffer ();
 1025                 return;
 1026         }
 1027 
 1028         // rebuild scale tables if volume is modified
 1029         if (s_volume->modified)
 1030                 S_InitScaletable ();
 1031 
 1032         VectorCopy(origin, listener_origin);
 1033         VectorCopy(forward, listener_forward);
 1034         VectorCopy(right, listener_right);
 1035         VectorCopy(up, listener_up);
 1036 
 1037         combine = NULL;
 1038 
 1039         // update spatialization for dynamic sounds     
 1040         ch = channels;
 1041         for (i=0 ; i<MAX_CHANNELS; i++, ch++)
 1042         {
 1043                 if (!ch->sfx)
 1044                         continue;
 1045                 if (ch->autosound)
 1046                 {       // autosounds are regenerated fresh each frame
 1047                         memset (ch, 0, sizeof(*ch));
 1048                         continue;
 1049                 }
 1050                 S_Spatialize(ch);         // respatialize channel
 1051                 if (!ch->leftvol && !ch->rightvol)
 1052                 {
 1053                         memset (ch, 0, sizeof(*ch));
 1054                         continue;
 1055                 }
 1056         }
 1057 
 1058         // add loopsounds
 1059         S_AddLoopSounds ();
 1060 
 1061         //
 1062         // debugging output
 1063         //
 1064         if (s_show->value)
 1065         {
 1066                 total = 0;
 1067                 ch = channels;
 1068                 for (i=0 ; i<MAX_CHANNELS; i++, ch++)
 1069                         if (ch->sfx && (ch->leftvol || ch->rightvol) )
 1070                         {
 1071                                 Com_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
 1072                                 total++;
 1073                         }
 1074                 
 1075                 Com_Printf ("----(%i)---- painted: %i\n", total, paintedtime);
 1076         }
 1077 
 1078 // mix some sound
 1079         S_Update_();
 1080 }
 1081 
 1082 void GetSoundtime(void)
 1083 {
 1084         int             samplepos;
 1085         static  int             buffers;
 1086         static  int             oldsamplepos;
 1087         int             fullsamples;
 1088         
 1089         fullsamples = dma.samples / dma.channels;
 1090 
 1091 // it is possible to miscount buffers if it has wrapped twice between
 1092 // calls to S_Update.  Oh well.
 1093         samplepos = SNDDMA_GetDMAPos();
 1094 
 1095         if (samplepos < oldsamplepos)
 1096         {
 1097                 buffers++;                                      // buffer wrapped
 1098                 
 1099                 if (paintedtime > 0x40000000)
 1100                 {       // time to chop things off to avoid 32 bit limits
 1101                         buffers = 0;
 1102                         paintedtime = fullsamples;
 1103                         S_StopAllSounds ();
 1104                 }
 1105         }
 1106         oldsamplepos = samplepos;
 1107 
 1108         soundtime = buffers*fullsamples + samplepos/dma.channels;
 1109 }
 1110 
 1111 
 1112 void S_Update_(void)
 1113 {
 1114         unsigned        endtime;
 1115         int                             samps;
 1116 
 1117         if (!sound_started)
 1118                 return;
 1119 
 1120         SNDDMA_BeginPainting ();
 1121 
 1122         if (!dma.buffer)
 1123                 return;
 1124 
 1125 // Updates DMA time
 1126         GetSoundtime();
 1127 
 1128 // check to make sure that we haven't overshot
 1129         if (paintedtime < soundtime)
 1130         {
 1131                 Com_DPrintf ("S_Update_ : overflow\n");
 1132                 paintedtime = soundtime;
 1133         }
 1134 
 1135 // mix ahead of current position
 1136         endtime = soundtime + s_mixahead->value * dma.speed;
 1137 //endtime = (soundtime + 4096) & ~4095;
 1138 
 1139         // mix to an even submission block size
 1140         endtime = (endtime + dma.submission_chunk-1)
 1141                 & ~(dma.submission_chunk-1);
 1142         samps = dma.samples >> (dma.channels-1);
 1143         if (endtime - soundtime > samps)
 1144                 endtime = soundtime + samps;
 1145 
 1146         S_PaintChannels (endtime);
 1147 
 1148         SNDDMA_Submit ();
 1149 }
 1150 
 1151 /*
 1152 ===============================================================================
 1153 
 1154 console functions
 1155 
 1156 ===============================================================================
 1157 */
 1158 
 1159 void S_Play(void)
 1160 {
 1161         int     i;
 1162         char name[256];
 1163         sfx_t   *sfx;
 1164         
 1165         i = 1;
 1166         while (i<Cmd_Argc())
 1167         {
 1168                 if (!strrchr(Cmd_Argv(i), '.'))
 1169                 {
 1170                         strcpy(name, Cmd_Argv(i));
 1171                         strcat(name, ".wav");
 1172                 }
 1173                 else
 1174                         strcpy(name, Cmd_Argv(i));
 1175                 sfx = S_RegisterSound(name);
 1176                 S_StartSound(NULL, cl.playernum+1, 0, sfx, 1.0, 1.0, 0);
 1177                 i++;
 1178         }
 1179 }
 1180 
 1181 void S_SoundList(void)
 1182 {
 1183         int             i;
 1184         sfx_t   *sfx;
 1185         sfxcache_t      *sc;
 1186         int             size, total;
 1187 
 1188         total = 0;
 1189         for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
 1190         {
 1191                 if (!sfx->registration_sequence)
 1192                         continue;
 1193                 sc = sfx->cache;
 1194                 if (sc)
 1195                 {
 1196                         size = sc->length*sc->width*(sc->stereo+1);
 1197                         total += size;
 1198                         if (sc->loopstart >= 0)
 1199                                 Com_Printf ("L");
 1200                         else
 1201                                 Com_Printf (" ");
 1202                         Com_Printf("(%2db) %6i : %s\n",sc->width*8,  size, sfx->name);
 1203                 }
 1204                 else
 1205                 {
 1206                         if (sfx->name[0] == '*')
 1207                                 Com_Printf("  placeholder : %s\n", sfx->name);
 1208                         else
 1209                                 Com_Printf("  not loaded  : %s\n", sfx->name);
 1210                 }
 1211         }
 1212         Com_Printf ("Total resident: %i\n", total);
 1213 }
 1214 
 1215