1 /* Reduced from Doom's linuxdoom-1.10/s_sound.c, which is GPLv2 or later. */
2
3 /* { dg-additional-options "-fno-analyzer-call-summaries -Wno-analyzer-too-complex" } */
4
5 typedef struct _IO_FILE FILE;
6 extern FILE* stderr;
7 extern int
8 fprintf(FILE* __restrict __stream, const char* __restrict __format, ...);
9 extern int
10 sprintf(char* __restrict __s, const char* __restrict __format, ...)
11 __attribute__((__nothrow__));
12 extern int
13 abs(int __x) __attribute__((__nothrow__, __leaf__)) __attribute__((__const__));
14
15 typedef enum
16 {
17 false,
18 true
19 } boolean;
20
21 typedef unsigned char byte;
22
23 void
24 I_Error(char* error, ...);
25
26 typedef enum
27 {
28 shareware,
29 registered,
30 commercial,
31 /* [...snip...] */
32 } GameMode_t;
33
34 typedef int fixed_t;
35
36 fixed_t
37 FixedMul(fixed_t a, fixed_t b);
38
39 extern fixed_t finesine[5 * 8192 / 4];
40 typedef unsigned angle_t;
41
42 typedef struct mobj_s
43 {
44 /* [...snip...] */
45 fixed_t x;
46 fixed_t y;
47 fixed_t z;
48 /* [...snip...] */
49 angle_t angle;
50 /* [...snip...] */
51 } mobj_t;
52
53 typedef struct player_s
54 {
55 mobj_t* mo;
56 /* [...snip...] */
57 } player_t;
58
59 extern GameMode_t gamemode;
60 extern int gameepisode;
61 extern int gamemap;
62 extern int consoleplayer;
63 extern player_t players[4];
64
65 typedef struct sfxinfo_struct sfxinfo_t;
66
67 struct sfxinfo_struct
68 {
69 /* [...snip...] */
70 int priority;
71 sfxinfo_t* link;
72 int pitch;
73 int volume;
74 void* data;
75 int usefulness;
76 int lumpnum;
77 };
78
79 typedef struct
80 {
81 char* name;
82 int lumpnum;
83 void* data;
84 int handle;
85 } musicinfo_t;
86
87 extern sfxinfo_t S_sfx[];
88
89 extern musicinfo_t S_music[];
90
91 typedef enum
92 {
93 mus_None,
94 mus_e1m1,
95 /* [...snip...] */
96 mus_e1m5,
97 /* [...snip...] */
98 mus_e1m9,
99 /* [...snip...] */
100 mus_e2m4,
101 mus_e2m5,
102 mus_e2m6,
103 mus_e2m7,
104 /* [...snip...] */
105 mus_e3m2,
106 mus_e3m3,
107 mus_e3m4,
108 /* [...snip...] */
109 mus_runnin,
110 /* [...snip...] */
111 NUMMUSIC
112 } musicenum_t;
113
114 typedef enum
115 {
116 /* [...snip...] */
117 sfx_sawup,
118 /* [...snip...] */
119 sfx_sawhit,
120 /* [...snip...] */
121 sfx_itemup,
122 /* [...snip...] */
123 sfx_tink,
124 /* [...snip...] */
125 NUMSFX
126 } sfxenum_t;
127
128
129 void
130 I_SetChannels();
131
132 int
133 I_GetSfxLumpNum(sfxinfo_t* sfxinfo);
134
135 int
136 I_StartSound(int id, int vol, int sep, int pitch, int priority);
137
138 void
139 I_StopSound(int handle);
140 int
141 I_SoundIsPlaying(int handle);
142 void
143 I_UpdateSoundParams(int handle, int vol, int sep, int pitch);
144
145 void
146 I_SetMusicVolume(int volume);
147
148 void
149 I_PauseSong(int handle);
150 void
151 I_ResumeSong(int handle);
152 int
153 I_RegisterSong(void* data);
154
155 void
156 I_PlaySong(int handle, int looping);
157
158 void
159 I_StopSong(int handle);
160
161 void
162 I_UnRegisterSong(int handle);
163 void
164 S_StopSound(void* origin);
165 void
166 S_ChangeMusic(int music_id, int looping);
167 void
168 S_StopMusic(void);
169
170 void
171 S_SetMusicVolume(int volume);
172 void
173 S_SetSfxVolume(int volume);
174
175 void*
176 Z_Malloc(int size, int tag, void* ptr);
177 void
178 Z_ChangeTag2(void* ptr, int tag);
179
180 typedef struct memblock_s
181 {
182 /* [...snip...] */
183 int id;
184 /* [...snip...] */
185 } memblock_t;
186 int
187 M_Random(void);
188 int
189 W_GetNumForName(char* name);
190 void*
191 W_CacheLumpNum(int lump, int tag);
192 angle_t
193 R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2);
194
195 typedef struct
196 {
197 sfxinfo_t* sfxinfo;
198 void* origin;
199 int handle;
200 } channel_t;
201 static channel_t* channels;
202
203 int snd_SfxVolume = 15;
204 int snd_MusicVolume = 15;
205 static boolean mus_paused;
206 static musicinfo_t* mus_playing = 0;
207 int numChannels;
208 static int nextcleanup;
209
210 int
211 S_getChannel(void* origin, sfxinfo_t* sfxinfo);
212
213 int
214 S_AdjustSoundParams(mobj_t* listener,
215 mobj_t* source,
216 int* vol,
217 int* sep,
218 int* pitch);
219 void
220 S_StopChannel(int cnum);
221
222 void
223 S_Init(int sfxVolume, int musicVolume)
224 {
225 int i;
226
227 fprintf(stderr, "S_Init: default sfx volume %d\n", sfxVolume);
228
229 I_SetChannels();
230
231 S_SetSfxVolume(sfxVolume);
232
233 S_SetMusicVolume(musicVolume);
234
235 channels = (channel_t*)Z_Malloc(numChannels * sizeof(channel_t), 1, 0);
236
237 for (i = 0; i < numChannels; i++)
238 channels[i].sfxinfo = 0;
239
240 mus_paused = 0;
241
242 for (i = 1; i < NUMSFX; i++)
243 S_sfx[i].lumpnum = S_sfx[i].usefulness = -1;
244 }
245 void
246 S_Start(void)
247 {
248 int cnum;
249 int mnum;
250
251 for (cnum = 0; cnum < numChannels; cnum++)
252 if (channels[cnum].sfxinfo)
253 S_StopChannel(cnum);
254
255 mus_paused = 0;
256
257 if (gamemode == commercial)
258 mnum = mus_runnin + gamemap - 1;
259 else {
260 int spmus[] = {
261
262 mus_e3m4, mus_e3m2, mus_e3m3, mus_e1m5, mus_e2m7,
263 mus_e2m4, mus_e2m6, mus_e2m5, mus_e1m9
264 };
265
266 if (gameepisode < 4)
267 mnum = mus_e1m1 + (gameepisode - 1) * 9 + gamemap - 1;
268 else
269 mnum = spmus[gamemap - 1];
270 }
271
272 S_ChangeMusic(mnum, true);
273
274 nextcleanup = 15;
275 }
276
277 void
278 S_StartSoundAtVolume(void* origin_p, int sfx_id, int volume)
279 {
280
281 int rc;
282 int sep;
283 int pitch;
284 int priority;
285 sfxinfo_t* sfx;
286 int cnum;
287
288 mobj_t* origin = (mobj_t*)origin_p;
289 if (sfx_id < 1 || sfx_id > NUMSFX)
290 I_Error("Bad sfx #: %d", sfx_id);
291
292 sfx = &S_sfx[sfx_id];
293
294 if (sfx->link) {
295 pitch = sfx->pitch;
296 priority = sfx->priority;
297 volume += sfx->volume;
298
299 if (volume < 1)
300 return;
301
302 if (volume > snd_SfxVolume)
303 volume = snd_SfxVolume;
304 } else {
305 pitch = 128;
306 priority = 64;
307 }
308
309 if (origin && origin != players[consoleplayer].mo) {
310 rc = S_AdjustSoundParams(
311 players[consoleplayer].mo, origin, &volume, &sep, &pitch);
312
313 if (origin->x == players[consoleplayer].mo->x &&
314 origin->y == players[consoleplayer].mo->y) {
315 sep = 128;
316 }
317
318 if (!rc)
319 return;
320 } else {
321 sep = 128;
322 }
323
324 if (sfx_id >= sfx_sawup && sfx_id <= sfx_sawhit) {
325 pitch += 8 - (M_Random() & 15);
326
327 if (pitch < 0)
328 pitch = 0;
329 else if (pitch > 255)
330 pitch = 255;
331 } else if (sfx_id != sfx_itemup && sfx_id != sfx_tink) {
332 pitch += 16 - (M_Random() & 31);
333
334 if (pitch < 0)
335 pitch = 0;
336 else if (pitch > 255)
337 pitch = 255;
338 }
339
340 S_StopSound(origin);
341
342 cnum = S_getChannel(origin, sfx);
343
344 if (cnum < 0)
345 return;
346 if (sfx->lumpnum < 0)
347 sfx->lumpnum = I_GetSfxLumpNum(sfx);
348
349 if (!sfx->data) {
350 fprintf(stderr, "S_StartSoundAtVolume: 16bit and not pre-cached - wtf?\n");
351 }
352
353 if (sfx->usefulness++ < 0)
354 sfx->usefulness = 1;
355
356 channels[cnum].handle = I_StartSound(sfx_id,
357
358 volume,
359 sep,
360 pitch,
361 priority);
362 }
363
364 void
365 S_StartSound(void* origin, int sfx_id)
366 {
367
368 S_StartSoundAtVolume(origin, sfx_id, snd_SfxVolume);
369 }
370
371 void
372 S_StopSound(void* origin)
373 {
374
375 int cnum;
376
377 for (cnum = 0; cnum < numChannels; cnum++) {
378 if (channels[cnum].sfxinfo && channels[cnum].origin == origin) {
379 S_StopChannel(cnum);
380 break;
381 }
382 }
383 }
384 void
385 S_PauseSound(void)
386 {
387 if (mus_playing && !mus_paused) {
388 I_PauseSong(mus_playing->handle);
389 mus_paused = true;
390 }
391 }
392
393 void
394 S_ResumeSound(void)
395 {
396 if (mus_playing && mus_paused) {
397 I_ResumeSong(mus_playing->handle);
398 mus_paused = false;
399 }
400 }
401
402 void
403 S_UpdateSounds(void* listener_p)
404 {
405 int audible;
406 int cnum;
407 int volume;
408 int sep;
409 int pitch;
410 sfxinfo_t* sfx;
411 channel_t* c;
412
413 mobj_t* listener = (mobj_t*)listener_p;
414 for (cnum = 0; cnum < numChannels; cnum++) {
415 c = &channels[cnum];
416 sfx = c->sfxinfo;
417
418 if (c->sfxinfo) {
419 if (I_SoundIsPlaying(c->handle)) {
420
421 volume = snd_SfxVolume;
422 pitch = 128;
423 sep = 128;
424
425 if (sfx->link) {
426 pitch = sfx->pitch;
427 volume += sfx->volume;
428 if (volume < 1) {
429 S_StopChannel(cnum);
430 continue;
431 } else if (volume > snd_SfxVolume) {
432 volume = snd_SfxVolume;
433 }
434 }
435
436 if (c->origin && listener_p != c->origin) {
437 audible =
438 S_AdjustSoundParams(listener, c->origin, &volume, &sep, &pitch);
439
440 if (!audible) {
441 S_StopChannel(cnum);
442 } else
443 I_UpdateSoundParams(c->handle, volume, sep, pitch);
444 }
445 } else {
446
447 S_StopChannel(cnum);
448 }
449 }
450 }
451 }
452
453 void
454 S_SetMusicVolume(int volume)
455 {
456 if (volume < 0 || volume > 127) {
457 I_Error("Attempt to set music volume at %d", volume);
458 }
459
460 I_SetMusicVolume(127);
461 I_SetMusicVolume(volume);
462 snd_MusicVolume = volume;
463 }
464
465 void
466 S_SetSfxVolume(int volume)
467 {
468
469 if (volume < 0 || volume > 127)
470 I_Error("Attempt to set sfx volume at %d", volume);
471
472 snd_SfxVolume = volume;
473 }
474
475 void
476 S_StartMusic(int m_id)
477 {
478 S_ChangeMusic(m_id, false);
479 }
480
481 void
482 S_ChangeMusic(int musicnum, int looping)
483 {
484 musicinfo_t* music;
485 char namebuf[9];
486
487 if ((musicnum <= mus_None) || (musicnum >= NUMMUSIC)) {
488 I_Error("Bad music number %d", musicnum);
489 } else
490 music = &S_music[musicnum];
491
492 /* We don't know that I_Error exits, so actually a false positive;
493 see PR analyzer/108867. */
494
495 if (mus_playing == music) /* { dg-warning "use of uninitialized value 'music'" } */
496 return;
497
498 S_StopMusic();
499
500 /* We shouldn't issue further warnings about 'music' being
501 uninitialized. */
502
503 if (!music->lumpnum) { /* { dg-bogus "use of uninitialized value 'music'" } */
504 sprintf(namebuf, "d_%s", music->name); /* { dg-bogus "use of uninitialized value 'music'" } */
505 music->lumpnum = W_GetNumForName(namebuf); /* { dg-bogus "use of uninitialized value 'music'" } */
506 }
507
508 music->data = (void*)W_CacheLumpNum(music->lumpnum, 3); /* { dg-bogus "use of uninitialized value 'music'" } */
509 music->handle = I_RegisterSong(music->data); /* { dg-bogus "use of uninitialized value 'music'" } */
510
511 I_PlaySong(music->handle, looping); /* { dg-bogus "use of uninitialized value 'music'" } */
512
513 mus_playing = music; /* { dg-bogus "use of uninitialized value 'music'" } */
514 }
515
516 void
517 S_StopMusic(void)
518 {
519 if (mus_playing) {
520 if (mus_paused)
521 I_ResumeSong(mus_playing->handle);
522
523 I_StopSong(mus_playing->handle);
524 I_UnRegisterSong(mus_playing->handle);
525 {
526 if (((memblock_t*)((byte*)(mus_playing->data) - sizeof(memblock_t)))
527 ->id != 0x1d4a11)
528 I_Error("Z_CT at "
529 "s_sound.c"
530 ":%i",
531 699);
532 Z_ChangeTag2(mus_playing->data, 101);
533 };
534 ;
535
536 mus_playing->data = 0;
537 mus_playing = 0;
538 }
539 }
540
541 void
542 S_StopChannel(int cnum)
543 {
544
545 int i;
546 channel_t* c = &channels[cnum];
547
548 if (c->sfxinfo) {
549
550 if (I_SoundIsPlaying(c->handle)) {
551
552 I_StopSound(c->handle);
553 }
554
555 for (i = 0; i < numChannels; i++) {
556 if (cnum != i && c->sfxinfo == channels[i].sfxinfo) {
557 break;
558 }
559 }
560
561 c->sfxinfo->usefulness--;
562
563 c->sfxinfo = 0;
564 }
565 }
566 int
567 S_AdjustSoundParams(mobj_t* listener,
568 mobj_t* source,
569 int* vol,
570 int* sep,
571 int* pitch)
572 {
573 fixed_t approx_dist;
574 fixed_t adx;
575 fixed_t ady;
576 angle_t angle;
577
578 adx = abs(listener->x - source->x);
579 ady = abs(listener->y - source->y);
580
581 approx_dist = adx + ady - ((adx < ady ? adx : ady) >> 1);
582
583 if (gamemap != 8 && approx_dist > (1200 * 0x10000)) {
584 return 0;
585 }
586
587 angle = R_PointToAngle2(listener->x, listener->y, source->x, source->y);
588
589 if (angle > listener->angle)
590 angle = angle - listener->angle;
591 else
592 angle = angle + (0xffffffff - listener->angle);
593
594 angle >>= 19;
595
596 *sep = 128 - (FixedMul((96 * 0x10000), finesine[angle]) >> 16);
597
598 if (approx_dist < (160 * 0x10000)) {
599 *vol = snd_SfxVolume;
600 } else if (gamemap == 8) {
601 if (approx_dist > (1200 * 0x10000))
602 approx_dist = (1200 * 0x10000);
603
604 *vol =
605 15 + ((snd_SfxVolume - 15) * (((1200 * 0x10000) - approx_dist) >> 16)) /
606 (((1200 * 0x10000) - (160 * 0x10000)) >> 16);
607 } else {
608
609 *vol = (snd_SfxVolume * (((1200 * 0x10000) - approx_dist) >> 16)) /
610 (((1200 * 0x10000) - (160 * 0x10000)) >> 16);
611 }
612
613 return (*vol > 0);
614 }
615 int
616 S_getChannel(void* origin, sfxinfo_t* sfxinfo)
617 {
618
619 int cnum;
620
621 channel_t* c;
622
623 for (cnum = 0; cnum < numChannels; cnum++) {
624 if (!channels[cnum].sfxinfo)
625 break;
626 else if (origin && channels[cnum].origin == origin) {
627 S_StopChannel(cnum);
628 break;
629 }
630 }
631
632 if (cnum == numChannels) {
633
634 for (cnum = 0; cnum < numChannels; cnum++)
635 if (channels[cnum].sfxinfo->priority >= sfxinfo->priority) /* { dg-warning "dereference of NULL" } */
636 break;
637
638 if (cnum == numChannels) {
639
640 return -1;
641 } else {
642
643 S_StopChannel(cnum);
644 }
645 }
646
647 c = &channels[cnum];
648
649 c->sfxinfo = sfxinfo;
650 c->origin = origin;
651
652 return cnum;
653 }