Skip to content

HTTPS clone URL

Subversion checkout URL

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