diff options
Diffstat (limited to 'apps/plugins/sdl/progs/quake/snd_dma.c')
-rw-r--r-- | apps/plugins/sdl/progs/quake/snd_dma.c | 1021 |
1 files changed, 1021 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/quake/snd_dma.c b/apps/plugins/sdl/progs/quake/snd_dma.c new file mode 100644 index 0000000000..4c42f32d49 --- /dev/null +++ b/apps/plugins/sdl/progs/quake/snd_dma.c | |||
@@ -0,0 +1,1021 @@ | |||
1 | /* | ||
2 | Copyright (C) 1996-1997 Id Software, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU General Public License | ||
6 | as published by the Free Software Foundation; either version 2 | ||
7 | of the License, or (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
12 | |||
13 | See the GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | |||
19 | */ | ||
20 | // snd_dma.c -- main control for any streaming sound output device | ||
21 | |||
22 | #include "quakedef.h" | ||
23 | |||
24 | #ifdef _WIN32 | ||
25 | #include "winquake.h" | ||
26 | #endif | ||
27 | |||
28 | void S_Play(void); | ||
29 | void S_PlayVol(void); | ||
30 | void S_SoundList(void); | ||
31 | void S_Update_(); | ||
32 | void S_StopAllSounds(qboolean clear); | ||
33 | void S_StopAllSoundsC(void); | ||
34 | |||
35 | // ======================================================================= | ||
36 | // Internal sound data & structures | ||
37 | // ======================================================================= | ||
38 | |||
39 | channel_t channels[MAX_CHANNELS]; | ||
40 | int total_channels; | ||
41 | |||
42 | int snd_blocked = 0; | ||
43 | static qboolean snd_ambient = 1; | ||
44 | qboolean snd_initialized = false; | ||
45 | |||
46 | // pointer should go away | ||
47 | volatile dma_t *shm = 0; | ||
48 | volatile dma_t sn; | ||
49 | |||
50 | vec3_t listener_origin; | ||
51 | vec3_t listener_forward; | ||
52 | vec3_t listener_right; | ||
53 | vec3_t listener_up; | ||
54 | vec_t sound_nominal_clip_dist=1000.0; | ||
55 | |||
56 | int soundtime; // sample PAIRS | ||
57 | int paintedtime; // sample PAIRS | ||
58 | |||
59 | |||
60 | #define MAX_SFX 512 | ||
61 | sfx_t *known_sfx; // hunk allocated [MAX_SFX] | ||
62 | int num_sfx; | ||
63 | |||
64 | sfx_t *ambient_sfx[NUM_AMBIENTS]; | ||
65 | |||
66 | // lowest rockbox supported | ||
67 | int desired_speed = SAMPR_16; | ||
68 | int desired_bits = 16; | ||
69 | |||
70 | int sound_started=0; | ||
71 | |||
72 | cvar_t bgmvolume = {"bgmvolume", "1", true}; | ||
73 | cvar_t volume = {"volume", "0.7", true}; | ||
74 | |||
75 | cvar_t nosound = {"nosound", "0"}; | ||
76 | cvar_t precache = {"precache", "1"}; | ||
77 | cvar_t loadas8bit = {"loadas8bit", "0"}; | ||
78 | cvar_t bgmbuffer = {"bgmbuffer", "4096"}; | ||
79 | cvar_t ambient_level = {"ambient_level", "0.3"}; | ||
80 | cvar_t ambient_fade = {"ambient_fade", "100"}; | ||
81 | cvar_t snd_noextraupdate = {"snd_noextraupdate", "0"}; | ||
82 | cvar_t snd_show = {"snd_show", "0"}; | ||
83 | cvar_t _snd_mixahead = {"_snd_mixahead", "0.1", true}; | ||
84 | |||
85 | |||
86 | // ==================================================================== | ||
87 | // User-setable variables | ||
88 | // ==================================================================== | ||
89 | |||
90 | |||
91 | // | ||
92 | // Fake dma is a synchronous faking of the DMA progress used for | ||
93 | // isolating performance in the renderer. The fakedma_updates is | ||
94 | // number of times S_Update() is called per second. | ||
95 | // | ||
96 | |||
97 | qboolean fakedma = false; | ||
98 | int fakedma_updates = 15; | ||
99 | |||
100 | |||
101 | void S_AmbientOff (void) | ||
102 | { | ||
103 | snd_ambient = false; | ||
104 | } | ||
105 | |||
106 | |||
107 | void S_AmbientOn (void) | ||
108 | { | ||
109 | snd_ambient = true; | ||
110 | } | ||
111 | |||
112 | |||
113 | void S_SoundInfo_f(void) | ||
114 | { | ||
115 | if (!sound_started || !shm) | ||
116 | { | ||
117 | Con_Printf ("sound system not started\n"); | ||
118 | return; | ||
119 | } | ||
120 | |||
121 | Con_Printf("%5d stereo\n", shm->channels - 1); | ||
122 | Con_Printf("%5d samples\n", shm->samples); | ||
123 | Con_Printf("%5d samplepos\n", shm->samplepos); | ||
124 | Con_Printf("%5d samplebits\n", shm->samplebits); | ||
125 | Con_Printf("%5d submission_chunk\n", shm->submission_chunk); | ||
126 | Con_Printf("%5d speed\n", shm->speed); | ||
127 | Con_Printf("0x%x dma buffer\n", shm->buffer); | ||
128 | Con_Printf("%5d total_channels\n", total_channels); | ||
129 | } | ||
130 | |||
131 | |||
132 | /* | ||
133 | ================ | ||
134 | S_Startup | ||
135 | ================ | ||
136 | */ | ||
137 | |||
138 | void S_Startup (void) | ||
139 | { | ||
140 | int rc; | ||
141 | |||
142 | if (!snd_initialized) | ||
143 | return; | ||
144 | |||
145 | if (!fakedma) | ||
146 | { | ||
147 | rc = SNDDMA_Init(); | ||
148 | |||
149 | if (!rc) | ||
150 | { | ||
151 | #ifndef _WIN32 | ||
152 | Con_Printf("S_Startup: SNDDMA_Init failed.\n"); | ||
153 | #endif | ||
154 | sound_started = 0; | ||
155 | return; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | sound_started = 1; | ||
160 | } | ||
161 | |||
162 | |||
163 | /* | ||
164 | ================ | ||
165 | S_Init | ||
166 | ================ | ||
167 | */ | ||
168 | void S_Init (void) | ||
169 | { | ||
170 | |||
171 | Con_Printf("\nSound Initialization\n"); | ||
172 | |||
173 | if (COM_CheckParm("-nosound")) | ||
174 | return; | ||
175 | |||
176 | if (COM_CheckParm("-simsound")) | ||
177 | fakedma = true; | ||
178 | |||
179 | Cmd_AddCommand("play", S_Play); | ||
180 | Cmd_AddCommand("playvol", S_PlayVol); | ||
181 | Cmd_AddCommand("stopsound", S_StopAllSoundsC); | ||
182 | Cmd_AddCommand("soundlist", S_SoundList); | ||
183 | Cmd_AddCommand("soundinfo", S_SoundInfo_f); | ||
184 | |||
185 | Cvar_RegisterVariable(&nosound); | ||
186 | Cvar_RegisterVariable(&volume); | ||
187 | Cvar_RegisterVariable(&precache); | ||
188 | Cvar_RegisterVariable(&loadas8bit); | ||
189 | Cvar_RegisterVariable(&bgmvolume); | ||
190 | Cvar_RegisterVariable(&bgmbuffer); | ||
191 | Cvar_RegisterVariable(&ambient_level); | ||
192 | Cvar_RegisterVariable(&ambient_fade); | ||
193 | Cvar_RegisterVariable(&snd_noextraupdate); | ||
194 | Cvar_RegisterVariable(&snd_show); | ||
195 | Cvar_RegisterVariable(&_snd_mixahead); | ||
196 | |||
197 | if (host_parms.memsize < 0x800000) | ||
198 | { | ||
199 | Cvar_Set ("loadas8bit", "1"); | ||
200 | Con_Printf ("loading all sounds as 8bit\n"); | ||
201 | } | ||
202 | |||
203 | |||
204 | |||
205 | snd_initialized = true; | ||
206 | |||
207 | S_Startup (); | ||
208 | |||
209 | known_sfx = Hunk_AllocName (MAX_SFX*sizeof(sfx_t), "sfx_t"); | ||
210 | num_sfx = 0; | ||
211 | |||
212 | // create a piece of DMA memory | ||
213 | |||
214 | if (fakedma) | ||
215 | { | ||
216 | shm = (void *) Hunk_AllocName(sizeof(*shm), "shm"); | ||
217 | shm->splitbuffer = 0; | ||
218 | shm->samplebits = 16; | ||
219 | shm->speed = 22050; | ||
220 | shm->channels = 2; | ||
221 | shm->samples = 32768; | ||
222 | shm->samplepos = 0; | ||
223 | shm->soundalive = true; | ||
224 | shm->gamealive = true; | ||
225 | shm->submission_chunk = 1; | ||
226 | shm->buffer = Hunk_AllocName(1<<16, "shmbuf"); | ||
227 | } | ||
228 | |||
229 | if ( shm ) { | ||
230 | Con_Printf ("Sound sampling rate: %i\n", shm->speed); | ||
231 | } | ||
232 | |||
233 | // provides a tick sound until washed clean | ||
234 | |||
235 | // if (shm->buffer) | ||
236 | // shm->buffer[4] = shm->buffer[5] = 0x7f; // force a pop for debugging | ||
237 | |||
238 | ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav"); | ||
239 | ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav"); | ||
240 | |||
241 | S_StopAllSounds (true); | ||
242 | } | ||
243 | |||
244 | |||
245 | // ======================================================================= | ||
246 | // Shutdown sound engine | ||
247 | // ======================================================================= | ||
248 | |||
249 | void S_Shutdown(void) | ||
250 | { | ||
251 | |||
252 | if (!sound_started) | ||
253 | return; | ||
254 | |||
255 | if (shm) | ||
256 | shm->gamealive = 0; | ||
257 | |||
258 | shm = 0; | ||
259 | sound_started = 0; | ||
260 | |||
261 | if (!fakedma) | ||
262 | { | ||
263 | SNDDMA_Shutdown(); | ||
264 | } | ||
265 | } | ||
266 | |||
267 | |||
268 | // ======================================================================= | ||
269 | // Load a sound | ||
270 | // ======================================================================= | ||
271 | |||
272 | /* | ||
273 | ================== | ||
274 | S_FindName | ||
275 | |||
276 | ================== | ||
277 | */ | ||
278 | sfx_t *S_FindName (char *name) | ||
279 | { | ||
280 | int i; | ||
281 | sfx_t *sfx; | ||
282 | |||
283 | if (!name) | ||
284 | Sys_Error ("S_FindName: NULL\n"); | ||
285 | |||
286 | if (Q_strlen(name) >= MAX_QPATH) | ||
287 | Sys_Error ("Sound name too long: %s", name); | ||
288 | |||
289 | // see if already loaded | ||
290 | for (i=0 ; i < num_sfx ; i++) | ||
291 | if (!Q_strcmp(known_sfx[i].name, name)) | ||
292 | { | ||
293 | return &known_sfx[i]; | ||
294 | } | ||
295 | |||
296 | if (num_sfx == MAX_SFX) | ||
297 | Sys_Error ("S_FindName: out of sfx_t"); | ||
298 | |||
299 | sfx = &known_sfx[i]; | ||
300 | strcpy (sfx->name, name); | ||
301 | |||
302 | num_sfx++; | ||
303 | |||
304 | return sfx; | ||
305 | } | ||
306 | |||
307 | |||
308 | /* | ||
309 | ================== | ||
310 | S_TouchSound | ||
311 | |||
312 | ================== | ||
313 | */ | ||
314 | void S_TouchSound (char *name) | ||
315 | { | ||
316 | sfx_t *sfx; | ||
317 | |||
318 | if (!sound_started) | ||
319 | return; | ||
320 | |||
321 | sfx = S_FindName (name); | ||
322 | Cache_Check (&sfx->cache); | ||
323 | } | ||
324 | |||
325 | /* | ||
326 | ================== | ||
327 | S_PrecacheSound | ||
328 | |||
329 | ================== | ||
330 | */ | ||
331 | sfx_t *S_PrecacheSound (char *name) | ||
332 | { | ||
333 | sfx_t *sfx; | ||
334 | |||
335 | if (!sound_started || nosound.value) | ||
336 | return NULL; | ||
337 | |||
338 | sfx = S_FindName (name); | ||
339 | |||
340 | // cache it in | ||
341 | if (precache.value) | ||
342 | S_LoadSound (sfx); | ||
343 | |||
344 | return sfx; | ||
345 | } | ||
346 | |||
347 | |||
348 | //============================================================================= | ||
349 | |||
350 | /* | ||
351 | ================= | ||
352 | SND_PickChannel | ||
353 | ================= | ||
354 | */ | ||
355 | channel_t *SND_PickChannel(int entnum, int entchannel) | ||
356 | { | ||
357 | int ch_idx; | ||
358 | int first_to_die; | ||
359 | int life_left; | ||
360 | |||
361 | // Check for replacement sound, or find the best one to replace | ||
362 | first_to_die = -1; | ||
363 | life_left = 0x7fffffff; | ||
364 | for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++) | ||
365 | { | ||
366 | if (entchannel != 0 // channel 0 never overrides | ||
367 | && channels[ch_idx].entnum == entnum | ||
368 | && (channels[ch_idx].entchannel == entchannel || entchannel == -1) ) | ||
369 | { // allways override sound from same entity | ||
370 | first_to_die = ch_idx; | ||
371 | break; | ||
372 | } | ||
373 | |||
374 | // don't let monster sounds override player sounds | ||
375 | if (channels[ch_idx].entnum == cl.viewentity && entnum != cl.viewentity && channels[ch_idx].sfx) | ||
376 | continue; | ||
377 | |||
378 | if (channels[ch_idx].end - paintedtime < life_left) | ||
379 | { | ||
380 | life_left = channels[ch_idx].end - paintedtime; | ||
381 | first_to_die = ch_idx; | ||
382 | } | ||
383 | } | ||
384 | |||
385 | if (first_to_die == -1) | ||
386 | return NULL; | ||
387 | |||
388 | if (channels[first_to_die].sfx) | ||
389 | channels[first_to_die].sfx = NULL; | ||
390 | |||
391 | return &channels[first_to_die]; | ||
392 | } | ||
393 | |||
394 | /* | ||
395 | ================= | ||
396 | SND_Spatialize | ||
397 | ================= | ||
398 | */ | ||
399 | void SND_Spatialize(channel_t *ch) | ||
400 | { | ||
401 | vec_t dot; | ||
402 | vec_t ldist, rdist, dist; | ||
403 | vec_t lscale, rscale, scale; | ||
404 | vec3_t source_vec; | ||
405 | sfx_t *snd; | ||
406 | |||
407 | // anything coming from the view entity will allways be full volume | ||
408 | if (ch->entnum == cl.viewentity) | ||
409 | { | ||
410 | ch->leftvol = ch->master_vol; | ||
411 | ch->rightvol = ch->master_vol; | ||
412 | return; | ||
413 | } | ||
414 | |||
415 | // calculate stereo seperation and distance attenuation | ||
416 | |||
417 | snd = ch->sfx; | ||
418 | VectorSubtract(ch->origin, listener_origin, source_vec); | ||
419 | |||
420 | dist = VectorNormalize(source_vec) * ch->dist_mult; | ||
421 | |||
422 | dot = DotProduct(listener_right, source_vec); | ||
423 | |||
424 | if (shm->channels == 1) | ||
425 | { | ||
426 | rscale = 1.0; | ||
427 | lscale = 1.0; | ||
428 | } | ||
429 | else | ||
430 | { | ||
431 | rscale = 1.0 + dot; | ||
432 | lscale = 1.0 - dot; | ||
433 | } | ||
434 | |||
435 | // add in distance effect | ||
436 | scale = (1.0 - dist) * rscale; | ||
437 | ch->rightvol = (int) (ch->master_vol * scale); | ||
438 | if (ch->rightvol < 0) | ||
439 | ch->rightvol = 0; | ||
440 | |||
441 | scale = (1.0 - dist) * lscale; | ||
442 | ch->leftvol = (int) (ch->master_vol * scale); | ||
443 | if (ch->leftvol < 0) | ||
444 | ch->leftvol = 0; | ||
445 | } | ||
446 | |||
447 | |||
448 | // ======================================================================= | ||
449 | // Start a sound effect | ||
450 | // ======================================================================= | ||
451 | |||
452 | void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation) | ||
453 | { | ||
454 | channel_t *target_chan, *check; | ||
455 | sfxcache_t *sc; | ||
456 | int vol; | ||
457 | int ch_idx; | ||
458 | int skip; | ||
459 | |||
460 | if (!sound_started) | ||
461 | return; | ||
462 | |||
463 | if (!sfx) | ||
464 | return; | ||
465 | |||
466 | if (nosound.value) | ||
467 | return; | ||
468 | |||
469 | vol = fvol*255; | ||
470 | |||
471 | // pick a channel to play on | ||
472 | target_chan = SND_PickChannel(entnum, entchannel); | ||
473 | if (!target_chan) | ||
474 | return; | ||
475 | |||
476 | // spatialize | ||
477 | memset (target_chan, 0, sizeof(*target_chan)); | ||
478 | VectorCopy(origin, target_chan->origin); | ||
479 | target_chan->dist_mult = attenuation / sound_nominal_clip_dist; | ||
480 | target_chan->master_vol = vol; | ||
481 | target_chan->entnum = entnum; | ||
482 | target_chan->entchannel = entchannel; | ||
483 | SND_Spatialize(target_chan); | ||
484 | |||
485 | if (!target_chan->leftvol && !target_chan->rightvol) | ||
486 | return; // not audible at all | ||
487 | |||
488 | // new channel | ||
489 | sc = S_LoadSound (sfx); | ||
490 | if (!sc) | ||
491 | { | ||
492 | target_chan->sfx = NULL; | ||
493 | return; // couldn't load the sound's data | ||
494 | } | ||
495 | |||
496 | target_chan->sfx = sfx; | ||
497 | target_chan->pos = 0.0; | ||
498 | target_chan->end = paintedtime + sc->length; | ||
499 | |||
500 | // if an identical sound has also been started this frame, offset the pos | ||
501 | // a bit to keep it from just making the first one louder | ||
502 | check = &channels[NUM_AMBIENTS]; | ||
503 | for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++) | ||
504 | { | ||
505 | if (check == target_chan) | ||
506 | continue; | ||
507 | if (check->sfx == sfx && !check->pos) | ||
508 | { | ||
509 | skip = rand () % (int)(0.1*shm->speed); | ||
510 | if (skip >= target_chan->end) | ||
511 | skip = target_chan->end - 1; | ||
512 | target_chan->pos += skip; | ||
513 | target_chan->end -= skip; | ||
514 | break; | ||
515 | } | ||
516 | |||
517 | } | ||
518 | } | ||
519 | |||
520 | void S_StopSound(int entnum, int entchannel) | ||
521 | { | ||
522 | int i; | ||
523 | |||
524 | for (i=0 ; i<MAX_DYNAMIC_CHANNELS ; i++) | ||
525 | { | ||
526 | if (channels[i].entnum == entnum | ||
527 | && channels[i].entchannel == entchannel) | ||
528 | { | ||
529 | channels[i].end = 0; | ||
530 | channels[i].sfx = NULL; | ||
531 | return; | ||
532 | } | ||
533 | } | ||
534 | } | ||
535 | |||
536 | void S_StopAllSounds(qboolean clear) | ||
537 | { | ||
538 | int i; | ||
539 | |||
540 | if (!sound_started) | ||
541 | return; | ||
542 | |||
543 | total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics | ||
544 | |||
545 | for (i=0 ; i<MAX_CHANNELS ; i++) | ||
546 | if (channels[i].sfx) | ||
547 | channels[i].sfx = NULL; | ||
548 | |||
549 | Q_memset(channels, 0, MAX_CHANNELS * sizeof(channel_t)); | ||
550 | |||
551 | if (clear) | ||
552 | S_ClearBuffer (); | ||
553 | } | ||
554 | |||
555 | void S_StopAllSoundsC (void) | ||
556 | { | ||
557 | S_StopAllSounds (true); | ||
558 | } | ||
559 | |||
560 | void S_ClearBuffer (void) | ||
561 | { | ||
562 | int clear; | ||
563 | |||
564 | #ifdef _WIN32 | ||
565 | if (!sound_started || !shm || (!shm->buffer && !pDSBuf)) | ||
566 | #else | ||
567 | if (!sound_started || !shm || !shm->buffer) | ||
568 | #endif | ||
569 | return; | ||
570 | |||
571 | if (shm->samplebits == 8) | ||
572 | clear = 0x80; | ||
573 | else | ||
574 | clear = 0; | ||
575 | |||
576 | #ifdef _WIN32 | ||
577 | if (pDSBuf) | ||
578 | { | ||
579 | DWORD dwSize; | ||
580 | DWORD *pData; | ||
581 | int reps; | ||
582 | HRESULT hresult; | ||
583 | |||
584 | reps = 0; | ||
585 | |||
586 | while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pData, &dwSize, NULL, NULL, 0)) != DS_OK) | ||
587 | { | ||
588 | if (hresult != DSERR_BUFFERLOST) | ||
589 | { | ||
590 | Con_Printf ("S_ClearBuffer: DS::Lock Sound Buffer Failed\n"); | ||
591 | S_Shutdown (); | ||
592 | return; | ||
593 | } | ||
594 | |||
595 | if (++reps > 10000) | ||
596 | { | ||
597 | Con_Printf ("S_ClearBuffer: DS: couldn't restore buffer\n"); | ||
598 | S_Shutdown (); | ||
599 | return; | ||
600 | } | ||
601 | } | ||
602 | |||
603 | Q_memset(pData, clear, shm->samples * shm->samplebits/8); | ||
604 | |||
605 | pDSBuf->lpVtbl->Unlock(pDSBuf, pData, dwSize, NULL, 0); | ||
606 | |||
607 | } | ||
608 | else | ||
609 | #endif | ||
610 | { | ||
611 | Q_memset(shm->buffer, clear, shm->samples * shm->samplebits/8); | ||
612 | } | ||
613 | } | ||
614 | |||
615 | |||
616 | /* | ||
617 | ================= | ||
618 | S_StaticSound | ||
619 | ================= | ||
620 | */ | ||
621 | void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation) | ||
622 | { | ||
623 | channel_t *ss; | ||
624 | sfxcache_t *sc; | ||
625 | |||
626 | if (!sfx) | ||
627 | return; | ||
628 | |||
629 | if (total_channels == MAX_CHANNELS) | ||
630 | { | ||
631 | Con_Printf ("total_channels == MAX_CHANNELS\n"); | ||
632 | return; | ||
633 | } | ||
634 | |||
635 | ss = &channels[total_channels]; | ||
636 | total_channels++; | ||
637 | |||
638 | sc = S_LoadSound (sfx); | ||
639 | if (!sc) | ||
640 | return; | ||
641 | |||
642 | if (sc->loopstart == -1) | ||
643 | { | ||
644 | Con_Printf ("Sound %s not looped\n", sfx->name); | ||
645 | return; | ||
646 | } | ||
647 | |||
648 | ss->sfx = sfx; | ||
649 | VectorCopy (origin, ss->origin); | ||
650 | ss->master_vol = vol; | ||
651 | ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist; | ||
652 | ss->end = paintedtime + sc->length; | ||
653 | |||
654 | SND_Spatialize (ss); | ||
655 | } | ||
656 | |||
657 | |||
658 | //============================================================================= | ||
659 | |||
660 | /* | ||
661 | =================== | ||
662 | S_UpdateAmbientSounds | ||
663 | =================== | ||
664 | */ | ||
665 | void S_UpdateAmbientSounds (void) | ||
666 | { | ||
667 | mleaf_t *l; | ||
668 | float vol; | ||
669 | int ambient_channel; | ||
670 | channel_t *chan; | ||
671 | |||
672 | if (!snd_ambient) | ||
673 | return; | ||
674 | |||
675 | // calc ambient sound levels | ||
676 | if (!cl.worldmodel) | ||
677 | return; | ||
678 | |||
679 | l = Mod_PointInLeaf (listener_origin, cl.worldmodel); | ||
680 | if (!l || !ambient_level.value) | ||
681 | { | ||
682 | for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++) | ||
683 | channels[ambient_channel].sfx = NULL; | ||
684 | return; | ||
685 | } | ||
686 | |||
687 | for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++) | ||
688 | { | ||
689 | chan = &channels[ambient_channel]; | ||
690 | chan->sfx = ambient_sfx[ambient_channel]; | ||
691 | |||
692 | vol = ambient_level.value * l->ambient_sound_level[ambient_channel]; | ||
693 | if (vol < 8) | ||
694 | vol = 0; | ||
695 | |||
696 | // don't adjust volume too fast | ||
697 | if (chan->master_vol < vol) | ||
698 | { | ||
699 | chan->master_vol += host_frametime * ambient_fade.value; | ||
700 | if (chan->master_vol > vol) | ||
701 | chan->master_vol = vol; | ||
702 | } | ||
703 | else if (chan->master_vol > vol) | ||
704 | { | ||
705 | chan->master_vol -= host_frametime * ambient_fade.value; | ||
706 | if (chan->master_vol < vol) | ||
707 | chan->master_vol = vol; | ||
708 | } | ||
709 | |||
710 | chan->leftvol = chan->rightvol = chan->master_vol; | ||
711 | } | ||
712 | } | ||
713 | |||
714 | |||
715 | /* | ||
716 | ============ | ||
717 | S_Update | ||
718 | |||
719 | Called once each time through the main loop | ||
720 | ============ | ||
721 | */ | ||
722 | void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) | ||
723 | { | ||
724 | int i, j; | ||
725 | int total; | ||
726 | channel_t *ch; | ||
727 | channel_t *combine; | ||
728 | |||
729 | if (!sound_started || (snd_blocked > 0)) | ||
730 | return; | ||
731 | |||
732 | VectorCopy(origin, listener_origin); | ||
733 | VectorCopy(forward, listener_forward); | ||
734 | VectorCopy(right, listener_right); | ||
735 | VectorCopy(up, listener_up); | ||
736 | |||
737 | // update general area ambient sound sources | ||
738 | S_UpdateAmbientSounds (); | ||
739 | |||
740 | combine = NULL; | ||
741 | |||
742 | // update spatialization for static and dynamic sounds | ||
743 | ch = channels+NUM_AMBIENTS; | ||
744 | for (i=NUM_AMBIENTS ; i<total_channels; i++, ch++) | ||
745 | { | ||
746 | if (!ch->sfx) | ||
747 | continue; | ||
748 | SND_Spatialize(ch); // respatialize channel | ||
749 | if (!ch->leftvol && !ch->rightvol) | ||
750 | continue; | ||
751 | |||
752 | // try to combine static sounds with a previous channel of the same | ||
753 | // sound effect so we don't mix five torches every frame | ||
754 | |||
755 | if (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS) | ||
756 | { | ||
757 | // see if it can just use the last one | ||
758 | if (combine && combine->sfx == ch->sfx) | ||
759 | { | ||
760 | combine->leftvol += ch->leftvol; | ||
761 | combine->rightvol += ch->rightvol; | ||
762 | ch->leftvol = ch->rightvol = 0; | ||
763 | continue; | ||
764 | } | ||
765 | // search for one | ||
766 | combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; | ||
767 | for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; j<i; j++, combine++) | ||
768 | if (combine->sfx == ch->sfx) | ||
769 | break; | ||
770 | |||
771 | if (j == total_channels) | ||
772 | { | ||
773 | combine = NULL; | ||
774 | } | ||
775 | else | ||
776 | { | ||
777 | if (combine != ch) | ||
778 | { | ||
779 | combine->leftvol += ch->leftvol; | ||
780 | combine->rightvol += ch->rightvol; | ||
781 | ch->leftvol = ch->rightvol = 0; | ||
782 | } | ||
783 | continue; | ||
784 | } | ||
785 | } | ||
786 | |||
787 | |||
788 | } | ||
789 | |||
790 | // | ||
791 | // debugging output | ||
792 | // | ||
793 | if (snd_show.value) | ||
794 | { | ||
795 | total = 0; | ||
796 | ch = channels; | ||
797 | for (i=0 ; i<total_channels; i++, ch++) | ||
798 | if (ch->sfx && (ch->leftvol || ch->rightvol) ) | ||
799 | { | ||
800 | //Con_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name); | ||
801 | total++; | ||
802 | } | ||
803 | |||
804 | Con_Printf ("----(%i)----\n", total); | ||
805 | } | ||
806 | |||
807 | // mix some sound | ||
808 | S_Update_(); | ||
809 | } | ||
810 | |||
811 | void GetSoundtime(void) | ||
812 | { | ||
813 | int samplepos; | ||
814 | static int buffers; | ||
815 | static int oldsamplepos; | ||
816 | int fullsamples; | ||
817 | |||
818 | fullsamples = shm->samples / shm->channels; | ||
819 | |||
820 | // it is possible to miscount buffers if it has wrapped twice between | ||
821 | // calls to S_Update. Oh well. | ||
822 | #ifdef __sun__ | ||
823 | soundtime = SNDDMA_GetSamples(); | ||
824 | #else | ||
825 | samplepos = SNDDMA_GetDMAPos(); | ||
826 | |||
827 | |||
828 | if (samplepos < oldsamplepos) | ||
829 | { | ||
830 | buffers++; // buffer wrapped | ||
831 | |||
832 | if (paintedtime > 0x40000000) | ||
833 | { // time to chop things off to avoid 32 bit limits | ||
834 | buffers = 0; | ||
835 | paintedtime = fullsamples; | ||
836 | S_StopAllSounds (true); | ||
837 | } | ||
838 | } | ||
839 | oldsamplepos = samplepos; | ||
840 | |||
841 | soundtime = buffers*fullsamples + samplepos/shm->channels; | ||
842 | #endif | ||
843 | } | ||
844 | |||
845 | void S_ExtraUpdate (void) | ||
846 | { | ||
847 | |||
848 | #ifdef _WIN32 | ||
849 | IN_Accumulate (); | ||
850 | #endif | ||
851 | |||
852 | if (snd_noextraupdate.value) | ||
853 | return; // don't pollute timings | ||
854 | S_Update_(); | ||
855 | } | ||
856 | |||
857 | void S_Update_(void) | ||
858 | { | ||
859 | #ifndef SDL | ||
860 | |||
861 | unsigned endtime; | ||
862 | int samps; | ||
863 | |||
864 | if (!sound_started || (snd_blocked > 0)) | ||
865 | return; | ||
866 | |||
867 | // Updates DMA time | ||
868 | GetSoundtime(); | ||
869 | |||
870 | // check to make sure that we haven't overshot | ||
871 | if (paintedtime < soundtime) | ||
872 | { | ||
873 | //Con_Printf ("S_Update_ : overflow\n"); | ||
874 | paintedtime = soundtime; | ||
875 | } | ||
876 | |||
877 | // mix ahead of current position | ||
878 | endtime = soundtime + _snd_mixahead.value * shm->speed; | ||
879 | samps = shm->samples >> (shm->channels-1); | ||
880 | if (endtime - soundtime > samps) | ||
881 | endtime = soundtime + samps; | ||
882 | |||
883 | #ifdef _WIN32 | ||
884 | // if the buffer was lost or stopped, restore it and/or restart it | ||
885 | { | ||
886 | DWORD dwStatus; | ||
887 | |||
888 | if (pDSBuf) | ||
889 | { | ||
890 | if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DD_OK) | ||
891 | Con_Printf ("Couldn't get sound buffer status\n"); | ||
892 | |||
893 | if (dwStatus & DSBSTATUS_BUFFERLOST) | ||
894 | pDSBuf->lpVtbl->Restore (pDSBuf); | ||
895 | |||
896 | if (!(dwStatus & DSBSTATUS_PLAYING)) | ||
897 | pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); | ||
898 | } | ||
899 | } | ||
900 | #endif | ||
901 | |||
902 | S_PaintChannels (endtime); | ||
903 | |||
904 | SNDDMA_Submit (); | ||
905 | #endif /* ! SDL */ | ||
906 | } | ||
907 | |||
908 | /* | ||
909 | =============================================================================== | ||
910 | |||
911 | console functions | ||
912 | |||
913 | =============================================================================== | ||
914 | */ | ||
915 | |||
916 | void S_Play(void) | ||
917 | { | ||
918 | static int hash=345; | ||
919 | int i; | ||
920 | char name[256]; | ||
921 | sfx_t *sfx; | ||
922 | |||
923 | i = 1; | ||
924 | while (i<Cmd_Argc()) | ||
925 | { | ||
926 | if (!Q_strrchr(Cmd_Argv(i), '.')) | ||
927 | { | ||
928 | Q_strcpy(name, Cmd_Argv(i)); | ||
929 | Q_strcat(name, ".wav"); | ||
930 | } | ||
931 | else | ||
932 | Q_strcpy(name, Cmd_Argv(i)); | ||
933 | sfx = S_PrecacheSound(name); | ||
934 | S_StartSound(hash++, 0, sfx, listener_origin, 1.0, 1.0); | ||
935 | i++; | ||
936 | } | ||
937 | } | ||
938 | |||
939 | void S_PlayVol(void) | ||
940 | { | ||
941 | static int hash=543; | ||
942 | int i; | ||
943 | float vol; | ||
944 | char name[256]; | ||
945 | sfx_t *sfx; | ||
946 | |||
947 | i = 1; | ||
948 | while (i<Cmd_Argc()) | ||
949 | { | ||
950 | if (!Q_strrchr(Cmd_Argv(i), '.')) | ||
951 | { | ||
952 | Q_strcpy(name, Cmd_Argv(i)); | ||
953 | Q_strcat(name, ".wav"); | ||
954 | } | ||
955 | else | ||
956 | Q_strcpy(name, Cmd_Argv(i)); | ||
957 | sfx = S_PrecacheSound(name); | ||
958 | vol = Q_atof(Cmd_Argv(i+1)); | ||
959 | S_StartSound(hash++, 0, sfx, listener_origin, vol, 1.0); | ||
960 | i+=2; | ||
961 | } | ||
962 | } | ||
963 | |||
964 | void S_SoundList(void) | ||
965 | { | ||
966 | int i; | ||
967 | sfx_t *sfx; | ||
968 | sfxcache_t *sc; | ||
969 | int size, total; | ||
970 | |||
971 | total = 0; | ||
972 | for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++) | ||
973 | { | ||
974 | sc = Cache_Check (&sfx->cache); | ||
975 | if (!sc) | ||
976 | continue; | ||
977 | size = sc->length*sc->width*(sc->stereo+1); | ||
978 | total += size; | ||
979 | if (sc->loopstart >= 0) | ||
980 | Con_Printf ("L"); | ||
981 | else | ||
982 | Con_Printf (" "); | ||
983 | Con_Printf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name); | ||
984 | } | ||
985 | Con_Printf ("Total resident: %i\n", total); | ||
986 | } | ||
987 | |||
988 | |||
989 | void S_LocalSound (char *sound) | ||
990 | { | ||
991 | sfx_t *sfx; | ||
992 | |||
993 | if (nosound.value) | ||
994 | return; | ||
995 | if (!sound_started) | ||
996 | return; | ||
997 | |||
998 | sfx = S_PrecacheSound (sound); | ||
999 | if (!sfx) | ||
1000 | { | ||
1001 | Con_Printf ("S_LocalSound: can't cache %s\n", sound); | ||
1002 | return; | ||
1003 | } | ||
1004 | S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1); | ||
1005 | } | ||
1006 | |||
1007 | |||
1008 | void S_ClearPrecache (void) | ||
1009 | { | ||
1010 | } | ||
1011 | |||
1012 | |||
1013 | void S_BeginPrecaching (void) | ||
1014 | { | ||
1015 | } | ||
1016 | |||
1017 | |||
1018 | void S_EndPrecaching (void) | ||
1019 | { | ||
1020 | } | ||
1021 | |||