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
126 static int nextcleanup;
136 sfxinfo_t* sfxinfo );
147 void S_StopChannel(int cnum);
152 // Initializes sound stuff, including volume
153 // Sets channels, SFX and music volume,
154 // allocates channel buffer, sets S_sfx lookup.
162 fprintf( stderr, "S_Init: default sfx volume %d\n", sfxVolume);
164 // Whatever these did with DMX, these are rather dummies now.
167 S_SetSfxVolume(sfxVolume);
168 // No music with Linux - another dummy.
169 S_SetMusicVolume(musicVolume);
171 // Allocating the internal channels for mixing
172 // (the maximum numer of sounds rendered
173 // simultaneously) within zone memory.
175 (channel_t *) Z_Malloc(numChannels*sizeof(channel_t), PU_STATIC, 0);
177 // Free all channels for use
178 for (i=0 ; i<numChannels ; i++)
179 channels[i].sfxinfo = 0;
181 // no sounds are playing, and they are not mus_paused
184 // Note that sounds have not been cached (yet).
185 for (i=1 ; i<NUMSFX ; i++)
186 S_sfx[i].lumpnum = S_sfx[i].usefulness = -1;
193 // Per level startup code.
194 // Kills playing sounds at start of level,
195 // determines music if any, changes music.
202 // kill all playing sounds at start of level
203 // (trust me - a good idea)
204 for (cnum=0 ; cnum<numChannels ; cnum++)
205 if (channels[cnum].sfxinfo)
208 // start new music for the level
211 if (gamemode == commercial)
212 mnum = mus_runnin + gamemap - 1;
217 // Song - Who? - Where?
219 mus_e3m4, // American e4m1
220 mus_e3m2, // Romero e4m2
221 mus_e3m3, // Shawn e4m3
222 mus_e1m5, // American e4m4
223 mus_e2m7, // Tim e4m5
224 mus_e2m4, // Romero e4m6
225 mus_e2m6, // J.Anderson e4m7 CHIRON.WAD
226 mus_e2m5, // Shawn e4m8
231 mnum = mus_e1m1 + (gameepisode-1)*9 + gamemap-1;
233 mnum = spmus[gamemap-1];
236 // HACK FOR COMMERCIAL
237 // if (commercial && mnum > mus_e3m9)
240 S_ChangeMusic(mnum, true);
263 mobj_t* origin = (mobj_t *) origin_p;
268 "S_StartSoundAtVolume: playing sound %d (%s)\n",
269 sfx_id, S_sfx[sfx_id].name );*/
271 // check for bogus sound #
272 if (sfx_id < 1 || sfx_id > NUMSFX)
273 I_Error("Bad sfx #: %d", sfx_id);
275 sfx = &S_sfx[sfx_id];
277 // Initialize sound parameters
281 priority = sfx->priority;
282 volume += sfx->volume;
287 if (volume > snd_SfxVolume)
288 volume = snd_SfxVolume;
293 priority = NORM_PRIORITY;
297 // Check to see if it is audible,
298 // and if not, modify the params
299 if (origin && origin != players[consoleplayer].mo)
301 rc = S_AdjustSoundParams(players[consoleplayer].mo,
307 if ( origin->x == players[consoleplayer].mo->x
308 && origin->y == players[consoleplayer].mo->y)
321 // hacks to vary the sfx pitches
322 if (sfx_id >= sfx_sawup
323 && sfx_id <= sfx_sawhit)
325 pitch += 8 - (M_Random()&15);
332 else if (sfx_id != sfx_itemup
333 && sfx_id != sfx_tink)
335 pitch += 16 - (M_Random()&31);
346 // try to find a channel
347 cnum = S_getChannel(origin, sfx);
353 // This is supposed to handle the loading/caching.
354 // For some odd reason, the caching is done nearly
355 // each time the sound is needed?
358 // get lumpnum if necessary
359 if (sfx->lumpnum < 0)
360 sfx->lumpnum = I_GetSfxLumpNum(sfx);
363 // cache data if necessary
366 /* PORTME 9DOOM uncomment this back in later
368 "S_StartSoundAtVolume: 16bit and not pre-cached - wtf?\n");
371 // DOS remains, 8bit handling
372 //sfx->data = (void *) W_CacheLumpNum(sfx->lumpnum, PU_MUSIC);
374 // "S_StartSoundAtVolume: loading %d (lump %d) : 0x%x\n",
375 // sfx_id, sfx->lumpnum, (int)sfx->data );
380 // increase the usefulness
381 if (sfx->usefulness++ < 0)
384 // Assigns the handle to one of the channels in the
385 // mix/output buffer.
386 channels[cnum].handle = I_StartSound(sfx_id,
400 // if (sfx_id == sfx_sawful)
401 // sfx_id = sfx_itemup;
404 S_StartSoundAtVolume(origin, sfx_id, snd_SfxVolume);
407 // UNUSED. We had problems, had we not?
413 static mobj_t* last_saw_origins[10] = {1,1,1,1,1,1,1,1,1,1};
414 static int first_saw=0;
415 static int next_saw=0;
417 if (sfx_id == sfx_sawidl
418 || sfx_id == sfx_sawful
419 || sfx_id == sfx_sawhit)
421 for (i=first_saw;i!=next_saw;i=(i+1)%10)
422 if (last_saw_origins[i] != origin)
423 fprintf(stderr, "old origin 0x%lx != "
424 "origin 0x%lx for sfx %d\n",
429 last_saw_origins[next_saw] = origin;
430 next_saw = (next_saw + 1) % 10;
431 if (next_saw == first_saw)
432 first_saw = (first_saw + 1) % 10;
434 for (n=i=0; i<numChannels ; i++)
436 if (channels[i].sfxinfo == &S_sfx[sfx_sawidl]
437 || channels[i].sfxinfo == &S_sfx[sfx_sawful]
438 || channels[i].sfxinfo == &S_sfx[sfx_sawhit]) n++;
443 for (i=0; i<numChannels ; i++)
445 if (channels[i].sfxinfo == &S_sfx[sfx_sawidl]
446 || channels[i].sfxinfo == &S_sfx[sfx_sawful]
447 || channels[i].sfxinfo == &S_sfx[sfx_sawhit])
450 "chn: sfxinfo=0x%lx, origin=0x%lx, "
457 fprintf(stderr, "\n");
468 void S_StopSound(void *origin)
473 for (cnum=0 ; cnum<numChannels ; cnum++)
475 if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
492 // Stop and resume music, during game PAUSE.
494 void S_PauseSound(void)
496 if (mus_playing && !mus_paused)
498 I_PauseSong(mus_playing->handle);
503 void S_ResumeSound(void)
505 if (mus_playing && mus_paused)
507 I_ResumeSong(mus_playing->handle);
514 // Updates music & sounds
516 void S_UpdateSounds(void* listener_p)
526 mobj_t* listener = (mobj_t*)listener_p;
530 // Clean up unused data.
531 // This is currently not done for 16bit (sounds cached static).
533 /*if (gametic > nextcleanup)
535 for (i=1 ; i<NUMSFX ; i++)
537 if (S_sfx[i].usefulness < 1
538 && S_sfx[i].usefulness > -1)
540 if (--S_sfx[i].usefulness == -1)
542 Z_ChangeTag(S_sfx[i].data, PU_CACHE);
547 nextcleanup = gametic + 15;
550 for (cnum=0 ; cnum<numChannels ; cnum++)
557 if (I_SoundIsPlaying(c->handle))
559 // initialize parameters
560 volume = snd_SfxVolume;
567 volume += sfx->volume;
573 else if (volume > snd_SfxVolume)
575 volume = snd_SfxVolume;
579 // check non-local sounds for distance clipping
580 // or modify their params
581 if (c->origin && listener_p != c->origin)
583 audible = S_AdjustSoundParams(listener,
594 I_UpdateSoundParams(c->handle, volume, sep, pitch);
599 // if channel is allocated but sound has stopped,
605 // kill music if it is a single-play && finished
607 // && !I_QrySongPlaying(mus_playing->handle)
613 void S_SetMusicVolume(int volume)
615 if (volume < 0 || volume > 127)
617 I_Error("Attempt to set music volume at %d",
621 I_SetMusicVolume(127);
622 I_SetMusicVolume(volume);
623 snd_MusicVolume = volume;
628 void S_SetSfxVolume(int volume)
631 if (volume < 0 || volume > 127)
632 I_Error("Attempt to set sfx volume at %d", volume);
634 snd_SfxVolume = volume;
639 // Starts some music with the music id found in sounds.h.
641 void S_StartMusic(int m_id)
643 S_ChangeMusic(m_id, false);
654 if ( (musicnum <= mus_None)
655 || (musicnum >= NUMMUSIC) )
658 I_Error("Bad music number %d", musicnum);
661 music = &S_music[musicnum];
663 if (mus_playing == music)
666 // shutdown old music
669 // get lumpnum if neccessary
672 sprintf(namebuf, "d_%s", music->name);
673 music->lumpnum = W_GetNumForName(namebuf);
676 // load & register it
677 music->data = (void *) W_CacheLumpNum(music->lumpnum, PU_MUSIC);
678 music->handle = I_RegisterSong(music->data);
681 I_PlaySong(music->handle, looping);
687 void S_StopMusic(void)
692 I_ResumeSong(mus_playing->handle);
694 I_StopSong(mus_playing->handle);
695 I_UnRegisterSong(mus_playing->handle);
696 Z_ChangeTag(mus_playing->data, PU_CACHE);
698 mus_playing->data = 0;
706 void S_StopChannel(int cnum)
710 channel_t* c = &channels[cnum];
714 // stop the sound playing
715 if (I_SoundIsPlaying(c->handle))
718 if (c->sfxinfo == &S_sfx[sfx_sawful])
719 fprintf(stderr, "stopped\n");
721 I_StopSound(c->handle);
725 // if other channels are playing the sound
726 for (i=0 ; i<numChannels ; i++)
729 && c->sfxinfo == channels[i].sfxinfo)
735 // degrade usefulness of sound data
736 c->sfxinfo->usefulness--;
745 // Changes volume, stereo-separation, and pitch variables
746 // from the norm of a sound effect to be played.
747 // If the sound is not audible, returns a 0.
748 // Otherwise, modifies parameters and returns 1.
763 // calculate the distance to sound origin
764 // and clip it if necessary
765 adx = abs(listener->x - source->x);
766 ady = abs(listener->y - source->y);
768 // From _GG1_ p.428. Appox. eucledian distance fast.
769 approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1);
772 && approx_dist > S_CLIPPING_DIST)
777 // angle of source to listener
778 angle = R_PointToAngle2(listener->x,
783 if (angle > listener->angle)
784 angle = angle - listener->angle;
786 angle = angle + (0xffffffff - listener->angle);
788 angle >>= ANGLETOFINESHIFT;
791 *sep = 128 - (FixedMul(S_STEREO_SWING,finesine[angle])>>FRACBITS);
793 // volume calculation
794 if (approx_dist < S_CLOSE_DIST)
796 *vol = snd_SfxVolume;
798 else if (gamemap == 8)
800 if (approx_dist > S_CLIPPING_DIST)
801 approx_dist = S_CLIPPING_DIST;
803 *vol = 15+ ((snd_SfxVolume-15)
804 *((S_CLIPPING_DIST - approx_dist)>>FRACBITS))
810 *vol = (snd_SfxVolume
811 * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS))
823 // If none available, return -1. Otherwise channel #.
830 // channel number to use
835 // Find an open channel
836 for (cnum=0 ; cnum<numChannels ; cnum++)
838 if (!channels[cnum].sfxinfo)
840 else if (origin && channels[cnum].origin == origin)
848 if (cnum == numChannels)
850 // Look for lower priority
851 for (cnum=0 ; cnum<numChannels ; cnum++)
852 if (channels[cnum].sfxinfo->priority >= sfxinfo->priority) break;
854 if (cnum == numChannels)
856 // FUCK! No lower priority. Sorry, Charlie.
861 // Otherwise, kick out lower priority.
868 // channel is decided to be cnum.
869 c->sfxinfo = sfxinfo;