1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
5 * PrBoom a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * DESCRIPTION: Platform-independent sound code
29 *-----------------------------------------------------------------------------*/
45 #include "rockmacros.h"
47 // when to clip out sounds
48 // Does not fit the large outdoor areas.
49 #define S_CLIPPING_DIST (1200<<FRACBITS)
51 // Distance tp origin when sounds should be maxed out.
52 // This should relate to movement clipping resolution
53 // (see BLOCKMAP handling).
54 // Originally: (200*0x10000).
56 #define S_CLOSE_DIST (160*0x10000)
57 #define S_ATTENUATOR ((S_CLIPPING_DIST-S_CLOSE_DIST)>>FRACBITS)
59 // Adjustable by menu.
60 #define NORM_PITCH 128
61 #define NORM_PRIORITY 64
63 #define S_STEREO_SWING (96<<FRACBITS)
67 sfxinfo_t
*sfxinfo
; // sound information (if null, channel avail.)
68 void *origin
; // origin of sound
69 int handle
; // handle of the sound being played
70 int is_pickup
; // killough 4/25/98: whether sound is a player's weapon
73 // the set of channels available
74 static channel_t
* channels
;
76 // These are not used, but should be (menu).
77 // Maximum volume of a sound effect.
78 // Internal default is max out of 0-15.
79 int snd_SfxVolume
= 15;
81 // Maximum volume of music. Useless so far.
82 int snd_MusicVolume
= 15;
84 // whether songs are mus_paused
85 static boolean mus_paused
;
87 // music currently being played
88 static musicinfo_t
* mus_playing
=0;
91 // by the defaults code in M_misc:
92 // number of channels available
93 int default_numChannels
;
96 //jff 3/17/98 to keep track of last IDMUS specified music num
103 void S_StopChannel(int cnum
);
105 int S_AdjustSoundParams(mobj_t
*listener
, mobj_t
*source
,
106 int *vol
, int *sep
, int *pitch
);
108 static int S_getChannel(void *origin
, sfxinfo_t
*sfxinfo
, int is_pickup
);
111 // Initializes sound stuff, including volume
112 // Sets channels, SFX and music volume,
113 // allocates channel buffer, sets S_sfx lookup.
116 void S_Init(int sfxVolume
,int musicVolume
)
118 //jff 1/22/98 skip sound init if sound not enabled
119 numChannels
= default_numChannels
;
124 printf("S_Init: default sfx volume %d\n", sfxVolume
);
126 // Whatever these did with DMX, these are rather dummies now.
129 S_SetSfxVolume(sfxVolume
);
131 S_SetMusicVolume(musicVolume
);
133 // Allocating the internal channels for mixing
134 // (the maximum numer of sounds rendered
135 // simultaneously) within zone memory.
137 channels
= (channel_t
*) calloc(numChannels
,sizeof(channel_t
));
139 // no sounds are playing, and they are not mus_paused
142 // Note that sounds have not been cached (yet).
143 for (i
=1 ; i
<NUMSFX
; i
++)
144 S_sfx
[i
].lumpnum
= S_sfx
[i
].usefulness
= -1;
149 // Per level startup code.
150 // Kills playing sounds at start of level,
151 // determines music if any, changes music.
159 // kill all playing sounds at start of level
160 // (trust me - a good idea)
161 for (cnum
=0 ; cnum
<numChannels
; cnum
++)
162 if (channels
[cnum
].sfxinfo
)
165 // start new music for the level
168 if (gamemode
== commercial
)
169 mnum
= mus_runnin
+ gamemap
- 1;
172 int spmus
[]= // Song - Who? - Where?
174 mus_e3m4
, // American e4m1
175 mus_e3m2
, // Romero e4m2
176 mus_e3m3
, // Shawn e4m3
177 mus_e1m5
, // American e4m4
178 mus_e2m7
, // Tim e4m5
179 mus_e2m4
, // Romero e4m6
180 mus_e2m6
, // J.Anderson e4m7 CHIRON.WAD
181 mus_e2m5
, // Shawn e4m8
186 mnum
= mus_e1m1
+ (gameepisode
-1)*9 + gamemap
-1;
188 mnum
= spmus
[gamemap
-1];
191 S_ChangeMusic(mnum
, true);
195 void S_StartSoundAtVolume(void *origin_p
, int sfx_id
, int volume
)
197 int sep
, pitch
, priority
, cnum
, is_pickup
;
199 mobj_t
* origin
= (mobj_t
*) origin_p
;
204 is_pickup
= sfx_id
& PICKUP_SOUND
|| sfx_id
== sfx_oof
|| (compatibility_level
>= prboom_2_compatibility
&& sfx_id
== sfx_noway
); // killough 4/25/98
205 sfx_id
&= ~PICKUP_SOUND
;
207 // check for bogus sound #
208 if (sfx_id
< 1 || sfx_id
> NUMSFX
)
209 I_Error("S_StartSoundAtVolume: Bad sfx #: %d", sfx_id
);
211 sfx
= &S_sfx
[sfx_id
];
213 // Initialize sound parameters
217 priority
= sfx
->priority
;
218 volume
+= sfx
->volume
;
223 if (volume
> snd_SfxVolume
)
224 volume
= snd_SfxVolume
;
229 priority
= NORM_PRIORITY
;
233 // Check to see if it is audible,
234 // and if not, modify the params
236 if (!origin
|| origin
== players
[displayplayer
].mo
) {
240 if (!S_AdjustSoundParams(players
[displayplayer
].mo
, origin
, &volume
,
244 if ( origin
->x
== players
[displayplayer
].mo
->x
&&
245 origin
->y
== players
[displayplayer
].mo
->y
)
248 // hacks to vary the sfx pitches
249 if (sfx_id
>= sfx_sawup
&& sfx_id
<= sfx_sawhit
)
250 pitch
+= 8 - (M_Random()&15);
252 if (sfx_id
!= sfx_itemup
&& sfx_id
!= sfx_tink
)
253 pitch
+= 16 - (M_Random()&31);
262 for (cnum
=0 ; cnum
<numChannels
; cnum
++)
263 if (channels
[cnum
].sfxinfo
&& channels
[cnum
].origin
== origin
&&
264 (comp
[comp_sound
] || channels
[cnum
].is_pickup
== is_pickup
))
270 // try to find a channel
271 cnum
= S_getChannel(origin
, sfx
, is_pickup
);
276 // get lumpnum if necessary
277 // killough 2/28/98: make missing sounds non-fatal
278 if (sfx
->lumpnum
< 0 && (sfx
->lumpnum
= I_GetSfxLumpNum(sfx
)) < 0)
281 // increase the usefulness
282 if (sfx
->usefulness
++ < 0)
285 // Assigns the handle to one of the channels in the mix/output buffer.
286 channels
[cnum
].handle
= I_StartSound(sfx_id
, cnum
, volume
, sep
, pitch
, priority
);
289 void S_StartSound(void *origin
, int sfx_id
)
291 S_StartSoundAtVolume(origin
, sfx_id
, snd_SfxVolume
);
294 void S_StopSound(void *origin
)
301 for (cnum
=0 ; cnum
<numChannels
; cnum
++)
302 if (channels
[cnum
].sfxinfo
&& channels
[cnum
].origin
== origin
)
310 // Stop and resume music, during game PAUSE.
312 void S_PauseSound(void)
317 if (mus_playing
&& !mus_paused
)
319 I_PauseSong(mus_playing
->handle
);
324 void S_ResumeSound(void)
329 if (mus_playing
&& mus_paused
)
331 I_ResumeSong(mus_playing
->handle
);
337 // Updates music & sounds
339 void S_UpdateSounds(void* listener_p
)
343 mobj_t
* listener
= (mobj_t
*)listener_p
;
348 for (cnum
=0 ; cnum
<numChannels
; cnum
++)
351 channel_t
* c
= &channels
[cnum
];
353 if ((sfx
= c
->sfxinfo
))
355 if (I_SoundIsPlaying(c
->handle
))
357 // initialize parameters
358 int volume
= snd_SfxVolume
;
359 int sep
= NORM_PITCH
;
360 int pitch
= NORM_SEP
;
365 volume
+= sfx
->volume
;
372 if (volume
> snd_SfxVolume
)
373 volume
= snd_SfxVolume
;
376 // check non-local sounds for distance clipping
377 // or modify their params
378 if (c
->origin
&& listener_p
!= c
->origin
) // killough 3/20/98
380 if (!S_AdjustSoundParams(listener
, c
->origin
,
381 &volume
, &sep
, &pitch
))
384 I_UpdateSoundParams(c
->handle
, volume
, sep
, pitch
);
393 void S_SetMusicVolume(int volume
)
398 if (volume
< 0 || volume
> 15)
399 I_Error("S_SetMusicVolume: Attempt to set music volume at %d", volume
);
400 I_SetMusicVolume(volume
);
401 snd_MusicVolume
= volume
;
404 void S_SetSfxVolume(int volume
)
409 if (volume
< 0 || volume
> 127)
410 I_Error("S_SetSfxVolume: Attempt to set sfx volume at %d", volume
);
411 snd_SfxVolume
= volume
;
415 // Starts some music with the music id found in sounds.h.
417 void S_StartMusic(int m_id
)
421 S_ChangeMusic(m_id
, false);
424 void S_ChangeMusic(int musicnum
, int looping
)
431 if (musicnum
<= mus_None
|| musicnum
>= NUMMUSIC
)
432 I_Error("S_ChangeMusic: Bad music number %d", musicnum
);
434 music
= &S_music
[musicnum
];
436 if (mus_playing
== music
)
439 // shutdown old music
442 // get lumpnum if neccessary
446 snprintf(namebuf
,sizeof(namebuf
),"d_%s", music
->name
);
447 music
->lumpnum
= W_GetNumForName(namebuf
);
450 // load & register it
451 music
->data
= W_CacheLumpNum(music
->lumpnum
);
452 // music->handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum));
454 // load & register it
455 // music->data = (void *) W_CacheLumpNum(music->lumpnum);
456 music
->handle
= I_RegisterSong(music
->data
);
459 I_PlaySong(music
->handle
, looping
);
465 void S_StopMusic(void)
473 I_ResumeSong(mus_playing
->handle
);
475 I_StopSong(mus_playing
->handle
);
476 I_UnRegisterSong(mus_playing
->handle
);
477 if (mus_playing
->lumpnum
>= 0)
478 W_UnlockLumpNum(mus_playing
->lumpnum
); // cph - release the music data
480 mus_playing
->data
= 0;
485 void S_StopChannel(int cnum
)
488 channel_t
* c
= &channels
[cnum
];
495 // stop the sound playing
496 if (I_SoundIsPlaying(c
->handle
))
497 I_StopSound(c
->handle
);
500 // if other channels are playing the sound
501 for (i
=0 ; i
<numChannels
; i
++)
502 if (cnum
!= i
&& c
->sfxinfo
== channels
[i
].sfxinfo
)
505 // degrade usefulness of sound data
506 c
->sfxinfo
->usefulness
--;
512 // Changes volume, stereo-separation, and pitch variables
513 // from the norm of a sound effect to be played.
514 // If the sound is not audible, returns a 0.
515 // Otherwise, modifies parameters and returns 1.
517 int S_AdjustSoundParams(mobj_t
*listener
, mobj_t
*source
,
518 int *vol
, int *sep
, int *pitch
)
521 fixed_t adx
, ady
, approx_dist
;
527 // calculate the distance to sound origin
528 // and clip it if necessary
529 adx
= D_abs(listener
->x
- source
->x
);
530 ady
= D_abs(listener
->y
- source
->y
);
532 // From _GG1_ p.428. Appox. eucledian distance fast.
533 approx_dist
= adx
+ ady
- ((adx
< ady
? adx
: ady
)>>1);
535 if (!approx_dist
) // killough 11/98: handle zero-distance as special case
538 *vol
= snd_SfxVolume
;
542 if (approx_dist
> S_CLIPPING_DIST
)
545 // angle of source to listener
546 angle
= R_PointToAngle2(listener
->x
, listener
->y
, source
->x
, source
->y
);
548 if (angle
<= listener
->angle
)
550 angle
-= listener
->angle
;
551 angle
>>= ANGLETOFINESHIFT
;
554 *sep
= 128 - (FixedMul(S_STEREO_SWING
,finesine
[angle
])>>FRACBITS
);
556 // volume calculation
557 if (approx_dist
< S_CLOSE_DIST
)
558 *vol
= snd_SfxVolume
*8;
561 *vol
= (snd_SfxVolume
* ((S_CLIPPING_DIST
-approx_dist
)>>FRACBITS
) * 8)
569 // If none available, return -1. Otherwise channel #.
571 // killough 4/25/98: made static, added is_pickup argument
573 static int S_getChannel(void *origin
, sfxinfo_t
*sfxinfo
, int is_pickup
)
575 // channel number to use
582 // Find an open channel
583 for (cnum
=0; cnum
<numChannels
&& channels
[cnum
].sfxinfo
; cnum
++)
584 if (origin
&& channels
[cnum
].origin
== origin
&&
585 channels
[cnum
].is_pickup
== is_pickup
)
592 if (cnum
== numChannels
)
593 { // Look for lower priority
594 for (cnum
=0 ; cnum
<numChannels
; cnum
++)
595 if (channels
[cnum
].sfxinfo
->priority
>= sfxinfo
->priority
)
597 if (cnum
== numChannels
)
598 return -1; // No lower priority. Sorry, Charlie.
600 S_StopChannel(cnum
); // Otherwise, kick out lower priority.
603 c
= &channels
[cnum
]; // channel is decided to be cnum.
604 c
->sfxinfo
= sfxinfo
;
606 c
->is_pickup
= is_pickup
; // killough 4/25/98