s_sound.c (8232B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #include "i_system.h" 5 #include "i_sound.h" 6 #include "sounds.h" 7 #include "s_sound.h" 8 #include "z_zone.h" 9 #include "m_random.h" 10 #include "w_wad.h" 11 #include "doomdef.h" 12 #include "p_local.h" 13 #include "doomstat.h" 14 15 const char snd_prefixen[] = { 'P', 'P', 'A', 'S', 'S', 'S', 'M', 'M', 'M', 'S', 'S', 'S' }; 16 17 #define S_MAX_VOLUME 127 18 #define S_CLIPPING_DIST (1200*0x10000) 19 #define S_CLOSE_DIST (160*0x10000) 20 #define S_ATTENUATOR ((S_CLIPPING_DIST-S_CLOSE_DIST)>>FRACBITS) 21 #define NORM_VOLUME snd_MaxVolume 22 #define NORM_PITCH 128 23 #define NORM_PRIORITY 64 24 #define NORM_SEP 128 25 #define S_PITCH_PERTURB 1 26 #define S_STEREO_SWING (96*0x10000) 27 #define S_IFRACVOL 30 28 #define NA 0 29 #define S_NUMCHANNELS 2 30 31 typedef struct { 32 sfxinfo_t* sfxinfo; 33 void* origin; 34 int handle; 35 } channel_t; 36 37 extern int snd_MusicDevice; 38 extern int snd_SfxDevice; 39 extern int snd_DesiredMusicDevice; 40 extern int snd_DesiredSfxDevice; 41 42 static channel_t* channels; 43 int snd_SfxVolume = 15; 44 int snd_MusicVolume = 15; 45 static boolean mus_paused; 46 static musicinfo_t* mus_playing=0; 47 int numChannels; 48 static int nextcleanup; 49 50 int 51 S_getChannel(void* origin, sfxinfo_t* sfxinfo); 52 53 int 54 S_AdjustSoundParams(mobj_t* listener, mobj_t* source, int* vol, int* sep, int* pitch); 55 void S_StopChannel(int cnum); 56 57 void 58 S_Init(int sfxVolume, int musicVolume) 59 { 60 int i; 61 62 fprintf(stderr, "S_Init: default sfx volume %d\n", sfxVolume); 63 I_SetChannels(); 64 S_SetSfxVolume(sfxVolume); 65 S_SetMusicVolume(musicVolume); 66 channels = (channel_t*)Z_Malloc(numChannels*sizeof(channel_t), PU_STATIC, 0); 67 for (i = 0; i < numChannels; ++i) 68 channels[i].sfxinfo = 0; 69 mus_paused = 0; 70 for (i = 1; i < NUMSFX; ++i) 71 S_sfx[i].lumpnum = S_sfx[i].usefulness = -1; 72 } 73 74 void 75 S_Start() 76 { 77 int cnum, mnum; 78 int spmus[] = { 79 mus_e3m4, 80 mus_e3m2, 81 mus_e3m3, 82 mus_e1m5, 83 mus_e2m7, 84 mus_e2m4, 85 mus_e2m6, 86 mus_e2m5, 87 mus_e1m9 88 }; 89 90 for (cnum = 0; cnum < numChannels; ++cnum) 91 if (channels[cnum].sfxinfo) 92 S_StopChannel(cnum); 93 mus_paused = 0; 94 if (gameepisode < 4) 95 mnum = mus_e1m1 + (gameepisode-1)*9 + gamemap-1; 96 else 97 mnum = spmus[gamemap-1]; 98 S_ChangeMusic(mnum, true); 99 nextcleanup = 15; 100 } 101 102 void 103 S_StartSoundAtVolume(void* origin_p, int sfx_id, int volume) 104 { 105 sfxinfo_t* sfx; 106 mobj_t* origin; 107 int rc, sep, pitch, priority, cnum; 108 origin = (mobj_t *) origin_p; 109 if (sfx_id < 1 || sfx_id > NUMSFX) 110 I_Error("Bad sfx #: %d", sfx_id); 111 sfx = &S_sfx[sfx_id]; 112 if (sfx->link) { 113 pitch = sfx->pitch; 114 priority = sfx->priority; 115 volume += sfx->volume; 116 if (volume < 1) 117 return; 118 if (volume > snd_SfxVolume) 119 volume = snd_SfxVolume; 120 } else { 121 pitch = NORM_PITCH; 122 priority = NORM_PRIORITY; 123 } 124 if (origin && origin != players[consoleplayer].mo) { 125 rc = S_AdjustSoundParams(players[consoleplayer].mo, origin, &volume, &sep, &pitch); 126 if (origin->x == players[consoleplayer].mo->x && origin->y == players[consoleplayer].mo->y) 127 sep = NORM_SEP; 128 if (!rc) 129 return; 130 } else sep = NORM_SEP; 131 if (sfx_id >= sfx_sawup && sfx_id <= sfx_sawhit) { 132 pitch += 8 - (M_Random()&15); 133 if (pitch<0) 134 pitch = 0; 135 if (pitch>255) 136 pitch = 255; 137 } 138 if (sfx_id != sfx_itemup && sfx_id != sfx_tink) { 139 pitch += 16 - (M_Random()&31); 140 if (pitch < 0) 141 pitch = 0; 142 if (pitch > 255) 143 pitch = 255; 144 } 145 S_StopSound(origin); 146 cnum = S_getChannel(origin, sfx); 147 if (cnum<0) return; 148 if (sfx->lumpnum < 0) sfx->lumpnum = I_GetSfxLumpNum(sfx); 149 if (!sfx->data) fprintf(stderr, "S_StartSoundAtVolume: 16bit and not pre-cached - wtf?\n"); 150 if (sfx->usefulness++ < 0) sfx->usefulness = 1; 151 channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority); 152 } 153 154 void 155 S_StartSound(void* origin, int sfx_id) 156 { 157 S_StartSoundAtVolume(origin, sfx_id, snd_SfxVolume); 158 } 159 160 void 161 S_StopSound(void *origin) 162 { 163 int cnum; 164 165 for (cnum = 0; cnum < numChannels; ++cnum) 166 if (channels[cnum].sfxinfo && channels[cnum].origin == origin) { 167 S_StopChannel(cnum); 168 break; 169 } 170 } 171 172 void 173 S_PauseSound() 174 { 175 if (mus_playing && !mus_paused) { 176 I_PauseSong(mus_playing->handle); 177 mus_paused = true; 178 } 179 } 180 181 void 182 S_ResumeSound() 183 { 184 if (mus_playing && mus_paused) { 185 I_ResumeSong(mus_playing->handle); 186 mus_paused = false; 187 } 188 } 189 190 void 191 S_UpdateSounds(void* listener_p) 192 { 193 sfxinfo_t* sfx; 194 channel_t* c; 195 mobj_t* listener; 196 int audible, cnum, volume, sep, pitch; 197 198 listener = (mobj_t*)listener_p; 199 for (cnum = 0; cnum < numChannels; ++cnum) { 200 c = &channels[cnum]; 201 sfx = c->sfxinfo; 202 if (c->sfxinfo) { 203 if (I_SoundIsPlaying(c->handle)) { 204 volume = snd_SfxVolume; 205 pitch = NORM_PITCH; 206 sep = NORM_SEP; 207 if (sfx->link) { 208 pitch = sfx->pitch; 209 volume += sfx->volume; 210 if (volume < 1) { 211 S_StopChannel(cnum); 212 continue; 213 } 214 if (volume > snd_SfxVolume) 215 volume = snd_SfxVolume; 216 } 217 if (c->origin && listener_p != c->origin) { 218 audible = S_AdjustSoundParams(listener, c->origin, &volume, &sep, &pitch); 219 if (!audible) 220 S_StopChannel(cnum); 221 else I_UpdateSoundParams(c->handle, volume, sep, pitch); 222 } 223 } 224 else S_StopChannel(cnum); 225 } 226 } 227 } 228 229 void 230 S_SetMusicVolume(int volume) 231 { 232 if (volume < 0 || volume > 127) 233 I_Error("Attempt to set music volume at %d", volume); 234 I_SetMusicVolume(127); 235 I_SetMusicVolume(volume); 236 snd_MusicVolume = volume; 237 } 238 239 void 240 S_SetSfxVolume(int volume) 241 { 242 if (volume < 0 || volume > 127) 243 I_Error("Attempt to set sfx volume at %d", volume); 244 snd_SfxVolume = volume; 245 } 246 247 void 248 S_StartMusic(int m_id) 249 { 250 S_ChangeMusic(m_id, false); 251 } 252 253 void 254 S_ChangeMusic(int musicnum, int looping) 255 { 256 musicinfo_t* music; 257 char namebuf[9]; 258 259 if ((musicnum <= mus_None) || (musicnum >= NUMMUSIC)) 260 I_Error("Bad music number %d", musicnum); 261 music = &S_music[musicnum]; 262 if (mus_playing == music) 263 return; 264 S_StopMusic(); 265 if (!music->lumpnum) { 266 sprintf(namebuf, "D_%s", music->name); 267 music->lumpnum = W_GetNumForName(namebuf); 268 } 269 music->data = (void *) W_CacheLumpNum(music->lumpnum, PU_MUSIC); 270 music->handle = I_RegisterSong(music->data); 271 I_PlaySong(music->handle, looping); 272 mus_playing = music; 273 } 274 275 void 276 S_StopMusic() 277 { 278 if (mus_playing) { 279 if (mus_paused) 280 I_ResumeSong(mus_playing->handle); 281 I_StopSong(mus_playing->handle); 282 I_UnRegisterSong(mus_playing->handle); 283 Z_ChangeTag(mus_playing->data, PU_CACHE); 284 mus_playing->data = 0; 285 mus_playing = 0; 286 } 287 } 288 289 void 290 S_StopChannel(int cnum) 291 { 292 channel_t* c; 293 int i; 294 295 c = &channels[cnum]; 296 if (c->sfxinfo) { 297 if (I_SoundIsPlaying(c->handle)) 298 I_StopSound(c->handle); 299 for (i = 0; i < numChannels; ++i) 300 if (cnum != i && c->sfxinfo == channels[i].sfxinfo) 301 break; 302 c->sfxinfo->usefulness--; 303 c->sfxinfo = 0; 304 } 305 } 306 307 int 308 S_AdjustSoundParams(mobj_t* listener, mobj_t* source, int* vol, int* sep, int* pitch) 309 { 310 fixed_t approx_dist, adx, ady; 311 angle_t angle; 312 313 adx = abs(listener->x - source->x); 314 ady = abs(listener->y - source->y); 315 approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1); 316 if (gamemap != 8 && approx_dist > S_CLIPPING_DIST) 317 return 0; 318 angle = R_PointToAngle2(listener->x, listener->y, source->x, source->y); 319 if (angle > listener->angle) 320 angle = angle - listener->angle; 321 else angle = angle + (0xffffffff - listener->angle); 322 angle >>= ANGLETOFINESHIFT; 323 *sep = 128 - (FixedMul(S_STEREO_SWING,finesine[angle])>>FRACBITS); 324 if (approx_dist < S_CLOSE_DIST) 325 *vol = snd_SfxVolume; 326 else if (gamemap == 8) { 327 if (approx_dist > S_CLIPPING_DIST) 328 approx_dist = S_CLIPPING_DIST; 329 *vol = 15+ ((snd_SfxVolume-15) * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) / S_ATTENUATOR; 330 } else *vol = (snd_SfxVolume * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) / S_ATTENUATOR; 331 return (*vol > 0); 332 } 333 334 int 335 S_getChannel(void* origin, sfxinfo_t* sfxinfo) 336 { 337 channel_t* c; 338 int cnum; 339 for (cnum = 0; cnum < numChannels; ++cnum) { 340 if (!channels[cnum].sfxinfo) 341 break; 342 if (origin && channels[cnum].origin == origin) { 343 S_StopChannel(cnum); 344 break; 345 } 346 } 347 if (cnum == numChannels) { 348 for (cnum = 0; cnum < numChannels; ++cnum) 349 if (channels[cnum].sfxinfo->priority >= sfxinfo->priority) 350 break; 351 if (cnum == numChannels) 352 return -1; 353 else S_StopChannel(cnum); 354 } 355 c = &channels[cnum]; 356 c->sfxinfo = sfxinfo; 357 c->origin = origin; 358 return cnum; 359 }