1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: s_sound.c 1422 2019-01-29 08:05:39Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 1998-2016 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 //
20 // $Log: s_sound.c,v $
21 // Revision 1.33  2003/07/14 21:22:24  hurdler
22 // go RC1
23 //
24 // Revision 1.32  2003/07/13 13:16:15  hurdler
25 //
26 // Revision 1.31  2002/12/13 22:34:27  ssntails
27 // MP3/OGG support!
28 //
29 // Revision 1.30  2002/09/19 21:47:05  judgecutor
30 //
31 // Revision 1.29  2002/09/12 20:10:51  hurdler
32 // Added some cvars
33 //
34 // Revision 1.28  2002/08/16 20:19:36  judgecutor
35 // Sound pitching coming back
36 //
37 // Revision 1.27  2001/08/20 20:40:39  metzgermeister
38 // Revision 1.26  2001/05/27 13:42:48  bpereira
39 //
40 // Revision 1.25  2001/04/30 17:19:24  stroggonmeth
41 // HW fix and misc. changes
42 //
43 // Revision 1.24  2001/04/18 19:32:26  hurdler
44 //
45 // Revision 1.23  2001/04/17 22:26:07  calumr
46 // Initial Mac add
47 //
48 // Revision 1.22  2001/04/04 20:24:21  judgecutor
49 // Added support for the 3D Sound
50 //
51 // Revision 1.21  2001/04/02 18:54:32  bpereira
52 // Revision 1.20  2001/04/01 17:35:07  bpereira
53 // Revision 1.19  2001/03/03 11:11:49  hurdler
54 // Revision 1.18  2001/02/24 13:35:21  bpereira
55 // Revision 1.17  2001/01/27 11:02:36  bpereira
56 //
57 // Revision 1.16  2001/01/25 22:15:44  bpereira
58 // added heretic support
59 //
60 // Revision 1.15  2000/11/21 21:13:18  stroggonmeth
61 // Optimised 3D floors and fixed crashing bug in high resolutions.
62 //
63 // Revision 1.14  2000/11/12 21:59:53  hurdler
64 // Please verify that sound bug
65 //
66 // Revision 1.13  2000/11/03 11:48:40  hurdler
67 // Fix compiling problem under win32 with 3D-Floors and FragglScript (to verify!)
68 //
69 // Revision 1.12  2000/11/02 17:50:10  stroggonmeth
70 // Big 3Dfloors & FraggleScript commit!!
71 //
72 // Revision 1.11  2000/10/27 20:38:20  judgecutor
73 // - Added the SurroundSound support
74 //
75 // Revision 1.10  2000/09/28 20:57:18  bpereira
76 // Revision 1.9  2000/05/07 08:27:57  metzgermeister
77 //
78 // Revision 1.8  2000/04/22 16:16:50  emanne
79 // Correction de l'interface.
80 // Une erreur s'y �tait gliss�, d'o� un segfault si on compilait sans SDL.
81 //
82 // Revision 1.7  2000/04/21 08:23:47  emanne
83 // To have SDL working.
84 // qmus2mid.h: force include of qmus2mid_sdl.h when needed.
85 //
86 // Revision 1.6  2000/03/29 19:39:48  bpereira
87 //
88 // Revision 1.5  2000/03/22 18:51:08  metzgermeister
89 // introduced I_PauseCD() for Linux
90 //
91 // Revision 1.4  2000/03/12 23:21:10  linuxcub
92 // Added consvars which hold the filenames and arguments which will be used
93 // when running the soundserver and musicserver (under Linux). I hope I
94 // didn't break anything ... Erling Jacobsen, linuxcub@email.dk
95 //
96 // Revision 1.3  2000/03/06 15:13:08  hurdler
97 // Revision 1.2  2000/02/27 00:42:11  hurdler
98 // Revision 1.1.1.1  2000/02/22 20:32:32  hurdler
99 // Initial import into CVS (v1.29 pr3)
100 //
101 //
102 // DESCRIPTION:
103 //    Sound control
104 //
105 //-----------------------------------------------------------------------------
106 
107 #include "doomincl.h"
108 #include "doomstat.h"
109 #include "command.h"
110 #include "g_game.h"
111 #include "m_argv.h"
112 #include "r_main.h"     //R_PointToAngle2() used to calc stereo sep.
113 #include "r_things.h"   // for skins
114 #include "p_info.h"
115 
116 #include "i_sound.h"
117 #include "s_sound.h"
118 #include "qmus2mid.h"
119 #include "w_wad.h"
120 #include "z_zone.h"
121 #include "d_main.h"
122 
123 #include "m_random.h"
124 
125 // 3D Sound Interface
126 #include "hardware/hw3sound.h"
127 
128 
129 // commands for music and sound servers
130 #ifdef MUSSERV
131 consvar_t cv_musserver_cmd = { "musserver_cmd", "musserver", CV_SAVE };
132 consvar_t cv_musserver_arg = { "musserver_arg", "-t 20", CV_SAVE };
133 
CV_musserv_opt_OnChange(void)134 void CV_musserv_opt_OnChange( void )
135 {
136     I_SetMusicOption();
137 }
138 
139 CV_PossibleValue_t musserv_opt_cons_t[] = {
140    {0, "Default dev"},
141    {1, "Search 1"},
142    {2, "Search 2"},
143    {3, "Search 3"},
144    {4, "Midi"},
145    {5, "TiMidity"},
146    {6, "FluidSynth"},
147    {7, "Ext Midi"},
148    {8, "Synth"},
149    {9, "FM Synth"},
150    {10, "Awe32 Synth"},
151    {11, "Dev6"},
152    {12, "Dev7"},
153    {13, "Dev8"},
154    {14, "Dev9"},
155    {0, NULL}
156 };
157 
158 consvar_t cv_musserver_opt = { "musserver_opt", "Search 1", CV_SAVE | CV_CALL,
159              musserv_opt_cons_t, CV_musserv_opt_OnChange };
160 #endif
161 
162 #ifdef SNDSERV
163 consvar_t cv_sndserver_cmd = { "sndserver_cmd", "llsndserv", CV_SAVE };
164 consvar_t cv_sndserver_arg = { "sndserver_arg", "-quiet", CV_SAVE };
165 #endif
166 
167 
168 #ifdef MACOS_DI
169 // specific to macos directory
170 consvar_t play_mode = { "play_mode", "0", CV_SAVE, CV_byte };
171   // enum playmode_t (0..2)
172 #endif
173 
174 
175 // stereo reverse 1=true, 0=false
176 consvar_t cv_stereoreverse = { "stereoreverse", "0", CV_SAVE, CV_OnOff };
177 
178 // if true, all sounds are loaded at game startup
179 consvar_t cv_precachesound = { "precachesound", "0", CV_SAVE, CV_OnOff };
180 
181 CV_PossibleValue_t soundvolume_cons_t[] = { {0, "MIN"}, {31, "MAX"}, {0, NULL} };
182 
183 // actual general (maximum) sound & music volume, saved into the config
184 consvar_t cv_soundvolume = { "soundvolume", "15", CV_SAVE, soundvolume_cons_t };
185 consvar_t cv_musicvolume = { "musicvolume", "15", CV_SAVE, soundvolume_cons_t };
186 consvar_t cv_rndsoundpitch = { "rndsoundpitch", "Off", CV_SAVE, CV_OnOff };
187 
188 // number of channels available
189 static void SetChannelsNum(void);
190 consvar_t cv_numChannels = { "snd_channels", "16", CV_SAVE | CV_CALL, CV_byte, SetChannelsNum };
191 
192 #ifdef SURROUND_SOUND
193 consvar_t cv_surround = { "surround", "0", CV_SAVE, CV_OnOff };
194 #endif
195 
196 #define S_MAX_VOLUME            127
197 
198 // when to clip out sounds
199 // Does not fit the large outdoor areas.
200 // added 2-2-98 in 8 bit volume control (befort  (1200*0x10000))
201 // Is 1200 in Boom, 1600 in Heretic.
202 #define S_FAR_DIST         1200
203 
204 // Distance tp origin when sounds should be maxed out.
205 // This should relate to movement clipping resolution
206 // (see BLOCKMAP handling).
207 // Originally: (200*0x10000).
208 // Is 200 in Boom, 0 In Heretic.
209 // added 2-2-98 in 8 bit volume control (befort  (160*0x10000))
210 #define S_CLOSE_DIST        160
211 
212 // Adjustable by menu.
213 #define NORM_VOLUME             snd_MaxVolume
214 
215 #define NORM_PITCH              128
216 #define NORM_PRIORITY           64
217 
218 #define S_PITCH_PERTURB         1
219 #define S_STEREO_SWING          (96<<FRACBITS)
220 
221 
222 // percent attenuation from front to back
223 #define S_IFRACVOL              30
224 
225 typedef struct
226 {
227     // When empty, sfxinfo=NULL, priority=-0x3FFF.
228     // sound information (if null, channel avail.)
229     sfxinfo_t * sfxinfo;
230     const xyz_t * origin;    // origin of sound
231     int16_t   priority;  // Heretic style signed priority, adjusted for dist,
232     int       handle;    // handle of the sound being played
233 } channel_t;
234 
235 // The set of channels available.
236 // Number of channels is set by cv_numChannels
237 static channel_t *channels;
238 
239 // whether songs are mus_paused
240 static boolean mus_paused;
241 
242 // music currently being played
243 static musicinfo_t *mus_playing = NULL;
244 
245 // [WDJ] unused
246 #ifdef CLEANUP
247 static int nextcleanup;
248 #endif
249 
250 //
251 // Internals.
252 //
253 typedef struct {
254     int volume;
255     int sep;  // +/- 127, <0 is left, >0 is right
256     int pitch;
257     int dist; // integer part of sound distance
258 } sound_param_t;
259 
260 static
261 boolean S_AdjustSoundParams(const mobj_t * listener, const xyz_t * source,
262                             /*OUT*/ sound_param_t * sp );
263 
264 static void S_StopChannel(int cnum);
265 
266 
S_Register_SoundStuff(void)267 void S_Register_SoundStuff(void)
268 {
269     // Any cv_ with CV_SAVE needs to be registered, even if it is not used.
270     // Otherwise there will be error messages when config is loaded.
271     CV_RegisterVar(&cv_stereoreverse);
272     CV_RegisterVar(&cv_precachesound);
273 #ifdef SURROUND_SOUND
274     CV_RegisterVar(&cv_surround);
275 #endif
276 
277     if (dedicated)
278         return;
279 
280 #ifdef SNDSERV
281     CV_RegisterVar(&cv_sndserver_cmd);
282     CV_RegisterVar(&cv_sndserver_arg);
283 #endif
284 #ifdef MUSSERV
285     CV_RegisterVar(&cv_musserver_cmd);
286     CV_RegisterVar(&cv_musserver_arg);
287     CV_RegisterVar(&cv_musserver_opt);
288 #endif
289 
290 #if 0
291 //[WDJ]  disabled in 143beta_macosx
292 //[segabor]
293 #ifdef MACOS_DI        //mp3 playlist stuff
294 // specific to macos directory
295     {
296         int i;
297         for (i = 0; i < PLAYLIST_LENGTH; i++)
298         {
299             user_songs[i].name = malloc(7);
300             sprintf(user_songs[i].name, "song%i%i", i / 10, i % 10);
301             user_songs[i].defaultvalue = malloc(1);
302             *user_songs[i].defaultvalue = 0;
303             user_songs[i].flags = CV_SAVE;
304             user_songs[i].PossibleValue = NULL;
305             CV_RegisterVar(&user_songs[i]);
306         }
307         CV_RegisterVar(&play_mode);
308     }
309 #endif
310 #endif
311 }
312 
SetChannelsNum(void)313 static void SetChannelsNum(void)
314 {
315     int i;
316 
317     // Allocating the internal channels for mixing
318     // (the maximum number of sounds rendered
319     // simultaneously) within zone memory.
320     if (channels)
321         Z_Free(channels);
322 
323 #ifdef HW3SOUND
324     if (hws_mode != HWS_DEFAULT_MODE)
325     {
326         HW3S_SetSourcesNum();
327         return;
328     }
329 #endif
330     channels = (channel_t *) Z_Malloc(cv_numChannels.value * sizeof(channel_t), PU_STATIC, 0);
331 
332     // Free all channels for use
333     for (i = 0; i < cv_numChannels.value; i++)
334     {
335         channels[i].sfxinfo = NULL;
336         channels[i].origin = NULL;
337     }
338 
339 }
340 
S_InitRuntimeMusic()341 void S_InitRuntimeMusic()
342 {
343     int i;
344 
345     for (i = mus_firstfreeslot; i < mus_lastfreeslot; i++)
346         S_music[i].name = NULL;
347 }
348 
349 
350 // [WDJ] Common routine to handling sfx names and get the sound lump.
351 // Much easier to maintain here.
352 // Replace S_GetSfxLumpNum
353 // Called by I_GetSfx
S_GetSfxLump(sfxinfo_t * sfx)354 void S_GetSfxLump( sfxinfo_t * sfx )
355 {
356     char lmpname[20] = "\0\0\0\0\0\0\0\0";  // do not leave this to chance [WDJ]
357     byte * sfx_lump_data;
358     lumpnum_t  sfx_lumpnum;
359 
360     if (EN_heretic) {	// [WDJ] heretic names are different
361        sprintf(lmpname, "%s", sfx->name);
362     }else{
363        sprintf(lmpname, "ds%s", sfx->name);
364     }
365 
366     // Now, there is a severe problem with the sound handling,
367     // in it is not (yet/anymore) gamemode aware. That means, sounds from
368     // DOOM II will be requested even with DOOM shareware.
369     // The sound list is wired into sounds.c, which sets the external variable.
370     // I do not do runtime patches to that variable. Instead, we will use a
371     // default sound for replacement.
372 
373     if( ! VALID_LUMP( W_CheckNumForName(lmpname) ) )
374     {
375         // sound not found
376         // try plain name too (hth2.wad amb*)
377         if( VALID_LUMP( W_CheckNumForName(sfx->name) ) )
378         {
379             sfx_lumpnum = W_GetNumForName(sfx->name);
380             goto lump_found;
381         }
382 
383         if( verbose > 1 )
384             GenPrintf(EMSG_ver, "Sound missing: %s, Using default sound\n", lmpname);
385         // Heretic shareware: get many missing sound names at sound init,
386         // but not after game starts.  These come from list of sounds
387         // in sounds.c, but not all those are in the game.
388         if (EN_heretic)
389             sfx_lumpnum = W_GetNumForName("keyup");
390         else
391             sfx_lumpnum = W_GetNumForName("dspistol");
392     }
393     else
394     {
395         sfx_lumpnum = W_GetNumForName(lmpname);
396     }
397 
398  lump_found:
399     // if lump not found, W_GetNumForName would have done I_Error
400     sfx->lumpnum = sfx_lumpnum;
401 
402     // Get the sound data from the WAD, allocate lump
403     //  in zone memory.
404     sfx->length = W_LumpLength(sfx_lumpnum);
405     // Copy is necessary because lump may be used by multiple sfx.
406     // Free of shared lump would corrupt other sfx using it.
407     sfx_lump_data = W_CacheLumpNum(sfx_lumpnum, PU_SOUND);
408     sfx->data = Z_Malloc( sfx->length, PU_SOUND, 0 );
409     memcpy( sfx->data, sfx_lump_data, sfx->length );
410     Z_ChangeTag( sfx_lump_data, PU_CACHE );
411 
412     // sound data header format
413     // 0,1: 03
414     // 2,3: sample rate (11,2B)=11025, (56,22)=22050
415     // 4,5: number of samples
416     // 6,7: 00
417 
418     // caller must fix size and data ptr for the mixer
419 }
420 
421 
422 // [WDJ] Common routine to Get data for a sfx
S_GetSfx(sfxinfo_t * sfx)423 static void S_GetSfx( sfxinfo_t * sfx )
424 {
425     if ( sfx->name )
426     {
427 //        debug_Printf("cached sound %s\n", sfx->name);
428         if (sfx->link)
429         {
430             // NOTE: linked sounds use the link data at StartSound time
431             // Example is the chaingun sound linked to pistol.
432             if( ! sfx->link->data )
433                 I_GetSfx( sfx->link );
434             // Linked to previously loaded
435             sfx->data = sfx->link->data;
436             sfx->length = sfx->link->length;
437         }
438         else
439         {
440             // Load data from WAD file.
441             I_GetSfx( sfx );
442         }
443     }
444 }
445 
446 // [WDJ] Common routine to Free data for a sfx
S_FreeSfx(sfxinfo_t * sfx)447 void S_FreeSfx( sfxinfo_t * sfx )
448 {
449     if( sfx->link )  // do not free linked data
450     {
451         sfx->data = NULL;
452     }
453     else if( sfx->data )
454     {
455         I_FreeSfx( sfx );  // some must free their own buffers
456 
457         if( sfx->data )    // if not already free
458         {
459             Z_Free( sfx->data );
460             sfx->data = NULL;
461         }
462     }
463 }
464 
465 
466 //
467 // Initializes sound stuff, including volume
468 // Sets channels, SFX and music volume,
469 //  allocates channel buffer, sets S_sfx lookup.
470 //
S_Init(int sfxVolume,int musicVolume)471 void S_Init(int sfxVolume, int musicVolume)
472 {
473     sfxid_t i;
474 
475     if (dedicated)
476         return;
477 
478     //debug_Printf( "S_Init: default sfx volume %d\n", sfxVolume);
479 
480     S_SetSfxVolume(sfxVolume);
481     S_SetMusicVolume(musicVolume);
482 
483     SetChannelsNum();
484 
485     // no sounds are playing, and they are not mus_paused
486     mus_paused = false;
487 
488     // Note that sounds have not been cached (yet).
489     for (i = 1; i < NUMSFX; i++)
490     {
491         sfxinfo_t * sfx = & S_sfx[i];
492         sfx->usefulness = -1;    // for I_GetSfx()
493         sfx->lumpnum = NO_LUMP;
494         sfx->data = NULL;
495         sfx->length = 0;
496 #if 1
497         // [WDJ] Single Saw sound fix.
498         // SFX_saw marks some additional sounds that may need SFX_single.
499         // The need for these may be obsolete.
500         // Need to know the situation that required single saw sound.
501         if( sfx->flags & SFX_saw )
502            sfx->flags |= SFX_single;
503 #endif
504     }
505 
506     //
507     //  precache sounds if requested by cmdline, or cv_precachesound var true
508     //
509     if (!nosoundfx && (M_CheckParm("-precachesound") || cv_precachesound.value))
510     {
511         // Initialize external data (all sounds) at start, keep static.
512 //        GenPrintf(EMSG_info, "Loading sounds... ");
513         GenPrintf(EMSG_info, "Caching sound data (%d sfx)... ", NUMSFX);
514 
515         for (i = 1; i < NUMSFX; i++)
516         {
517             // NOTE: linked sounds use the link's data at StartSound time
518             if (S_sfx[i].name && !S_sfx[i].link)
519                 S_GetSfx( & S_sfx[i] );
520         }
521 
522         GenPrintf(EMSG_info, " pre-cached all sound data\n");
523     }
524 
525     S_InitRuntimeMusic();
526 }
527 
528 
529 //
530 // Per level startup code.
531 // Kills playing sounds at start of level,
532 //  determines music if any, changes music.
533 //
534 
535 //SoM: Stop all sounds, load level info, THEN start sounds.
S_Stop_LevelSound(void)536 void S_Stop_LevelSound(void)
537 {
538     int cnum;
539 
540 #ifdef HW3SOUND
541     if (hws_mode != HWS_DEFAULT_MODE)
542     {
543         HW3S_Stop_LevelSound();
544         return;
545     }
546 #endif
547 
548     // kill all playing sounds at start of level
549     //  (trust me - a good idea)
550     for (cnum = 0; cnum < cv_numChannels.value; cnum++)
551     {
552         S_StopChannel(cnum);  // has all tests needed
553     }
554 }
555 
556 // Called by P_SetupLevel.
S_Start_LevelSound(void)557 void S_Start_LevelSound(void)
558 {
559     int mnum;
560 
561     // start new music for the level
562     mus_paused = false;
563 
564     if (gamemode == doom2_commercial)
565         mnum = mus_runnin + gamemap - 1;
566     else if (gamemode == heretic)
567         mnum = mus_he1m1 + (gameepisode - 1) * 9 + gamemap - 1;
568     else
569     {
570         const int spmus[] = {
571             // Song - Who? - Where?
572 
573             mus_e3m4,   // American     e4m1
574             mus_e3m2,   // Romero       e4m2
575             mus_e3m3,   // Shawn        e4m3
576             mus_e1m5,   // American     e4m4
577             mus_e2m7,   // Tim  e4m5
578             mus_e2m4,   // Romero       e4m6
579             mus_e2m6,   // J.Anderson   e4m7 CHIRON.WAD
580             mus_e2m5,   // Shawn        e4m8
581             mus_e1m9    // Tim          e4m9
582         };
583 
584         if (gameepisode < 4)
585             mnum = mus_e1m1 + (gameepisode - 1) * 9 + gamemap - 1;
586         else
587             mnum = spmus[gamemap - 1];
588     }
589 
590     // HACK FOR COMMERCIAL
591     //  if (gamemode==doom2_commercial && mnum > mus_e3m9)
592     //      mnum -= mus_e3m9;
593 
594     if (info_music && *info_music)
595         S_ChangeMusicName(info_music, true);
596     else
597         S_ChangeMusic(mnum, true);
598 
599 #ifdef CLEANUP
600     nextcleanup = 15;
601 #endif
602 }
603 
604 
605 //
606 // S_get_channel :
607 //   Kill origin sounds, dependent upon sfx flags.
608 //   Reuse the channel, or find another channel.
609 //   Return channel number, if none available, return -1.
610 //
611 //  priority : Heretic style ascending signed priority adjusted for distance
S_get_channel(const xyz_t * origin,sfxinfo_t * sfxinfo,int16_t priority)612 static int S_get_channel(const xyz_t *origin, sfxinfo_t * sfxinfo,
613                          int16_t priority )
614 {
615     // [WDJ] Like PrBoom, separate channel for player tagged sfx
616     uint32_t kill_flags = (sfxinfo->flags & (SFX_player|SFX_saw)) | SFX_org_kill;
617     int16_t low_priority = priority;  // neg is lower priority
618     int pick_cnum = -1;
619     int chanlimit = sfxinfo->limit_channels; // 1..99
620     int cnum;  // channel number to use
621     channel_t * c;
622 
623     // Using the Heretic system, higher num is higher priority.
624     // Priority adjusted by dist.
625     //  pri *= ( 10 - (dist/160));
626 
627     // Find an open channel, or lowest priority
628     // Stop previous origin sound, so do not break from loop
629     // Done in one loop for efficiency
630     for (cnum = cv_numChannels.value-1; cnum >= 0 ; cnum--)
631     {
632         c = & channels[cnum];
633         // stop previous origin sound
634         if (origin && c->origin == origin)
635         {
636             if( ! c->sfxinfo )  goto reuse_cnum;  // empty
637             // reuse channel with same origin, flags, when SFX_org_kill
638             if((c->sfxinfo->flags & (SFX_player|SFX_saw|SFX_org_kill)) == kill_flags )
639                 goto reuse_cnum;
640         }
641         if (! c->sfxinfo)   // empty
642         {
643             pick_cnum = cnum;
644             low_priority = -0x3FFF;  // empty is already lowest priority
645             continue;
646         }
647         // Heretic style channel limits per sfx.
648         if (c->sfxinfo == sfxinfo)
649             chanlimit --;
650         // Find lowest priority ( neg is lowest ).
651         if (c->priority < low_priority)
652         {
653             pick_cnum = cnum;
654             low_priority = c->priority;
655         }
656     }
657 
658     // Heretic style channel limits.
659     if( chanlimit <= 0 )
660 #if 1
661         priority -= (NORM_PRIORITY/2);  // soft limit
662 #else
663         return -1;  // already at or over limit
664 #endif
665 
666     cnum = pick_cnum;
667     if( pick_cnum >= 0 )
668     {
669         if( low_priority == -0x3FFF )  // found empty
670             goto use_cnum;
671         if( priority >= low_priority )  // can replace this sound
672             goto reuse_cnum;
673     }
674     // No lower priority.  Sorry, Charlie.
675     return -1;
676 
677  reuse_cnum:
678     S_StopChannel(cnum);
679  use_cnum:
680     c = &channels[cnum];
681 
682     // channel is decided to be cnum.
683     c->sfxinfo = sfxinfo;
684     c->priority = priority;
685     c->origin = origin;
686 
687     return cnum;
688 }
689 
690 
691 // Does the sfx special case handling for all drivers.
692 // [WDJ] Due to special mobj tests that this has acquired, sectors were
693 // being cast as mobj and tested for fields they do not have.  Have split
694 // the sound origin parameter from the mobj attribute tests.
695 //  volume : 0..255
696 //  origin : x,y,z of the sector or mobj (saved, don't use temps)
697 //  mo : the origin mobj, for testing attributes
698 // Called by StartSound.
699 // Called by hardware S_StartAmbientSound.
700 static
S_StartSoundAtVolume(const xyz_t * origin,const mobj_t * mo,sfxid_t sfx_id,int volume,channel_type_t ct_type)701 void S_StartSoundAtVolume(const xyz_t *origin, const mobj_t * mo,
702                           sfxid_t sfx_id, int volume,
703                           channel_type_t ct_type )
704 {
705     sound_param_t sp1;
706     int priority;  // Heretic style signed priority, nominally -10 .. 2560.
707     sfxinfo_t * sfx;
708     int cnum;
709 
710     if (nosoundfx || (mo && mo->type == MT_SPIRIT))
711         goto done;
712 
713 #if 0
714     if( EN_heretic )
715     {
716         if( origin == NULL )
717             origin = & consoleplayer_ptr->mo->x;
718         // volume = (volume*(snd_MaxVolume+1)*8)>>7;
719     }
720 #endif
721 
722 #if 0
723     // Debug.
724     debug_Printf( "S_StartSoundAtVolume: playing sound %d (%s), volume = %i\n",
725                 sfx_id, S_sfx[sfx_id].name, volume );
726 #endif
727 
728 #ifdef PARANOIA
729     // check for bogus sound #
730     if (sfx_id < 1 || sfx_id > NUMSFX)
731     {
732         I_SoftError("Bad sfx #: %d\n", sfx_id);
733         goto done;
734     }
735 #endif
736 
737     sfx = &S_sfx[sfx_id];
738 //    priority = sfx->priority;  // Heretic
739 //    priority = NORM_PRIORITY;  // Boom
740     sp1.pitch = NORM_PITCH;
741     sp1.sep = 0;
742 
743     if( (sfx->skinsound >= 0) && mo && mo->skin )
744     {
745         // redirect player sound to the sound in the skin table
746         sfx_id = ((skin_t *) mo->skin)->soundsid[sfx->skinsound];
747         sfx = &S_sfx[sfx_id];
748     }
749 
750     // Initialize sound parameters
751     if (sfx->link)
752     {
753         if( sfx->link_mod > 0 )
754         {
755             // Doom only
756             // Only modifies pitch, and we don't even implement that.
757             // The only link entry had NORM_PRIORITY.
758             sp1.pitch = link_mods[sfx->link_mod].pitch;
759 //          priority = sfx->priority;  // Boom
760             volume += link_mods[sfx->link_mod].mod_volume;
761 #if 0
762             // There are no sfx link mods that would trigger this.
763             if (volume < 1)
764                 goto done;
765 #endif
766         }
767 
768         // added 2-2-98 SfxVolume is now the hardware volume, don't mix up
769         //    if (volume > SfxVolume)
770         //      volume = SfxVolume;
771 
772         // update reference from link, it may have been purged
773         sfx->data = sfx->link->data;
774         sfx->length = sfx->link->length;
775     }
776     else
777     {
778 //        pitch = NORM_PITCH;
779 //        priority = NORM_PRIORITY;  // Boom ignored the sfx priority.
780     }
781 
782     sp1.volume = volume;
783     sp1.dist = 0;
784     // Check to see if it is audible,
785     //  and if not, modify the params
786 
787     //added:16-01-98:changed consoleplayer to displayplayer
788     //[WDJ] added displayplayer2_ptr tests, stop segfaults
789     if( origin
790         && (mo != displayplayer_ptr->mo)
791         && !(cv_splitscreen.value && displayplayer2_ptr
792              && (mo == displayplayer2_ptr->mo) ) )
793     {
794         sound_param_t sp2 = sp1;  // must save before AdjustSound
795         boolean audible1, audible2;
796 
797         audible1 = S_AdjustSoundParams(displayplayer_ptr->mo, origin, &sp1);
798 
799         // sp1 has been adjusted for dist and angle, optional additional adjustments follow.
800         if (cv_splitscreen.value && displayplayer2_ptr)
801         {
802             // splitscreen sound for player2
803             audible2 = S_AdjustSoundParams(displayplayer2_ptr->mo, origin, &sp2);
804             if (!audible2)
805             {
806                 if (!audible1)
807                     goto done;
808             }
809             else if (!audible1 || (audible1 && (sp2.volume > sp1.volume)))
810             {
811                 sp1 = sp2;  // as heard by player 2
812                 if (origin->x == displayplayer2_ptr->mo->x
813                     && origin->y == displayplayer2_ptr->mo->y)
814                 {
815                     sp1.sep = 0;
816                 }
817             }
818         }
819         else if (!audible1)
820             goto done;
821 
822         if (origin->x == displayplayer_ptr->mo->x
823             && origin->y == displayplayer_ptr->mo->y)
824         {
825             sp1.sep = 0;
826         }
827     }
828     else
829     {
830         sp1.sep = 0;
831     }
832 
833     // hacks to vary the sfx pitches
834 
835     //added:16-02-98: removed by Fab, because it used M_Random() and it
836     //                was a big bug, and then it doesnt change anything
837     //                dont hear any diff. maybe I'll put it back later
838     //                but of course not using M_Random().
839     //added 16-08-02: added back by Judgecutor
840     //Sound pitching for both Doom and Heretic
841     if( cv_rndsoundpitch.EV )
842     {
843         if (EN_heretic)
844         {
845             // Heretic
846             sp1.pitch = 128 + (M_Random() & 7);
847             sp1.pitch -= (M_Random() & 7);
848         }
849         else
850         {
851             // From Boom
852             if (sfx_id >= sfx_sawup && sfx_id <= sfx_sawhit)
853                 sp1.pitch += 8 - (M_Random() & 15);
854             else if (sfx_id != sfx_itemup && sfx_id != sfx_tink)
855                 sp1.pitch += 16 - (M_Random() & 31);
856         }
857     }
858     else if( demoplayback )
859     {
860         M_Random(); M_Random();  // to keep demo sync
861     }
862 
863     if (sp1.pitch < 0)
864         sp1.pitch = NORM_PITCH;
865     if (sp1.pitch > 255)
866         sp1.pitch = 255;
867 
868     if( EN_heretic )
869     {
870         // Heretic highest priority is 256, lowest 1.
871         priority = sfx->priority * (10 - (sp1.dist/160) );
872     }
873     else
874     {
875         // [WDJ] Boom was using NORM_PRIORITY for everything, ignoring the
876         // sfx priority, but we have the Heretic system, so why not use it.
877         // Doom highest priority is 1, lowest is 256.
878         priority = 257 - sfx->priority;  // Convert to Heretic system.
879         // Because of wads with 100 monsters, mod for dist too.
880         priority -= NORM_PRIORITY * sp1.dist / S_FAR_DIST;
881     }
882 
883 #ifdef HW3SOUND
884     if (hws_mode != HWS_DEFAULT_MODE)
885     {
886         HW3S_I_StartSound(origin, NULL, ct_type, sfx_id, priority,
887                           sp1.volume, sp1.pitch, sp1.sep);
888         goto done;
889     };
890 #endif
891 
892     // Kill origin sound, reuse channel, or find a channel
893     // Dependent upon sfx flags
894     cnum = S_get_channel(origin, sfx, priority);
895     if (cnum < 0)
896         goto done;
897 
898     // cache data if necessary
899     // NOTE : set sfx->data NULL sfx->lump -1 to force a reload
900     if (!sfx->data)
901         S_GetSfx( sfx );  // handles linked sfx too
902 
903     // [WDJ] usefulness of a recent sound
904     if( sfx->usefulness < 10 )
905        sfx->usefulness = 10;  // min
906     else if( sfx->usefulness > 800 )
907        sfx->usefulness = 800;  // max
908     sfx->usefulness += 3;   // increasing
909 
910     // [WDJ] From PrBoom, wad dakills has zero length sounds
911     // (DSBSPWLK, DSBSPACT, DSSWTCHN, DSSWTCHX)
912     if (sfx->length <= 0)
913        goto done;
914 
915 #ifdef SURROUND_SOUND
916     // judgecutor:
917     // Avoid channel reverse if surround
918     if (cv_stereoreverse.value && sp1.sep < SURROUND_SEP )
919         sp1.sep = -sp1.sep;
920 #else
921     //added:11-04-98:
922     if (cv_stereoreverse.value)
923         sp1.sep = -sp1.sep;
924 #endif
925 
926 //    debug_Printf("stereo sep %d reverse %d\n", sp1.sep, cv_stereoreverse.value);
927 
928     // Returns a handle to a mixer/output channel.
929     channels[cnum].handle =
930       I_StartSound(sfx_id, sp1.volume, sp1.sep, sp1.pitch, priority);
931 done:
932     return;
933 }
934 
935 // Most sfx sounds are called through this interface.
936 //  origin : the position
937 //  mo : mobj for testing attributes
938 static inline
S_StartNormSound(const xyz_t * origin,const mobj_t * mo,sfxid_t sfx_id)939 void S_StartNormSound(const xyz_t * origin, const mobj_t * mo, sfxid_t sfx_id)
940 {
941     // the volume is handled 8 bits
942     S_StartSoundAtVolume(origin, mo, sfx_id, 255, CT_NORMAL);
943 }
944 
945 // Most plain sfx sounds are called through this interface.
S_StartSound(sfxid_t sfx_id)946 void S_StartSound( sfxid_t sfx_id )
947 {
948     S_StartNormSound( NULL, NULL, sfx_id );  // No origin
949 }
950 
951 // Most switch sounds are called through this interface.
S_StartXYZSound(const xyz_t * origin,sfxid_t sfx_id)952 void S_StartXYZSound(const xyz_t * origin, sfxid_t sfx_id)
953 {
954     S_StartNormSound( origin, NULL, sfx_id );  // No mobj
955 }
956 
957 // Most sector sfx sounds are called through this interface.
S_StartSecSound(const sector_t * sec,sfxid_t sfx_id)958 void S_StartSecSound(const sector_t *sec, sfxid_t sfx_id)
959 {
960     S_StartNormSound( &sec->soundorg, NULL, sfx_id );  // xyz_t *
961 }
962 
963 // Most Mobj sfx sounds are called through this interface.
S_StartObjSound(const mobj_t * mo,sfxid_t sfx_id)964 void S_StartObjSound(const mobj_t *mo, sfxid_t sfx_id)
965 {
966     // Requires that the x,y,z in an mobj_t be the same as xyz_t.
967     S_StartNormSound( (xyz_t*)&(mo->x), mo, sfx_id );  // xyz_t *
968 }
969 
S_StartAttackSound(const mobj_t * mo,sfxid_t sfx_id)970 void S_StartAttackSound(const mobj_t * mo, sfxid_t sfx_id)
971 {
972     S_StartSoundAtVolume( (xyz_t*)&(mo->x), mo, sfx_id, 255, CT_ATTACK);
973 }
974 
S_StartScreamSound(const mobj_t * mo,sfxid_t sfx_id)975 void S_StartScreamSound(const mobj_t * mo, sfxid_t sfx_id)
976 {
977     S_StartSoundAtVolume( (xyz_t*)&(mo->x), mo, sfx_id, 255, CT_SCREAM);
978 }
979 
S_StartAmbientSound(sfxid_t sfx_id,int volume)980 void S_StartAmbientSound(sfxid_t sfx_id, int volume)
981 {
982 #ifdef HW3SOUND
983     if (hws_mode != HWS_DEFAULT_MODE)
984     {
985         volume += 30;
986         if (volume > 255)
987             volume = 255;
988     }
989 #endif
990     S_StartSoundAtVolume(NULL, NULL, sfx_id, volume, CT_AMBIENT);
991 }
992 
993 //
994 // S_StartSoundName
995 //  origin : the position
996 //  mo : mobj for testing attributes
997 // Starts an general sound using the given name.
S_StartXYZSoundName(const xyz_t * origin,const mobj_t * mo,const char * soundname)998 void S_StartXYZSoundName(const xyz_t *origin, const mobj_t * mo,
999                          const char *soundname)
1000 {
1001     int sfxid;
1002 
1003     //Search existing sounds...
1004     for (sfxid = sfx_None + 1; sfxid < NUMSFX; sfxid++)
1005     {
1006         if (!S_sfx[sfxid].name)
1007             continue;
1008 
1009         if (!strcasecmp(S_sfx[sfxid].name, soundname))
1010             goto play_sfx;  // found name
1011     }
1012 
1013     // add soundname to S_sfx
1014     // [WDJ] S_AddSoundFx now handles search for free slot and remove
1015     // of least useful sfx when full.
1016     sfxid = S_AddSoundFx(soundname, 0);
1017 
1018  play_sfx:
1019     S_StartNormSound(origin, mo, sfxid);
1020 }
1021 
1022 
1023 static
S_StopXYZSound(const xyz_t * origin)1024 void S_StopXYZSound(const xyz_t *origin)
1025 {
1026     int cnum;
1027 
1028     // SoM: Sounds without origin can have multiple sources, they shouldn't
1029     // be stopped by new sounds.
1030     if (!origin)
1031         return;
1032 
1033 #ifdef HW3SOUND
1034     if (hws_mode != HWS_DEFAULT_MODE)
1035     {
1036         HW3S_StopSound(origin);
1037         return;
1038     }
1039 #endif
1040     for (cnum = 0; cnum < cv_numChannels.value; cnum++)
1041     {
1042         if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
1043         {
1044             if( (channels[cnum].sfxinfo->flags & SFX_org_kill) )
1045             {
1046                 S_StopChannel(cnum);
1047             }
1048         }
1049     }
1050 }
1051 
S_StopSecSound(const sector_t * sec)1052 void S_StopSecSound(const sector_t *sec)
1053 {
1054     S_StopXYZSound( &sec->soundorg );
1055 }
1056 
S_StopObjSound(const mobj_t * mo)1057 void S_StopObjSound(const mobj_t *mo)
1058 {
1059     S_StopXYZSound( (xyz_t*)&mo->x );
1060 }
1061 
1062 
1063 
1064 //
1065 // Stop and resume music, during game PAUSE.
1066 //
S_PauseSound(void)1067 void S_PauseSound(void)
1068 {
1069     if (mus_playing && !mus_paused)
1070     {
1071         I_PauseSong(mus_playing->handle);
1072         mus_paused = true;
1073     }
1074 
1075 #ifdef CDMUS
1076     // pause cd music
1077     I_PauseCD();
1078 #endif
1079 }
1080 
S_ResumeSound(void)1081 void S_ResumeSound(void)
1082 {
1083     if (mus_playing && mus_paused)
1084     {
1085         I_ResumeSong(mus_playing->handle);
1086         mus_paused = false;
1087     }
1088 
1089 #ifdef CDMUS
1090     // resume cd music
1091     I_ResumeCD();
1092 #endif
1093 }
1094 
1095 //
1096 // Updates music & sounds
1097 //
1098 
1099 // The volumes for the hardware and software mixers.
1100 // Range 0..31
1101 int mix_sfxvolume = 0;
1102 int mix_musicvolume = 0;
1103 
1104 // Called by D_DoomLoop upon tics.
S_UpdateSounds(void)1105 void S_UpdateSounds(void)
1106 {
1107     sound_param_t sp1;
1108     int cnum;
1109     sfxinfo_t *sfx;
1110     channel_t *c;
1111 
1112     mobj_t *listener = displayplayer_ptr->mo;
1113 
1114     if (dedicated)
1115         return;
1116 
1117     // Update sound/music volumes, if changed manually at console
1118     if (mix_sfxvolume != cv_soundvolume.value)
1119         S_SetSfxVolume(cv_soundvolume.value);
1120     if (mix_musicvolume != cv_musicvolume.value)
1121         S_SetMusicVolume(cv_musicvolume.value);
1122 
1123 #ifdef HW3SOUND
1124     if (hws_mode != HWS_DEFAULT_MODE)
1125     {
1126         HW3S_UpdateSources();
1127         return;
1128     }
1129 #endif
1130 
1131 #ifdef CLEANUP
1132        Clean up unused data.
1133        if (gametic > nextcleanup)
1134        {
1135        for (i=1 ; i<NUMSFX ; i++)
1136        {
1137        if (S_sfx[i].usefulness==0)
1138        {
1139        //S_sfx[i].usefulness--;
1140 
1141        // don't forget to unlock it !!!
1142        // __dmpi_unlock_....
1143        //Z_ChangeTag(S_sfx[i].data, PU_CACHE);
1144        //S_sfx[i].data = 0;
1145 
1146        CONS_Printf ("\2flushed sfx %.6s\n", S_sfx[i].name);
1147        }
1148        }
1149        nextcleanup = gametic + 15;
1150        }
1151 #endif
1152 
1153     for (cnum = 0; cnum < cv_numChannels.value; cnum++)
1154     {
1155         c = &channels[cnum];
1156         sfx = c->sfxinfo;
1157 
1158         if (c->sfxinfo)
1159         {
1160             if ( ! I_SoundIsPlaying(c->handle))
1161             {
1162                 // if channel is allocated but sound has stopped,
1163                 //  free it
1164                 S_StopChannel(cnum);
1165                 continue;
1166             }
1167 
1168             // Sound is still playing, adjust for player or source movement.
1169             // Initialize parameters
1170             sp1.volume = 255;   //8 bits internal volume precision
1171             sp1.pitch = NORM_PITCH;
1172             sp1.sep = 0;
1173 
1174             if (sfx->link)  // strange (BP)
1175             {
1176                 if( sfx->link_mod > 0 )
1177                 {
1178                     // Doom only
1179                     // Only modifies pitch, and we don't even implement that.
1180                     sp1.pitch = link_mods[sfx->link_mod].pitch;
1181                     sp1.volume += link_mods[sfx->link_mod].mod_volume;
1182 #if 0
1183                     // There are no sfx link mods that would trigger this.
1184                     if (sp1.volume < 1)
1185                     {
1186                         S_StopChannel(cnum);
1187                         continue;
1188                     }
1189 #endif
1190                 }
1191             }
1192 
1193             // check non-local sounds for distance clipping
1194             //  or modify their params
1195             if (c->origin
1196                 && (((xyz_t*)&listener->x) != c->origin)
1197                 && !(cv_splitscreen.value && displayplayer2_ptr
1198                      && (c->origin == (xyz_t*)&displayplayer2_ptr->mo->x) ) )
1199             {
1200                 sound_param_t sp2 = sp1;
1201                 boolean audible1, audible2;
1202 
1203                 audible1 = S_AdjustSoundParams(listener, c->origin, &sp1);
1204 
1205                 if (cv_splitscreen.value && displayplayer2_ptr)
1206                 {
1207                     // splitscreen sound for player2
1208                     audible2 = S_AdjustSoundParams(displayplayer2_ptr->mo, c->origin, &sp2);
1209                     if (audible2
1210                         && (!audible1 || (sp2.volume > sp1.volume)) )
1211                     {
1212                         audible1 = true;
1213                         sp1 = sp2;
1214                     }
1215                 }
1216 
1217                 if (!audible1)
1218                 {
1219                     S_StopChannel(cnum);
1220                     continue;
1221                 }
1222 
1223 #ifdef SURROUND_SOUND
1224                 // judgecutor:
1225                 // Avoid channel reverse if surround
1226                 if (cv_stereoreverse.value && sp1.sep < SURROUND_SEP )
1227                     sp1.sep = -sp1.sep;
1228 #else
1229                 if (cv_stereoreverse.value)
1230                     sp1.sep = -sp1.sep;
1231 #endif
1232                 I_UpdateSoundParams(c->handle, sp1.volume, sp1.sep, sp1.pitch);
1233             }
1234         }
1235     }
1236     // kill music if it is a single-play && finished
1237     // if (     mus_playing
1238     //      && !I_QrySongPlaying(mus_playing->handle)
1239     //      && !mus_paused )
1240     // S_StopMusic();
1241 
1242 }
1243 
1244 //  volume : volume control,  0..31
S_SetMusicVolume(int volume)1245 void S_SetMusicVolume(int volume)
1246 {
1247     if (volume < 0 || volume > 31)
1248     {
1249         GenPrintf( EMSG_warn, "musicvolume should be between 0-31\n");
1250         volume = ( volume < 0 ) ? 0 : 31;  // clamp
1251     }
1252 
1253     mix_musicvolume = volume;  // check for change of var
1254 
1255     I_SetMusicVolume(volume);
1256 
1257 #ifdef __DJGPP__
1258     I_SetMusicVolume(31);       //faB: this is a trick for buggy dos drivers.. I think.
1259 #endif
1260 }
1261 
1262 //  volume : volume control,  0..31
S_SetSfxVolume(int volume)1263 void S_SetSfxVolume(int volume)
1264 {
1265     if (volume < 0 || volume > 31)
1266     {
1267         GenPrintf( EMSG_warn, "sfxvolume should be between 0-31\n");
1268         volume = ( volume < 0 ) ? 0 : 31;  // clamp
1269     }
1270 
1271     mix_sfxvolume = volume; // check for change of var
1272 
1273 #ifdef HW3SOUND
1274     hws_mode == HWS_DEFAULT_MODE ? I_SetSfxVolume(volume) : HW3S_SetSfxVolume(volume & 31);
1275 #else
1276     // now hardware volume
1277     I_SetSfxVolume(volume);
1278 #endif
1279 
1280 }
1281 
1282 //
1283 // Starts some music with the music id found in sounds.h.
1284 //
S_StartMusic(int m_id)1285 void S_StartMusic(int m_id)
1286 {
1287     S_ChangeMusic(m_id, true);
1288 }
1289 
1290 //
1291 // S_ChangeMusicName
1292 // Changes music by name
1293 //   looping : non-zero if continuous looping of music
S_ChangeMusicName(const char * name,byte looping)1294 void S_ChangeMusicName( const char * name, byte looping)
1295 {
1296     int music;
1297 
1298     if (!strncmp(name, "-", 6))
1299     {
1300         S_StopMusic();
1301         return;
1302     }
1303 
1304     music = S_FindMusic(name);
1305 
1306     if (music > mus_None && music < NUMMUSIC)
1307         S_ChangeMusic(music, looping);
1308     else
1309     {
1310         GenPrintf(EMSG_warn, "Music not found: %s\n", name);
1311         S_StopMusic();  // stop music anyway
1312     }
1313 }
1314 
S_ChangeMusic(int music_num,byte looping)1315 void S_ChangeMusic(int music_num, byte looping)
1316 {
1317     musicinfo_t *music;
1318 
1319     if (dedicated)
1320         return;
1321 
1322     if (nomusic)
1323         return;
1324 
1325     if ((music_num <= mus_None) || (music_num >= NUMMUSIC))
1326     {
1327         GenPrintf(EMSG_error, "Bad music number %d\n", music_num);
1328         return;
1329     }
1330     else
1331         music = &S_music[music_num];
1332 
1333     if (mus_playing == music)
1334         return;
1335 
1336     // shutdown old music
1337     S_StopMusic();
1338 
1339     // get lumpnum if neccessary
1340     // Test of the music ever being looked up, not a test of VALID_LUMP.
1341     if( music->lumpnum == 0 )
1342     {
1343         if (EN_heretic)
1344             music->lumpnum = W_GetNumForName(music->name);
1345         else
1346             music->lumpnum = W_GetNumForName(va("d_%s", music->name));
1347     }
1348 #if 0
1349     // W_GetNumForName will I_Error instead of returning NO_LUMP.
1350     if( ! VALID_LUMP(music->lumpnum) )
1351         return;
1352 #endif
1353 
1354 #ifdef MUSSERV
1355     // Play song, with information for ports with music servers.
1356     music->data = NULL;
1357     music->handle = I_PlayServerSong( music->name, music->lumpnum, looping );
1358 #else
1359     // load & register it
1360     music->data = (void *) S_CacheMusicLump(music->lumpnum);
1361     music->handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum));
1362     // play it
1363     I_PlaySong(music->handle, looping);
1364 #endif
1365 
1366     mus_playing = music;
1367 }
1368 
1369 
S_StopMusic()1370 void S_StopMusic()
1371 {
1372     if (mus_playing)
1373     {
1374         if (mus_paused)
1375             I_ResumeSong(mus_playing->handle);
1376 
1377         I_StopSong(mus_playing->handle);
1378         I_UnRegisterSong(mus_playing->handle);
1379 #ifndef MUSSERV
1380         if( mus_playing->data )
1381             Z_ChangeTag(mus_playing->data, PU_CACHE);
1382         mus_playing->data = NULL;
1383 #endif
1384 
1385         mus_playing = NULL;
1386     }
1387 }
1388 
S_StopChannel(int cnum)1389 static void S_StopChannel(int cnum)
1390 {
1391     channel_t *c = &channels[cnum];
1392 
1393     if (c->sfxinfo)
1394     {
1395         // stop the sound playing
1396         if (I_SoundIsPlaying(c->handle))
1397         {
1398             I_StopSound(c->handle);
1399         }
1400 
1401 #if 0
1402 // [WDJ] Does nothing
1403         // check to see
1404         //  if other channels are playing the sound
1405         int i;
1406         for (i = 0; i < cv_numChannels.value; i++)
1407         {
1408             if (cnum != i && c->sfxinfo == channels[i].sfxinfo)
1409             {
1410                 break;
1411             }
1412         }
1413 #endif
1414 
1415 #ifdef CLEANUP
1416         // degrade usefulness of sound data
1417         c->sfxinfo->usefulness--;
1418 #endif
1419 
1420         if( (c->sfxinfo->flags & SFX_org_kill) == 0 )
1421            c->origin = NULL;  // do not reuse
1422         c->sfxinfo = NULL;
1423         c->priority = -0x3FFF;
1424     }
1425 }
1426 
1427 //
1428 // Changes volume, stereo-separation, and pitch variables
1429 //  from the norm of a sound effect to be played.
1430 // If the sound is not audible, returns a 0.
1431 // Otherwise, modifies parameters and returns 1.
1432 //
1433 //   sp : /*OUT*/ sep, volume, 0..255
1434 // Return true if the sound is audible.
1435 static
S_AdjustSoundParams(const mobj_t * listener,const xyz_t * source,sound_param_t * sp)1436 boolean S_AdjustSoundParams(const mobj_t * listener, const xyz_t * source,
1437                             /*OUT*/ sound_param_t * sp )
1438 {
1439     int approx_dist;  // integer part of dist
1440     fixed_t adx, ady;
1441     angle_t angle;
1442     int v;
1443 
1444     if( ! listener )  return 0;  // [WDJ] Stop splitscreen segfault.
1445 
1446     // calculate the distance to sound origin
1447     //  and clip it if necessary
1448     adx = abs(listener->x - source->x);
1449     ady = abs(listener->y - source->y);
1450 
1451     // From _GG1_ p.428. Appox. eucledian distance fast.
1452     approx_dist = (adx + ady - (((adx < ady)? adx : ady) >> 1)) >> FRACBITS;
1453     // [WDJ] Used everywhere coarsely, so pass integer part.
1454     sp->dist = approx_dist;
1455 
1456     // Original has MAP08 without sound clipping by distance
1457     // Boom    if(approx_dist > 1200)
1458     // Heretic if(approx_dist > 1600)
1459     // Vanilla Doom2: (gamemap != 8 && approx_dist > S_FAR_DIST)
1460     //   doom2 map 8 apparantly was a joke level.
1461     if ( approx_dist > S_FAR_DIST )
1462     {
1463         return false;  // not audible
1464     }
1465 
1466     // angle of source to listener
1467     angle = R_PointToAngle2(listener->x, listener->y, source->x, source->y);
1468 
1469     if (angle > listener->angle)
1470         angle = angle - listener->angle;
1471     else
1472         angle = angle + (0xffffffff - listener->angle);
1473 
1474 #ifdef SURROUND_SOUND
1475     // Produce a surround sound for angle from 105 till 255
1476     if (cv_surround.value
1477         && (angle > (ANG90 + (ANG45 / 3)) && angle < (ANG270 - (ANG45 / 3))))
1478         sp->sep = SURROUND_SEP;
1479     else
1480     {
1481 #endif
1482         // stereo separation, <0 is left
1483         sp->sep =  - (FixedMul(S_STEREO_SWING, sine_ANG(angle)) >> FRACBITS);
1484 
1485 #ifdef SURROUND_SOUND
1486     }
1487 #endif
1488 
1489     // volume calculation
1490     // Multiplication by snd_SfxVolume has been moved to port drivers.
1491     // This generates a position relative volume, 0..255.
1492     if (approx_dist < S_CLOSE_DIST)
1493     {
1494         // added 2-2-98 SfxVolume is now hardware volume
1495         sp->volume = 255;     //snd_SfxVolume;
1496         return true;
1497     }
1498 
1499     // Original had MAP08 making distant sound effects louder than near.
1500     // removed hack here for gamemap==8 (it made far sound still present)
1501     if( EN_heretic )
1502     {
1503         // Heretic distance effect
1504         // Used sndmax: 0..31, default was 31.
1505         // Heretic  volume= (sndmax*16 + dist * (-sndmax*16)/MAX_SND_DIST) >> 9;
1506         //          volume= ((sndmax*16) - ((dist*sndmax*16)/MAX_SND_DIST)) >> 9;
1507         // Heretic has sndcurve lump:  volume= sndcurve[dist];
1508         v = ( (255*16) - ( (255*16*approx_dist) / S_FAR_DIST ) ) >> 4;
1509     }
1510     else
1511     {
1512         // Doom/Boom distance effect.
1513         // Used snd_SfxVolume: 0..15, default was 15.
1514         //  We use volume 0..255.
1515         // PrBoom: v = (snd_SfxVolume * ((S_FAR_DIST-approx_dist)>>FRACBITS)*8)
1516         //             / ((S_FAR_DIST-S_CLOSE_DIST)>>FRACBITS)
1517 #if 1
1518         v = (240 * (S_FAR_DIST - approx_dist)) / (S_FAR_DIST-S_CLOSE_DIST);
1519 #else
1520         // added 2-2-98 in 8 bit volume control (befort  remove the +4)
1521         // Range 0..240
1522         v = (15 * (S_FAR_DIST - approx_dist))
1523              / ((S_FAR_DIST-S_CLOSE_DIST)>>4);
1524 //#define S_ATTENUATOR   ((S_FAR_DIST-S_CLOSE_DIST)>>(FRACBITS+4))
1525 //      v = (15 * ((S_FAR_DIST - approx_dist) >> FRACBITS)) / S_ATTENUATOR;
1526 #endif
1527     }
1528 
1529     if( v > 255 )
1530     {
1531         v = 255;
1532         if( devparm )
1533             GenPrintf( EMSG_dev, "AdjustSound maxxed volume.\n" );
1534     }
1535     sp->volume = v;
1536 
1537     return (v > 0);
1538 }
1539 
1540 
1541 // SoM: Searches through the channels and checks for origin or id.
1542 //   origin : the origin position to check,  if NULL do not check it
1543 //   sfxid : the sfx to check,  if sfx_None do not check it
1544 // returns true if either is found.
1545 // Is called by S_AddSoundFx (with origin==NULL)
S_SoundPlaying(xyz_t * origin,sfxid_t sfxid)1546 boolean  S_SoundPlaying( xyz_t *origin, sfxid_t sfxid)
1547 {
1548     sfxinfo_t * sfx;
1549     int cnum;
1550 
1551 #ifdef HW3SOUND
1552     if (hws_mode != HWS_DEFAULT_MODE)
1553     {
1554         return HW3S_SoundPlaying(origin, id);
1555     }
1556 #endif
1557 
1558     // Enable match test when sfxid specified.
1559     sfx = ( sfxid == sfx_None )? NULL : & S_sfx[sfxid];
1560 
1561     for (cnum = 0; cnum < cv_numChannels.value; cnum++)
1562     {
1563         if (origin && channels[cnum].origin == origin)
1564             return 1;
1565 
1566         if ( sfx && (channels[cnum].sfxinfo == sfx) )
1567             return 1;
1568     }
1569     return 0;
1570 }
1571