1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
6 // Copyright (C) 1993-1996 by id Software, Inc.
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.
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
21 //-----------------------------------------------------------------------------
25 rcsid[] = "$Id: s_sound.c,v 1.6 1997/02/03 22:45:12 b1 Exp $";
43 const char snd_prefixen[]
44 = { 'P', 'P', 'A', 'S', 'S', 'S', 'M', 'M', 'M', 'S', 'S', 'S' };
46 #define S_MAX_VOLUME 127
48 // when to clip out sounds
49 // Does not fit the large outdoor areas.
50 #define S_CLIPPING_DIST (1200*0x10000)
52 // Distance tp origin when sounds should be maxed out.
53 // This should relate to movement clipping resolution
54 // (see BLOCKMAP handling).
55 // Originally: (200*0x10000).
56 #define S_CLOSE_DIST (160*0x10000)
59 #define S_ATTENUATOR ((S_CLIPPING_DIST-S_CLOSE_DIST)>>FRACBITS)
61 // Adjustable by menu.
62 #define NORM_VOLUME snd_MaxVolume
64 #define NORM_PITCH 128
65 #define NORM_PRIORITY 64
68 #define S_PITCH_PERTURB 1
69 #define S_STEREO_SWING (96*0x10000)
71 // percent attenuation from front to back
75 #define S_NUMCHANNELS 2
78 // Current music/sfx card - index useless
79 // w/o a reference LUT in a sound module.
80 extern int snd_MusicDevice;
81 extern int snd_SfxDevice;
82 // Config file? Same disclaimer as above.
83 extern int snd_DesiredMusicDevice;
84 extern int snd_DesiredSfxDevice;
90 // sound information (if null, channel avail.)
96 // handle of the sound being played
102 // the set of channels available
103 static channel_t* channels;
105 // These are not used, but should be (menu).
106 // Maximum volume of a sound effect.
107 // Internal default is max out of 0-15.
108 int snd_SfxVolume = 15;
110 // Maximum volume of music. Useless so far.
111 int snd_MusicVolume = 15;
115 // whether songs are mus_paused
116 static boolean mus_paused;
118 // music currently being played
119 static musicinfo_t* mus_playing=0;
122 // by the defaults code in M_misc:
123 // number of channels available
132 sfxinfo_t* sfxinfo );
143 void S_StopChannel(int cnum);
148 // Initializes sound stuff, including volume
149 // Sets channels, SFX and music volume,
150 // allocates channel buffer, sets S_sfx lookup.
158 fprintf( stderr, "S_Init: default sfx volume %d\n", sfxVolume);
160 // Whatever these did with DMX, these are rather dummies now.
163 S_SetSfxVolume(sfxVolume);
164 // No music with Linux - another dummy.
165 S_SetMusicVolume(musicVolume);
167 // Allocating the internal channels for mixing
168 // (the maximum numer of sounds rendered
169 // simultaneously) within zone memory.
171 (channel_t *) Z_Malloc(numChannels*sizeof(channel_t), PU_STATIC, 0);
173 // Free all channels for use
174 for (i=0 ; i<numChannels ; i++)
175 channels[i].sfxinfo = 0;
177 // no sounds are playing, and they are not mus_paused
185 // Per level startup code.
186 // Kills playing sounds at start of level,
187 // determines music if any, changes music.
194 // kill all playing sounds at start of level
195 // (trust me - a good idea)
196 for (cnum=0 ; cnum<numChannels ; cnum++)
197 if (channels[cnum].sfxinfo)
200 // start new music for the level
203 if (gamemode == commercial)
204 mnum = mus_runnin + gamemap - 1;
209 // Song - Who? - Where?
211 mus_e3m4, // American e4m1
212 mus_e3m2, // Romero e4m2
213 mus_e3m3, // Shawn e4m3
214 mus_e1m5, // American e4m4
215 mus_e2m7, // Tim e4m5
216 mus_e2m4, // Romero e4m6
217 mus_e2m6, // J.Anderson e4m7 CHIRON.WAD
218 mus_e2m5, // Shawn e4m8
223 mnum = mus_e1m1 + (gameepisode-1)*9 + gamemap-1;
225 mnum = spmus[gamemap-1];
228 // HACK FOR COMMERCIAL
229 // if (commercial && mnum > mus_e3m9)
232 S_ChangeMusic(mnum, true);
253 mobj_t* origin = (mobj_t *) origin_p;
256 // check for bogus sound #
257 if (sfx_id < 1 || sfx_id > NUMSFX)
258 I_Error("Bad sfx #: %d", sfx_id);
260 sfx = &S_sfx[sfx_id];
262 // Initialize sound parameters
266 priority = sfx->priority;
267 volume += sfx->volume;
272 if (volume > snd_SfxVolume)
273 volume = snd_SfxVolume;
278 priority = NORM_PRIORITY;
282 // Check to see if it is audible,
283 // and if not, modify the params
284 if (origin && origin != players[consoleplayer].mo)
286 rc = S_AdjustSoundParams(players[consoleplayer].mo,
292 if ( origin->x == players[consoleplayer].mo->x
293 && origin->y == players[consoleplayer].mo->y)
306 // hacks to vary the sfx pitches
307 if (sfx_id >= sfx_sawup
308 && sfx_id <= sfx_sawhit)
310 pitch += 8 - (M_Random()&15);
317 else if (sfx_id != sfx_itemup
318 && sfx_id != sfx_tink)
320 pitch += 16 - (M_Random()&31);
331 // try to find a channel
332 cnum = S_getChannel(origin, sfx);
337 // Assigns the handle to one of the channels in the
338 // mix/output buffer.
339 channels[cnum].handle = I_StartSound(sfx_id,
352 // if (sfx_id == sfx_sawful)
353 // sfx_id = sfx_itemup;
356 S_StartSoundAtVolume(origin, sfx_id, snd_SfxVolume);
359 // UNUSED. We had problems, had we not?
365 static mobj_t* last_saw_origins[10] = {1,1,1,1,1,1,1,1,1,1};
366 static int first_saw=0;
367 static int next_saw=0;
369 if (sfx_id == sfx_sawidl
370 || sfx_id == sfx_sawful
371 || sfx_id == sfx_sawhit)
373 for (i=first_saw;i!=next_saw;i=(i+1)%10)
374 if (last_saw_origins[i] != origin)
375 fprintf(stderr, "old origin 0x%lx != "
376 "origin 0x%lx for sfx %d\n",
381 last_saw_origins[next_saw] = origin;
382 next_saw = (next_saw + 1) % 10;
383 if (next_saw == first_saw)
384 first_saw = (first_saw + 1) % 10;
386 for (n=i=0; i<numChannels ; i++)
388 if (channels[i].sfxinfo == &S_sfx[sfx_sawidl]
389 || channels[i].sfxinfo == &S_sfx[sfx_sawful]
390 || channels[i].sfxinfo == &S_sfx[sfx_sawhit]) n++;
395 for (i=0; i<numChannels ; i++)
397 if (channels[i].sfxinfo == &S_sfx[sfx_sawidl]
398 || channels[i].sfxinfo == &S_sfx[sfx_sawful]
399 || channels[i].sfxinfo == &S_sfx[sfx_sawhit])
402 "chn: sfxinfo=0x%lx, origin=0x%lx, "
409 fprintf(stderr, "\n");
420 void S_StopSound(void *origin)
425 for (cnum=0 ; cnum<numChannels ; cnum++)
427 if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
444 // Stop and resume music, during game PAUSE.
446 void S_PauseSound(void)
448 if (mus_playing && !mus_paused)
450 I_PauseSong(mus_playing->handle);
455 void S_ResumeSound(void)
457 if (mus_playing && mus_paused)
459 I_ResumeSong(mus_playing->handle);
466 // Updates music & sounds
468 void S_UpdateSounds(void* listener_p)
478 mobj_t* listener = (mobj_t*)listener_p;
480 for (cnum=0 ; cnum<numChannels ; cnum++)
487 if (I_SoundIsPlaying(c->handle))
489 // initialize parameters
490 volume = snd_SfxVolume;
497 volume += sfx->volume;
503 else if (volume > snd_SfxVolume)
505 volume = snd_SfxVolume;
509 // check non-local sounds for distance clipping
510 // or modify their params
511 if (c->origin && listener_p != c->origin)
513 audible = S_AdjustSoundParams(listener,
524 I_UpdateSoundParams(c->handle, volume, sep, pitch);
529 // if channel is allocated but sound has stopped,
535 // kill music if it is a single-play && finished
537 // && !I_QrySongPlaying(mus_playing->handle)
543 void S_SetMusicVolume(int volume)
545 if (volume < 0 || volume > 127)
547 I_Error("Attempt to set music volume at %d",
551 I_SetMusicVolume(127);
552 I_SetMusicVolume(volume);
553 snd_MusicVolume = volume;
558 void S_SetSfxVolume(int volume)
561 if (volume < 0 || volume > 127)
562 I_Error("Attempt to set sfx volume at %d", volume);
564 snd_SfxVolume = volume;
569 // Starts some music with the music id found in sounds.h.
571 void S_StartMusic(int m_id)
573 S_ChangeMusic(m_id, false);
584 if ( (musicnum <= mus_None)
585 || (musicnum >= NUMMUSIC) )
588 I_Error("Bad music number %d", musicnum);
591 music = &S_music[musicnum];
593 if (mus_playing == music)
596 // shutdown old music
599 // get lumpnum if neccessary
602 sprintf(namebuf, "d_%s", music->name);
603 music->lumpnum = W_GetNumForName(namebuf);
606 // load & register it
607 music->data = (void *) W_CacheLumpNum(music->lumpnum, PU_MUSIC);
608 music->handle = I_RegisterSong(music->data);
611 I_PlaySong(music->handle, looping);
617 void S_StopMusic(void)
622 I_ResumeSong(mus_playing->handle);
624 I_StopSong(mus_playing->handle);
625 I_UnRegisterSong(mus_playing->handle);
626 Z_ChangeTag(mus_playing->data, PU_CACHE);
628 mus_playing->data = 0;
636 void S_StopChannel(int cnum)
640 channel_t* c = &channels[cnum];
644 // stop the sound playing
645 if (I_SoundIsPlaying(c->handle))
648 if (c->sfxinfo == &S_sfx[sfx_sawful])
649 fprintf(stderr, "stopped\n");
651 I_StopSound(c->handle);
655 // if other channels are playing the sound
656 for (i=0 ; i<numChannels ; i++)
659 && c->sfxinfo == channels[i].sfxinfo)
672 // Changes volume, stereo-separation, and pitch variables
673 // from the norm of a sound effect to be played.
674 // If the sound is not audible, returns a 0.
675 // Otherwise, modifies parameters and returns 1.
690 // calculate the distance to sound origin
691 // and clip it if necessary
692 adx = abs(listener->x - source->x);
693 ady = abs(listener->y - source->y);
695 // From _GG1_ p.428. Appox. eucledian distance fast.
696 approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1);
699 && approx_dist > S_CLIPPING_DIST)
704 // angle of source to listener
705 angle = R_PointToAngle2(listener->x,
710 if (angle > listener->angle)
711 angle = angle - listener->angle;
713 angle = angle + (0xffffffff - listener->angle);
715 angle >>= ANGLETOFINESHIFT;
718 *sep = 128 - (FixedMul(S_STEREO_SWING,finesine[angle])>>FRACBITS);
720 // volume calculation
721 if (approx_dist < S_CLOSE_DIST)
723 *vol = snd_SfxVolume;
725 else if (gamemap == 8)
727 if (approx_dist > S_CLIPPING_DIST)
728 approx_dist = S_CLIPPING_DIST;
730 *vol = 15+ ((snd_SfxVolume-15)
731 *((S_CLIPPING_DIST - approx_dist)>>FRACBITS))
737 *vol = (snd_SfxVolume
738 * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS))
750 // If none available, return -1. Otherwise channel #.
757 // channel number to use
762 // Find an open channel
763 for (cnum=0 ; cnum<numChannels ; cnum++)
765 if (!channels[cnum].sfxinfo)
767 else if (origin && channels[cnum].origin == origin)
775 if (cnum == numChannels)
777 // Look for lower priority
778 for (cnum=0 ; cnum<numChannels ; cnum++)
779 if (channels[cnum].sfxinfo->priority >= sfxinfo->priority) break;
781 if (cnum == numChannels)
783 // FUCK! No lower priority. Sorry, Charlie.
788 // Otherwise, kick out lower priority.
795 // channel is decided to be cnum.
796 c->sfxinfo = sfxinfo;