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