s_sound.c
上传用户:xuyinpeng
上传日期:2021-05-12
资源大小:455k
文件大小:18k
源码类别:

射击游戏

开发平台:

Visual C++

  1. // Emacs style mode select   -*- C++ -*- 
  2. //-----------------------------------------------------------------------------
  3. //
  4. // $Id:$
  5. //
  6. // Copyright (C) 1993-1996 by id Software, Inc.
  7. //
  8. // This source is available for distribution and/or modification
  9. // only under the terms of the DOOM Source Code License as
  10. // published by id Software. All rights reserved.
  11. //
  12. // The source is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
  15. // for more details.
  16. //
  17. // $Log:$
  18. //
  19. // DESCRIPTION:  none
  20. //
  21. //-----------------------------------------------------------------------------
  22. static const char
  23. rcsid[] = "$Id: s_sound.c,v 1.6 1997/02/03 22:45:12 b1 Exp $";
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include "i_system.h"
  27. #include "i_sound.h"
  28. #include "sounds.h"
  29. #include "s_sound.h"
  30. #include "z_zone.h"
  31. #include "m_random.h"
  32. #include "w_wad.h"
  33. #include "doomdef.h"
  34. #include "p_local.h"
  35. #include "doomstat.h"
  36. void WriteDebug(char *);
  37. // Purpose?
  38. const char snd_prefixen[]
  39. = { 'P', 'P', 'A', 'S', 'S', 'S', 'M', 'M', 'M', 'S', 'S', 'S' };
  40. #define S_MAX_VOLUME 127
  41. // when to clip out sounds
  42. // Does not fit the large outdoor areas.
  43. #define S_CLIPPING_DIST (1200*0x10000)
  44. // Distance tp origin when sounds should be maxed out.
  45. // This should relate to movement clipping resolution
  46. // (see BLOCKMAP handling).
  47. // Originally: (200*0x10000).
  48. #define S_CLOSE_DIST (160*0x10000)
  49. #define S_ATTENUATOR ((S_CLIPPING_DIST-S_CLOSE_DIST)>>FRACBITS)
  50. // Adjustable by menu.
  51. #define NORM_VOLUME     snd_MaxVolume
  52. #define NORM_PITCH      128
  53. #define NORM_PRIORITY 64
  54. #define NORM_SEP 128
  55. #define S_PITCH_PERTURB 1
  56. #define S_STEREO_SWING (96*0x10000)
  57. // percent attenuation from front to back
  58. #define S_IFRACVOL 30
  59. #define NA 0
  60. #define S_NUMCHANNELS 2
  61. #define NUM_DSBUFFERS      256
  62. // Current music/sfx card - index useless
  63. //  w/o a reference LUT in a sound module.
  64. extern int snd_MusicDevice;
  65. extern int snd_SfxDevice;
  66. // Config file? Same disclaimer as above.
  67. extern int snd_DesiredMusicDevice;
  68. extern int snd_DesiredSfxDevice;
  69. typedef struct
  70. {
  71.     // sound information (if null, channel avail.)
  72.     sfxinfo_t* sfxinfo;
  73.     // origin of sound
  74.     void* origin;
  75.     // handle of the sound being played
  76.     int handle;
  77.     
  78. } channel_t;
  79. // the set of channels available
  80. static channel_t* channels;
  81. // These are not used, but should be (menu).
  82. // Maximum volume of a sound effect.
  83. // Internal default is max out of 0-15.
  84. int  snd_SfxVolume = 15;
  85. // Maximum volume of music. Useless so far.
  86. int  snd_MusicVolume = 15; 
  87. // whether songs are mus_paused
  88. static boolean mus_paused;
  89. // music currently being played
  90. static musicinfo_t* mus_playing=0;
  91. // following is set
  92. //  by the defaults code in M_misc:
  93. // number of channels available
  94. int numChannels;
  95. static int nextcleanup;
  96. //
  97. // Internals.
  98. //
  99. int
  100. S_getChannel
  101. ( void* origin,
  102.   sfxinfo_t* sfxinfo,
  103.   int       sfxid );
  104. int
  105. S_AdjustSoundParams
  106. ( mobj_t* listener,
  107.   mobj_t* source,
  108.   int* vol,
  109.   int* sep,
  110.   int* pitch );
  111. void S_StopChannel(int cnum);
  112. //
  113. // Initializes sound stuff, including volume
  114. // Sets channels, SFX and music volume,
  115. //  allocates channel buffer, sets S_sfx lookup.
  116. //
  117. void S_Init
  118. ( int sfxVolume,
  119.   int musicVolume )
  120. {  
  121.   int i;
  122.   fprintf( stderr, "S_Init: default sfx volume %dn", sfxVolume);
  123.   numChannels = NUM_DSBUFFERS;
  124.   // Whatever these did with DMX, these are rather dummies now.
  125.   I_SetChannels();
  126.   
  127.   S_SetSfxVolume(sfxVolume);
  128.   // No music with Linux - another dummy.
  129.   S_SetMusicVolume(musicVolume);
  130.   // Allocating the internal channels for mixing
  131.   // (the maximum numer of sounds rendered
  132.   // simultaneously) within zone memory.
  133.   channels =
  134.     (channel_t *) Z_Malloc(numChannels*sizeof(channel_t), PU_STATIC, 0);
  135.   
  136.   // Free all channels for use
  137.   for (i=0 ; i<numChannels ; i++)
  138.     channels[i].sfxinfo = 0;
  139.   
  140.   // no sounds are playing, and they are not mus_paused
  141.   mus_paused = 0;
  142.   // Note that sounds have not been cached (yet).
  143.   for (i=1 ; i<NUMSFX ; i++)
  144.     S_sfx[i].lumpnum = S_sfx[i].usefulness = -1;
  145. }
  146. //
  147. // Per level startup code.
  148. // Kills playing sounds at start of level,
  149. //  determines music if any, changes music.
  150. //
  151. void S_Start(void)
  152. {
  153.   int cnum;
  154.   int mnum;
  155.   // kill all playing sounds at start of level
  156.   //  (trust me - a good idea)
  157.   for (cnum=0 ; cnum<numChannels ; cnum++)
  158.     if (channels[cnum].sfxinfo)
  159.       S_StopChannel(cnum);
  160.   
  161.   // start new music for the level
  162.   mus_paused = 0;
  163.   
  164.   if (gamemode == commercial)
  165.     mnum = mus_runnin + gamemap - 1;
  166.   else
  167.   {
  168.     int spmus[]=
  169.     {
  170.       // Song - Who? - Where?
  171.       
  172.       mus_e3m4, // American e4m1
  173.       mus_e3m2, // Romero e4m2
  174.       mus_e3m3, // Shawn e4m3
  175.       mus_e1m5, // American e4m4
  176.       mus_e2m7, // Tim  e4m5
  177.       mus_e2m4, // Romero e4m6
  178.       mus_e2m6, // J.Anderson e4m7 CHIRON.WAD
  179.       mus_e2m5, // Shawn e4m8
  180.       mus_e1m9 // Tim e4m9
  181.     };
  182.     
  183.     if (gameepisode < 4)
  184.       mnum = mus_e1m1 + (gameepisode-1)*9 + gamemap-1;
  185.     else
  186.       mnum = spmus[gamemap-1];
  187.     }
  188.   
  189.   // HACK FOR COMMERCIAL
  190.   //  if (commercial && mnum > mus_e3m9)
  191.   //      mnum -= mus_e3m9;
  192.   
  193.   S_ChangeMusic(mnum, true);
  194.   
  195.   nextcleanup = 15;
  196. }
  197. void S_StartSoundAtVolume( void *origin_p, int sfx_id, int volume )
  198.    {
  199.     int        rc;
  200.     int        sep;
  201.     int        pitch;
  202.     int        priority;
  203.     sfxinfo_t *sfx;
  204.     int        cnum;
  205.     int        chnum;
  206.   
  207.     mobj_t* origin = (mobj_t *)origin_p;
  208.   
  209.     //WriteDebug("S_StartSoundAtVolume...n");
  210.   
  211.     // Debug.
  212.     /*fprintf( stderr,"S_StartSoundAtVolume: playing sound %d (%s)n",sfx_id, S_sfx[sfx_id].name );*/
  213.   
  214.     // check for bogus sound #
  215.     if (sfx_id < 1 || sfx_id > NUMSFX)
  216.         I_Error("Bad sfx #: %d", sfx_id);
  217.   
  218.     sfx = &S_sfx[sfx_id];
  219.   
  220.     // Initialize sound parameters
  221.     if (sfx->link)
  222.        {
  223.         pitch = sfx->pitch;
  224.         priority = sfx->priority;
  225.         volume += sfx->volume;
  226.     
  227.         if (volume < 1)
  228.            {
  229.             //WriteDebug("Volume off...n");
  230.             return;
  231.            }
  232.     
  233.         if (volume > snd_SfxVolume)
  234.             volume = snd_SfxVolume;
  235.        }
  236.     else
  237.        {
  238.         pitch = NORM_PITCH;
  239.         priority = NORM_PRIORITY;
  240.        }
  241.     // Check to see if it is audible,
  242.     //  and if not, modify the params
  243.     if (origin && origin != players[consoleplayer].mo)
  244.        {
  245.         rc = S_AdjustSoundParams(players[consoleplayer].mo, origin, &volume, &sep, &pitch);
  246.         if ( origin->x == players[consoleplayer].mo->x && origin->y == players[consoleplayer].mo->y)
  247.            {
  248.             sep = NORM_SEP;
  249.            }
  250.         if (!rc)
  251.            {
  252.             //WriteDebug("No rc from S_AdjustSoundParams...n");
  253.             return;
  254.            }
  255.        }
  256.     else
  257.        {
  258.         sep = NORM_SEP;
  259.        }
  260.   
  261.     // hacks to vary the sfx pitches
  262.     if (sfx_id >= sfx_sawup && sfx_id <= sfx_sawhit)
  263.        {
  264.         pitch += 8 - (M_Random()&15);
  265.         if (pitch < 0)
  266.             pitch = 0;
  267.         else
  268.         if (pitch>255)
  269.             pitch = 255;
  270.        }
  271.     else
  272.     if (sfx_id != sfx_itemup && sfx_id != sfx_tink)
  273.        {
  274.         pitch += 16 - (M_Random()&31);
  275.         if (pitch<0)
  276.             pitch = 0;
  277.         else
  278.         if (pitch > 255)
  279.             pitch = 255;
  280.        }
  281.   // kill old sound
  282.   S_StopSound(origin);
  283. /*
  284.   // try to find a channel
  285.   cnum = S_getChannel(origin, sfx, sfx_id);
  286.   
  287.   if (cnum<0)
  288.      {
  289.         //WriteDebug("cnum < 0 -- no channel...n");
  290.     return;
  291.      }
  292. */
  293.   //
  294.   // This is supposed to handle the loading/caching.
  295.   // For some odd reason, the caching is done nearly
  296.   //  each time the sound is needed?
  297.   //
  298.   
  299.   // get lumpnum if necessary
  300.   if (sfx->lumpnum < 0)
  301.     sfx->lumpnum = I_GetSfxLumpNum(sfx);
  302. #ifndef SNDSRV
  303.   // cache data if necessary
  304.   if (!sfx->data)
  305.   {
  306.     fprintf( stderr,
  307.      "S_StartSoundAtVolume: 16bit and not pre-cached - wtf?n");
  308.     // DOS remains, 8bit handling
  309.     //sfx->data = (void *) W_CacheLumpNum(sfx->lumpnum, PU_MUSIC);
  310.     // fprintf( stderr,
  311.     //      "S_StartSoundAtVolume: loading %d (lump %d) : 0x%xn",
  312.     //       sfx_id, sfx->lumpnum, (int)sfx->data );
  313.     
  314.   }
  315. #endif
  316.   
  317.   // increase the usefulness
  318.   if (sfx->usefulness++ < 0)
  319.       sfx->usefulness = 1;
  320.   
  321.   // Assigns the handle to one of the channels in the
  322.   //  mix/output buffer.
  323.   //WriteDebug("I_StartSound...n");
  324.   //channels[cnum].handle = I_StartSound(sfx_id,/*sfx->data,*/volume,sep,pitch,priority,origin);
  325.   cnum = I_StartSound(sfx_id,/*sfx->data,*/volume,sep,pitch,priority,origin);
  326.   channels[cnum].handle = cnum;
  327.   channels[cnum].sfxinfo = sfx;
  328.   channels[cnum].origin = origin;
  329. }
  330. void S_StartSound( void *origin, int sfx_id )
  331.    {
  332. #ifdef SAWDEBUG
  333.     // if (sfx_id == sfx_sawful)
  334.     // sfx_id = sfx_itemup;
  335. #endif
  336.     S_StartSoundAtVolume(origin, sfx_id, snd_SfxVolume);
  337.     // UNUSED. We had problems, had we not?
  338. #ifdef SAWDEBUG
  339. {
  340.     int i;
  341.     int n;
  342.     static mobj_t*      last_saw_origins[10] = {1,1,1,1,1,1,1,1,1,1};
  343.     static int first_saw=0;
  344.     static int next_saw=0;
  345.     if (sfx_id == sfx_sawidl
  346. || sfx_id == sfx_sawful
  347. || sfx_id == sfx_sawhit)
  348.     {
  349. for (i=first_saw;i!=next_saw;i=(i+1)%10)
  350.     if (last_saw_origins[i] != origin)
  351. fprintf(stderr, "old origin 0x%lx != "
  352. "origin 0x%lx for sfx %dn",
  353. last_saw_origins[i],
  354. origin,
  355. sfx_id);
  356.     
  357. last_saw_origins[next_saw] = origin;
  358. next_saw = (next_saw + 1) % 10;
  359. if (next_saw == first_saw)
  360.     first_saw = (first_saw + 1) % 10;
  361.     
  362. for (n=i=0; i<numChannels ; i++)
  363. {
  364.     if (channels[i].sfxinfo == &S_sfx[sfx_sawidl]
  365. || channels[i].sfxinfo == &S_sfx[sfx_sawful]
  366. || channels[i].sfxinfo == &S_sfx[sfx_sawhit]) n++;
  367. }
  368.     
  369. if (n>1)
  370. {
  371.     for (i=0; i<numChannels ; i++)
  372.     {
  373. if (channels[i].sfxinfo == &S_sfx[sfx_sawidl]
  374.     || channels[i].sfxinfo == &S_sfx[sfx_sawful]
  375.     || channels[i].sfxinfo == &S_sfx[sfx_sawhit])
  376. {
  377.     fprintf(stderr,
  378.     "chn: sfxinfo=0x%lx, origin=0x%lx, "
  379.     "handle=%dn",
  380.     channels[i].sfxinfo,
  381.     channels[i].origin,
  382.     channels[i].handle);
  383. }
  384.     }
  385.     fprintf(stderr, "n");
  386. }
  387.     }
  388. }
  389. #endif
  390.  
  391. }
  392. void S_StopSound(void *origin)
  393. {
  394.     int cnum;
  395.     for (cnum=0 ; cnum<numChannels ; cnum++)
  396.     {
  397. if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
  398. {
  399.     S_StopChannel(cnum);
  400.     break;
  401. }
  402.     }
  403. }
  404. //
  405. // Stop and resume music, during game PAUSE.
  406. //
  407. void S_PauseSound(void)
  408. {
  409.     if (mus_playing && !mus_paused)
  410.     {
  411. I_PauseSong(mus_playing->handle);
  412. mus_paused = true;
  413.     }
  414. }
  415. void S_ResumeSound(void)
  416. {
  417.     if (mus_playing && mus_paused)
  418.     {
  419. I_ResumeSong(mus_playing->handle);
  420. mus_paused = false;
  421.     }
  422. }
  423. //
  424. // Updates music & sounds
  425. //
  426. void S_UpdateSounds(void* listener_p)
  427. {
  428.     int audible;
  429.     int cnum;
  430.     int volume;
  431.     int sep;
  432.     int pitch;
  433.     sfxinfo_t* sfx;
  434.     channel_t* c;
  435.     
  436.     mobj_t* listener = (mobj_t*)listener_p;
  437.     
  438.     // Clean up unused data.
  439.     // This is currently not done for 16bit (sounds cached static).
  440.     // DOS 8bit remains. 
  441.     /*if (gametic > nextcleanup)
  442.     {
  443. for (i=1 ; i<NUMSFX ; i++)
  444. {
  445.     if (S_sfx[i].usefulness < 1
  446. && S_sfx[i].usefulness > -1)
  447.     {
  448. if (--S_sfx[i].usefulness == -1)
  449. {
  450.     Z_ChangeTag(S_sfx[i].data, PU_CACHE);
  451.     S_sfx[i].data = 0;
  452. }
  453.     }
  454. }
  455. nextcleanup = gametic + 15;
  456.     }*/
  457.     
  458.     for (cnum=0 ; cnum<numChannels ; cnum++)
  459.     {
  460. c = &channels[cnum];
  461. sfx = c->sfxinfo;
  462. if (c->sfxinfo)
  463. {
  464.     if (I_SoundIsPlaying(c->handle))
  465.     {
  466. // initialize parameters
  467. volume = snd_SfxVolume;
  468. pitch = NORM_PITCH;
  469. sep = NORM_SEP;
  470. if (sfx->link)
  471. {
  472.     pitch = sfx->pitch;
  473.     volume += sfx->volume;
  474.     if (volume < 1)
  475.     {
  476. S_StopChannel(cnum);
  477. continue;
  478.     }
  479.     else if (volume > snd_SfxVolume)
  480.     {
  481. volume = snd_SfxVolume;
  482.     }
  483. }
  484. // check non-local sounds for distance clipping
  485. //  or modify their params
  486. if (c->origin && listener_p != c->origin)
  487. {
  488.     audible = S_AdjustSoundParams(listener,
  489.   c->origin,
  490.   &volume,
  491.   &sep,
  492.   &pitch);
  493.     
  494.     if (!audible)
  495.     {
  496. S_StopChannel(cnum);
  497.     }
  498.     else
  499. I_UpdateSoundParams(c->handle, volume, sep, pitch);
  500. }
  501.     }
  502.     else
  503.     {
  504. // if channel is allocated but sound has stopped,
  505. //  free it
  506. S_StopChannel(cnum);
  507.     }
  508. }
  509.     }
  510.     // kill music if it is a single-play && finished
  511.     // if ( mus_playing
  512.     //      && !I_QrySongPlaying(mus_playing->handle)
  513.     //      && !mus_paused )
  514.     // S_StopMusic();
  515. }
  516. void S_SetMusicVolume(int volume)
  517. {
  518.     if (volume < 0 || volume > 127)
  519.     {
  520. I_Error("Attempt to set music volume at %d",
  521. volume);
  522.     }    
  523.     I_SetMusicVolume(127);
  524.     I_SetMusicVolume(volume);
  525.     snd_MusicVolume = volume;
  526. }
  527. void S_SetSfxVolume(int volume)
  528. {
  529.     if (volume < 0 || volume > 127)
  530. I_Error("Attempt to set sfx volume at %d", volume);
  531.     snd_SfxVolume = volume;
  532. }
  533. //
  534. // Starts some music with the music id found in sounds.h.
  535. //
  536. void S_StartMusic(int m_id)
  537. {
  538.     S_ChangeMusic(m_id, false);
  539. }
  540. void
  541. S_ChangeMusic
  542. ( int musicnum,
  543.   int looping )
  544. {
  545.     musicinfo_t* music;
  546.     char namebuf[9];
  547.     if ( (musicnum <= mus_None)
  548.  || (musicnum >= NUMMUSIC) )
  549.     {
  550. I_Error("Bad music number %d", musicnum);
  551.     }
  552.     else
  553. music = &S_music[musicnum];
  554.     if (mus_playing == music)
  555. return;
  556.     // shutdown old music
  557.     S_StopMusic();
  558.     // get lumpnum if neccessary
  559.     if (!music->lumpnum)
  560.     {
  561. sprintf(namebuf, "d_%s", music->name);
  562. music->lumpnum = W_GetNumForName(namebuf);
  563.     }
  564.     // load & register it
  565.     music->data = (void *) W_CacheLumpNum(music->lumpnum, PU_MUSIC);
  566.     music->handle = I_RegisterSong(music->data);
  567.     // play it
  568.     I_PlaySong(music->handle, looping);
  569.     mus_playing = music;
  570. }
  571. void S_StopMusic(void)
  572. {
  573.     if (mus_playing)
  574.     {
  575. if (mus_paused)
  576.     I_ResumeSong(mus_playing->handle);
  577. I_StopSong(mus_playing->handle);
  578. I_UnRegisterSong(mus_playing->handle);
  579. Z_ChangeTag(mus_playing->data, PU_CACHE);
  580. mus_playing->data = 0;
  581. mus_playing = 0;
  582.     }
  583. }
  584. void S_StopChannel(int cnum)
  585. {
  586.     int i;
  587.     channel_t* c = &channels[cnum];
  588.     if (c->sfxinfo)
  589.     {
  590. // stop the sound playing
  591. if (I_SoundIsPlaying(c->handle))
  592. {
  593. #ifdef SAWDEBUG
  594.     if (c->sfxinfo == &S_sfx[sfx_sawful])
  595. fprintf(stderr, "stoppedn");
  596. #endif
  597.     I_StopSound(c->handle);
  598. }
  599. // check to see
  600. //  if other channels are playing the sound
  601. for (i=0 ; i<numChannels ; i++)
  602. {
  603.     if (cnum != i
  604. && c->sfxinfo == channels[i].sfxinfo)
  605.     {
  606. break;
  607.     }
  608. }
  609. // degrade usefulness of sound data
  610. c->sfxinfo->usefulness--;
  611. c->sfxinfo = 0;
  612.     }
  613. }
  614. //
  615. // Changes volume, stereo-separation, and pitch variables
  616. //  from the norm of a sound effect to be played.
  617. // If the sound is not audible, returns a 0.
  618. // Otherwise, modifies parameters and returns 1.
  619. //
  620. int
  621. S_AdjustSoundParams
  622. ( mobj_t* listener,
  623.   mobj_t* source,
  624.   int* vol,
  625.   int* sep,
  626.   int* pitch )
  627. {
  628.     fixed_t approx_dist;
  629.     fixed_t adx;
  630.     fixed_t ady;
  631.     angle_t angle;
  632.     // calculate the distance to sound origin
  633.     //  and clip it if necessary
  634.     adx = abs(listener->x - source->x);
  635.     ady = abs(listener->y - source->y);
  636.     // From _GG1_ p.428. Appox. eucledian distance fast.
  637.     approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1);
  638.     
  639.     if (gamemap != 8
  640. && approx_dist > S_CLIPPING_DIST)
  641.     {
  642. return 0;
  643.     }
  644.     
  645.     // angle of source to listener
  646.     angle = R_PointToAngle2(listener->x,
  647.     listener->y,
  648.     source->x,
  649.     source->y);
  650.     if (angle > listener->angle)
  651. angle = angle - listener->angle;
  652.     else
  653. angle = angle + (0xffffffff - listener->angle);
  654.     angle >>= ANGLETOFINESHIFT;
  655.     // stereo separation
  656.     *sep = 128 - (FixedMul(S_STEREO_SWING,finesine[angle])>>FRACBITS);
  657.     // volume calculation
  658.     if (approx_dist < S_CLOSE_DIST)
  659.     {
  660. *vol = snd_SfxVolume;
  661.     }
  662.     else if (gamemap == 8)
  663.     {
  664. if (approx_dist > S_CLIPPING_DIST)
  665.     approx_dist = S_CLIPPING_DIST;
  666. *vol = 15+ ((snd_SfxVolume-15)
  667.     *((S_CLIPPING_DIST - approx_dist)>>FRACBITS))
  668.     / S_ATTENUATOR;
  669.     }
  670.     else
  671.     {
  672. // distance effect
  673. *vol = (snd_SfxVolume
  674. * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS))
  675.     / S_ATTENUATOR; 
  676.     }
  677.     
  678.     return (*vol > 0);
  679. }
  680. //
  681. // S_getChannel :
  682. //   If none available, return -1.  Otherwise channel #.
  683. //
  684. int S_getChannel( void *origin, sfxinfo_t *sfxinfo, int sfxid )
  685.    {
  686.     // channel number to use
  687.     int cnum;
  688.         
  689.     channel_t* c;
  690.     // Find an open channel
  691.     //for (cnum = 0; cnum < numChannels; cnum++)
  692.     for (cnum = 0; cnum < NUM_DSBUFFERS; cnum++)
  693.        {
  694.         if (!channels[cnum].sfxinfo)
  695.             break;
  696.         else
  697.         if (origin && channels[cnum].origin == origin)
  698.            {
  699.             S_StopChannel(cnum);
  700.             break;
  701.            }
  702.        }
  703.     // None available
  704.     if (cnum == NUM_DSBUFFERS)
  705.        {
  706.         // Look for lower priority
  707.         for (cnum = NUMSFX; cnum < NUM_DSBUFFERS; cnum++)
  708.              if (channels[cnum].sfxinfo->priority >= sfxinfo->priority)
  709.                  break;
  710.         if (cnum == numChannels)
  711.            {
  712.             // FUCK!  No lower priority.  Sorry, Charlie.    
  713.             return -1;
  714.            }
  715.         else
  716.            {
  717.             // Otherwise, kick out lower priority.
  718.             S_StopChannel(cnum);
  719.            }
  720.        }
  721.     c = &channels[cnum];
  722.     // channel is decided to be cnum.
  723.     c->sfxinfo = sfxinfo;
  724.     c->origin = origin;
  725.     return cnum;
  726.    }