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