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