DarkPlaces
Game engine based on the Quake 1 engine by id Software, developed by LadyHavoc
 
snd_main.h File Reference
#include <stddef.h>
#include "qtypes.h"
#include "qdefs.h"
+ Include dependency graph for snd_main.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  channel_t
 
struct  listener_t
 
struct  portable_sampleframe_t
 exported for capturevideo so ogg can see all channels More...
 
struct  sfx_t
 
struct  snd_buffer_t
 
struct  snd_fetcher_t
 
struct  snd_format_t
 
struct  snd_ringbuffer_t
 
struct  speakerlayout_t
 

Macros

#define SFXFLAG_FILEMISSING   (1 << 0)
 wasn't able to load the associated sound file
 
#define SFXFLAG_LEVELSOUND   (1 << 1)
 the sfx is part of the server or client precache list for this level
 
#define SFXFLAG_MENUSOUND   (1 << 3)
 not freed during level change (menu sounds, music, etc)
 
#define SFXFLAG_NONE   0
 
#define SFXFLAG_STREAMED   (1 << 2)
 informative only. You shouldn't need to know that
 
#define SND_CHANNELLAYOUT_ALSA   2
 
#define SND_CHANNELLAYOUT_AUTO   0
 
#define SND_CHANNELLAYOUT_STANDARD   1
 
#define SND_LISTENERS   8
 
#define STREAM_BUFFERSIZE   16384
 in sampleframes
 

Typedefs

typedef void(* snd_fetcher_freesfx_t) (struct sfx_s *sfx)
 
typedef void(* snd_fetcher_getsamplesfloat_t) (channel_t *ch, struct sfx_s *sfx, int firstsampleframe, int numsampleframes, float *outsamplesfloat)
 
typedef void(* snd_fetcher_stopchannel_t) (channel_t *ch)
 

Functions

qbool S_LoadSound (struct sfx_s *sfx, qbool complain)
 
void S_MixToBuffer (void *stream, unsigned int frames)
 
void S_SetUnderwaterIntensity (void)
 
snd_ringbuffer_tSnd_CreateRingBuffer (const snd_format_t *format, unsigned int sampleframes, void *buffer)
 If "buffer" is NULL, the function allocates one buffer of "sampleframes" sample frames itself (if "sampleframes" is 0, the function chooses the size).
 
unsigned int SndSys_GetSoundTime (void)
 Returns the number of sample frames consumed since the sound started.
 
qbool SndSys_Init (snd_format_t *fmt)
 Create "snd_renderbuffer", attempting to use the chosen sound format, but accepting if the driver wants to change it (e.g.
 
qbool SndSys_LockRenderBuffer (void)
 Get the exclusive lock on "snd_renderbuffer".
 
void SndSys_SendKeyEvents (void)
 if the sound system can generate events, send them
 
void SndSys_Shutdown (void)
 Stop the sound card, delete "snd_renderbuffer" and free its other resources.
 
void SndSys_Submit (void)
 Submit the contents of "snd_renderbuffer" to the sound card.
 
void SndSys_UnlockRenderBuffer (void)
 Release the exclusive lock on "snd_renderbuffer".
 

Variables

channel_t channels [MAX_CHANNELS]
 
qbool simsound
 If simsound is true, the sound card is not initialized and no sound is submitted to it.
 
bool snd_blocked
 When true, we submit silence to the audio device.
 
cvar_t snd_bufferlength
 
cvar_t snd_channellayout
 
struct mempool_s * snd_mempool
 
snd_ringbuffer_tsnd_renderbuffer
 
cvar_t snd_streaming
 
cvar_t snd_streaming_length
 
qbool snd_threaded
 enables use of snd_usethreadedmixing, provided that no sound hacks are in effect (like timedemo)
 
qbool snd_usethreadedmixing
 if true, the main thread does not mix sound, soundtime does not advance, and neither does snd_renderbuffer->endframe, instead the audio thread will call S_MixToBuffer as needed
 
cvar_t snd_waterfx
 
unsigned int total_channels
 

Macro Definition Documentation

◆ SFXFLAG_FILEMISSING

#define SFXFLAG_FILEMISSING   (1 << 0)

wasn't able to load the associated sound file

Definition at line 60 of file snd_main.h.

Referenced by S_LoadSound().

◆ SFXFLAG_LEVELSOUND

#define SFXFLAG_LEVELSOUND   (1 << 1)

the sfx is part of the server or client precache list for this level

Definition at line 61 of file snd_main.h.

Referenced by S_ClearUsed(), S_FreeSfx(), S_PrecacheSound(), and S_PurgeUnused().

◆ SFXFLAG_MENUSOUND

#define SFXFLAG_MENUSOUND   (1 << 3)

not freed during level change (menu sounds, music, etc)

Definition at line 63 of file snd_main.h.

Referenced by S_ClearUsed(), S_FreeSfx(), S_LocalSoundEx(), S_PrecacheSound(), S_PurgeUnused(), and S_SoundList_f().

◆ SFXFLAG_NONE

#define SFXFLAG_NONE   0

Definition at line 59 of file snd_main.h.

◆ SFXFLAG_STREAMED

#define SFXFLAG_STREAMED   (1 << 2)

informative only. You shouldn't need to know that

Definition at line 62 of file snd_main.h.

Referenced by OGG_LoadVorbisFile(), S_SoundList_f(), and XMP_LoadModFile().

◆ SND_CHANNELLAYOUT_ALSA

#define SND_CHANNELLAYOUT_ALSA   2

Definition at line 136 of file snd_main.h.

Referenced by S_SetChannelLayout().

◆ SND_CHANNELLAYOUT_AUTO

#define SND_CHANNELLAYOUT_AUTO   0

Definition at line 134 of file snd_main.h.

Referenced by S_SetChannelLayout(), S_Startup(), and SndSys_Init().

◆ SND_CHANNELLAYOUT_STANDARD

#define SND_CHANNELLAYOUT_STANDARD   1

Definition at line 135 of file snd_main.h.

Referenced by S_SetChannelLayout(), and SndSys_Init().

◆ SND_LISTENERS

#define SND_LISTENERS   8

◆ STREAM_BUFFERSIZE

#define STREAM_BUFFERSIZE   16384

in sampleframes

Definition at line 150 of file snd_main.h.

Typedef Documentation

◆ snd_fetcher_freesfx_t

typedef void(* snd_fetcher_freesfx_t) (struct sfx_s *sfx)

Definition at line 115 of file snd_main.h.

◆ snd_fetcher_getsamplesfloat_t

typedef void(* snd_fetcher_getsamplesfloat_t) (channel_t *ch, struct sfx_s *sfx, int firstsampleframe, int numsampleframes, float *outsamplesfloat)

Definition at line 113 of file snd_main.h.

◆ snd_fetcher_stopchannel_t

typedef void(* snd_fetcher_stopchannel_t) (channel_t *ch)

Definition at line 114 of file snd_main.h.

Function Documentation

◆ S_LoadSound()

qbool S_LoadSound ( struct sfx_s * sfx,
qbool complain )

Referenced by S_MixToBuffer(), and S_PrecacheSound().

◆ S_MixToBuffer()

void S_MixToBuffer ( void * stream,
unsigned int frames )

Definition at line 369 of file snd_mix.c.

370{
371 int channelindex;
372 channel_t *ch;
373 int totalmixframes;
374 unsigned char *outbytes = (unsigned char *) stream;
375 sfx_t *sfx;
377 int wantframes;
378 int i;
379 int count;
380 int fetched;
381 int fetch;
382 int istartframe;
383 int iendframe;
384 int ilengthframes;
385 int totallength;
386 int loopstart;
387 int indexfrac;
388 int indexfracstep;
389#define S_FETCHBUFFERSIZE 4096
390 float fetchsampleframes[S_FETCHBUFFERSIZE*2];
391 const float *fetchsampleframe;
392 float vol[SND_LISTENERS];
393 float lerp[2];
394 float sample[3];
395 double posd;
396 double speedd;
397 float maxvol;
398 qbool looping;
399 qbool silent;
400
401 // mix as many times as needed to fill the requested buffer
402 while (bufferframes)
403 {
404 // limit to the size of the paint buffer
405 totalmixframes = min(bufferframes, PAINTBUFFER_SIZE);
406
407 // clear the paint buffer
408 memset(paintbuffer, 0, totalmixframes * sizeof(paintbuffer[0]));
409
410 // paint in the channels.
411 // channels with zero volumes still advance in time but don't paint.
412 ch = channels; // cppcheck complains here but it is wrong, channels is a channel_t[MAX_CHANNELS] and not an int
413 for (channelindex = 0;channelindex < (int)total_channels;channelindex++, ch++)
414 {
415 sfx = ch->sfx;
416 if (sfx == NULL)
417 continue;
418 if (!S_LoadSound (sfx, true))
419 continue;
420 if (ch->flags & CHANNELFLAG_PAUSED)
421 continue;
422 if (!sfx->total_length)
423 continue;
424
425 // copy the channel information to the stack for reference, otherwise the
426 // values might change during a mix if the spatializer is updating them
427 // (note: this still may get some old and some new values!)
428 posd = ch->position;
429 speedd = ch->mixspeed * sfx->format.speed / snd_renderbuffer->format.speed;
430 for (i = 0;i < SND_LISTENERS;i++)
431 vol[i] = ch->volume[i];
432
433 // check total volume level, because we can skip some code on silent sounds but other code must still run (position updates mainly)
434 maxvol = 0;
435 for (i = 0;i < SND_LISTENERS;i++)
436 if(vol[i] > maxvol)
437 maxvol = vol[i];
439 {
440 case 1: // 8bpp
441 silent = maxvol < (1.0f / (256.0f));
442 // so silent it has zero effect
443 break;
444 case 2: // 16bpp
445 silent = maxvol < (1.0f / (65536.0f));
446 // so silent it has zero effect
447 break;
448 default: // floating point
449 silent = maxvol < 1.0e-13f;
450 // 130 dB is difference between hearing
451 // threshold and a jackhammer from
452 // working distance.
453 // therefore, anyone who turns up
454 // volume so much they notice this
455 // cutoff, likely already has their
456 // ear-drums blown out anyway.
457 break;
458 }
459
460 // when doing prologic mixing, some channels invert one side
461 if (ch->prologic_invert == -1)
462 vol[1] *= -1.0f;
463
464 // get some sfx info in a consistent form
465 totallength = sfx->total_length;
466 loopstart = (int)sfx->loopstart < totallength ? (int)sfx->loopstart : ((ch->flags & CHANNELFLAG_FORCELOOP) ? 0 : totallength);
467 looping = loopstart < totallength;
468
469 // do the actual paint now (may skip work if silent)
470 paint = paintbuffer;
471 istartframe = 0;
472 for (wantframes = totalmixframes;wantframes > 0;posd += count * speedd, wantframes -= count)
473 {
474 // check if this is a delayed sound
475 if (posd < 0)
476 {
477 // for a delayed sound we have to eat into the delay first
478 count = (int)floor(-posd / speedd) + 1;
479 count = bound(1, count, wantframes);
480 // let the for loop iterator apply the skip
481 continue;
482 }
483
484 // compute a fetch size that won't overflow our buffer
485 count = wantframes;
486 for (;;)
487 {
488 istartframe = (int)floor(posd);
489 iendframe = (int)floor(posd + (count-1) * speedd);
490 ilengthframes = count > 1 ? (iendframe - istartframe + 2) : 2;
491 if (ilengthframes <= S_FETCHBUFFERSIZE)
492 break;
493 // reduce count by 25% and try again
494 count -= count >> 2;
495 }
496
497 // zero whole fetch buffer for safety
498 // (floating point noise from uninitialized memory = HORRIBLE)
499 // otherwise we would only need to clear the excess
500 if (!silent)
501 memset(fetchsampleframes, 0, ilengthframes*sfx->format.channels*sizeof(fetchsampleframes[0]));
502
503 // if looping, do multiple fetches
504 fetched = 0;
505 for (;;)
506 {
507 fetch = min(ilengthframes - fetched, totallength - istartframe);
508 if (fetch > 0)
509 {
510 if (!silent)
511 sfx->fetcher->getsamplesfloat(ch, sfx, istartframe, fetch, fetchsampleframes + fetched*sfx->format.channels);
512 istartframe += fetch;
513 fetched += fetch;
514 }
515 if (istartframe == totallength && looping && fetched < ilengthframes)
516 {
517 // loop and fetch some more
518 posd += loopstart - totallength;
519 istartframe = loopstart;
520 }
521 else
522 {
523 break;
524 }
525 }
526
527 // set up our fixedpoint resampling variables (float to int conversions are expensive so do not do one per sampleframe)
528 fetchsampleframe = fetchsampleframes;
529 indexfrac = (int)floor((posd - floor(posd)) * 65536.0);
530 indexfracstep = (int)floor(speedd * 65536.0);
531 if (!silent)
532 {
533 if (sfx->format.channels == 2)
534 {
535 // music is stereo
536#if SND_LISTENERS != 8
537#error the following code only supports up to 8 channels, update it
538#endif
540 {
541 // surround mixing
542 for (i = 0;i < count;i++, paint++)
543 {
544 lerp[1] = indexfrac * (1.0f / 65536.0f);
545 lerp[0] = 1.0f - lerp[1];
546 sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[2] * lerp[1];
547 sample[1] = fetchsampleframe[1] * lerp[0] + fetchsampleframe[3] * lerp[1];
548 sample[2] = (sample[0] + sample[1]) * 0.5f;
549 paint->sample[0] += sample[0] * vol[0];
550 paint->sample[1] += sample[1] * vol[1];
551 paint->sample[2] += sample[0] * vol[2];
552 paint->sample[3] += sample[1] * vol[3];
553 paint->sample[4] += sample[2] * vol[4];
554 paint->sample[5] += sample[2] * vol[5];
555 paint->sample[6] += sample[0] * vol[6];
556 paint->sample[7] += sample[1] * vol[7];
557 indexfrac += indexfracstep;
558 fetchsampleframe += 2 * (indexfrac >> 16);
559 indexfrac &= 0xFFFF;
560 }
561 }
562 else
563 {
564 // stereo mixing
565 for (i = 0;i < count;i++, paint++)
566 {
567 lerp[1] = indexfrac * (1.0f / 65536.0f);
568 lerp[0] = 1.0f - lerp[1];
569 sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[2] * lerp[1];
570 sample[1] = fetchsampleframe[1] * lerp[0] + fetchsampleframe[3] * lerp[1];
571 paint->sample[0] += sample[0] * vol[0];
572 paint->sample[1] += sample[1] * vol[1];
573 indexfrac += indexfracstep;
574 fetchsampleframe += 2 * (indexfrac >> 16);
575 indexfrac &= 0xFFFF;
576 }
577 }
578 }
579 else if (sfx->format.channels == 1)
580 {
581 // most sounds are mono
582#if SND_LISTENERS != 8
583#error the following code only supports up to 8 channels, update it
584#endif
586 {
587 // surround mixing
588 for (i = 0;i < count;i++, paint++)
589 {
590 lerp[1] = indexfrac * (1.0f / 65536.0f);
591 lerp[0] = 1.0f - lerp[1];
592 sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[1] * lerp[1];
593 paint->sample[0] += sample[0] * vol[0];
594 paint->sample[1] += sample[0] * vol[1];
595 paint->sample[2] += sample[0] * vol[2];
596 paint->sample[3] += sample[0] * vol[3];
597 paint->sample[4] += sample[0] * vol[4];
598 paint->sample[5] += sample[0] * vol[5];
599 paint->sample[6] += sample[0] * vol[6];
600 paint->sample[7] += sample[0] * vol[7];
601 indexfrac += indexfracstep;
602 fetchsampleframe += (indexfrac >> 16);
603 indexfrac &= 0xFFFF;
604 }
605 }
606 else
607 {
608 // stereo mixing
609 for (i = 0;i < count;i++, paint++)
610 {
611 lerp[1] = indexfrac * (1.0f / 65536.0f);
612 lerp[0] = 1.0f - lerp[1];
613 sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[1] * lerp[1];
614 paint->sample[0] += sample[0] * vol[0];
615 paint->sample[1] += sample[0] * vol[1];
616 indexfrac += indexfracstep;
617 fetchsampleframe += (indexfrac >> 16);
618 indexfrac &= 0xFFFF;
619 }
620 }
621 }
622 }
623 }
624 ch->position = posd;
625 if (!looping && istartframe == totallength)
626 S_StopChannel(ch - channels, false, false);
627 }
628
630
631 S_UnderwaterFilter(totalmixframes);
632
633
634#ifdef CONFIG_VIDEO_CAPTURE
636 S_CaptureAVISound(paintbuffer, totalmixframes);
637#endif
638
640
641 // advance the output pointer
642 outbytes += totalmixframes * snd_renderbuffer->format.width * snd_renderbuffer->format.channels;
643 bufferframes -= totalmixframes;
644 }
645}
static int(ZEXPORT *qz_inflate)(z_stream *strm
GLenum GLenum GLsizei count
Definition glquake.h:656
#define min(A, B)
Definition mathlib.h:37
#define bound(min, num, max)
Definition mathlib.h:34
float floor(float f)
int i
#define PAINTBUFFER_SIZE
Definition qdefs.h:151
#define NULL
Definition qtypes.h:12
bool qbool
Definition qtypes.h:9
unsigned int total_channels
Definition snd_main.c:129
void S_StopChannel(unsigned int channel_ind, qbool lockmutex, qbool freesfx)
Definition snd_main.c:1648
channel_t channels[MAX_CHANNELS]
Definition snd_main.c:128
snd_ringbuffer_t * snd_renderbuffer
Definition snd_main.c:131
qbool snd_usethreadedmixing
if true, the main thread does not mix sound, soundtime does not advance, and neither does snd_renderb...
Definition snd_main.c:137
qbool S_LoadSound(struct sfx_s *sfx, qbool complain)
#define SND_LISTENERS
Definition snd_main.h:84
static void S_UnderwaterFilter(int endtime)
Definition snd_mix.c:338
static void S_SoftClipPaintBuffer(portable_sampleframe_t *painted_ptr, int nbframes, int width, int nchannels)
Definition snd_mix.c:55
#define S_FETCHBUFFERSIZE
static portable_sampleframe_t paintbuffer[PAINTBUFFER_SIZE]
Definition snd_mix.c:26
speakerlayout_t snd_speakerlayout
Definition snd_main.c:44
static void S_ConvertPaintBuffer(portable_sampleframe_t *painted_ptr, void *rb_ptr, int nbframes, int width, int nchannels)
Definition snd_mix.c:129
#define CHANNELFLAG_FORCELOOP
Definition sound.h:39
#define CHANNELFLAG_PAUSED
Definition sound.h:41
unsigned int flags
cf CHANNELFLAG_* defines
Definition snd_main.h:91
int prologic_invert
whether a sound is played on the surround channels in prologic
Definition snd_main.h:97
float volume[SND_LISTENERS]
spatialized volume per speaker (mastervol * distanceattenuation * channelvolume cvars)
Definition snd_main.h:104
double position
updated ONLY by mixer position in sfx, starts at 0, loops or stops at sfx->total_length
Definition snd_main.h:108
struct sfx_s * sfx
pointer to sound sample being used
Definition snd_main.h:89
float mixspeed
these are often updated while mixer is running, glitching should be minimized (mismatched channel vol...
Definition snd_main.h:102
exported for capturevideo so ogg can see all channels
Definition snd_main.h:196
float sample[SND_LISTENERS]
Definition snd_main.h:197
unsigned int speed
Definition snd_main.h:32
unsigned short channels
Definition snd_main.h:34
unsigned short width
Definition snd_main.h:33
snd_format_t format
Definition snd_main.h:47
unsigned int channels
Definition snd_main.h:212

References bound, CHANNELFLAG_FORCELOOP, CHANNELFLAG_PAUSED, channels, snd_format_t::channels, speakerlayout_t::channels, count, channel_t::flags, floor(), snd_ringbuffer_t::format, i, int(), min, channel_t::mixspeed, NULL, paintbuffer, PAINTBUFFER_SIZE, channel_t::position, channel_t::prologic_invert, S_ConvertPaintBuffer(), S_FETCHBUFFERSIZE, S_LoadSound(), S_SoftClipPaintBuffer(), S_StopChannel(), S_UnderwaterFilter(), portable_sampleframe_t::sample, channel_t::sfx, SND_LISTENERS, snd_renderbuffer, snd_speakerlayout, snd_usethreadedmixing, snd_format_t::speed, total_channels, channel_t::volume, and snd_format_t::width.

Referenced by Buffer_Callback(), and S_PaintAndSubmit().

◆ S_SetUnderwaterIntensity()

void S_SetUnderwaterIntensity ( void )

Definition at line 320 of file snd_mix.c.

321{
322 float target = cl.view_underwater ? bound(0.f, snd_waterfx.value, 2.f) : 0.f;
323
324 if (underwater.intensity < target)
325 {
326 underwater.intensity += cl.realframetime * 4.f;
327 underwater.intensity = min(underwater.intensity, target);
328 }
329 else if (underwater.intensity > target)
330 {
331 underwater.intensity -= cl.realframetime * 4.f;
332 underwater.intensity = max(underwater.intensity, target);
333 }
334
335 underwater.alpha = underwater.intensity ? exp(-underwater.intensity * log(12.f)) : 1.f;
336}
client_state_t cl
Definition cl_main.c:117
float log(float f)
#define max(A, B)
Definition mathlib.h:38
string target
Definition progsdefs.qc:193
cvar_t snd_waterfx
Definition snd_main.c:173
static struct @33 underwater
double realframetime
Definition client.h:871
qbool view_underwater
Definition client.h:1139
float value
Definition cvar.h:74

References bound, cl, log(), max, min, client_state_t::realframetime, snd_waterfx, target, underwater, cvar_t::value, and client_state_t::view_underwater.

Referenced by S_UpdateAmbientSounds().

◆ Snd_CreateRingBuffer()

snd_ringbuffer_t * Snd_CreateRingBuffer ( const snd_format_t * format,
unsigned int sampleframes,
void * buffer )

If "buffer" is NULL, the function allocates one buffer of "sampleframes" sample frames itself (if "sampleframes" is 0, the function chooses the size).

Definition at line 43 of file snd_mem.c.

44{
45 snd_ringbuffer_t *ringbuffer;
46
47 // If the caller provides a buffer, it must give us its size
48 if (sampleframes == 0 && buffer != NULL)
49 return NULL;
50
51 ringbuffer = (snd_ringbuffer_t*)Mem_Alloc(snd_mempool, sizeof (*ringbuffer));
52 memset(ringbuffer, 0, sizeof(*ringbuffer));
53 memcpy(&ringbuffer->format, format, sizeof(ringbuffer->format));
54
55 // If we haven't been given a buffer
56 if (buffer == NULL)
57 {
58 unsigned int maxframes;
59 size_t memsize;
60
61 if (sampleframes == 0)
62 maxframes = (format->speed + 1) / 2; // Make the sound buffer large enough for containing 0.5 sec of sound
63 else
64 maxframes = sampleframes;
65
66 memsize = maxframes * format->width * format->channels;
67 ringbuffer->ring = (unsigned char *) Mem_Alloc(snd_mempool, memsize);
68 ringbuffer->maxframes = maxframes;
69 }
70 else
71 {
72 ringbuffer->ring = (unsigned char *) buffer;
73 ringbuffer->maxframes = sampleframes;
74 }
75
76 return ringbuffer;
77}
GLuint buffer
Definition glquake.h:630
GLint GLint GLint GLsizei GLsizei GLenum format
Definition glquake.h:649
mempool_t * snd_mempool
Definition snd_main.c:144
unsigned char * ring
Definition snd_main.h:48
unsigned int maxframes
max size (buffer size), in sample frames
Definition snd_main.h:49
#define Mem_Alloc(pool, size)
Definition zone.h:92

References buffer, format, snd_ringbuffer_t::format, snd_ringbuffer_t::maxframes, Mem_Alloc, NULL, snd_ringbuffer_t::ring, and snd_mempool.

Referenced by S_Startup(), and SndSys_Init().

◆ SndSys_GetSoundTime()

unsigned int SndSys_GetSoundTime ( void )

Returns the number of sample frames consumed since the sound started.

Definition at line 209 of file snd_sdl.c.

210{
211 return sdlaudiotime;
212}
static unsigned int sdlaudiotime
Definition snd_sdl.c:28

References sdlaudiotime.

Referenced by S_PaintAndSubmit().

◆ SndSys_Init()

qbool SndSys_Init ( snd_format_t * fmt)

Create "snd_renderbuffer", attempting to use the chosen sound format, but accepting if the driver wants to change it (e.g.

7.1 to stereo or lowering the speed) Note: SDL automatically converts all formats, so this only fails if there is no audio

Definition at line 103 of file snd_sdl.c.

104{
105 unsigned int buffersize;
106 SDL_AudioSpec wantspec;
107 SDL_AudioSpec obtainspec;
108
109 snd_threaded = false;
110
111 Con_DPrint ("SndSys_Init: using the SDL module\n");
112
113 // Init the SDL Audio subsystem
114 if( SDL_InitSubSystem( SDL_INIT_AUDIO ) ) {
115 Con_Print( "Initializing the SDL Audio subsystem failed!\n" );
116 return false;
117 }
118
119 // SDL2 wiki recommends this range
120 buffersize = bound(512, ceil((double)fmt->speed * snd_bufferlength.value / 1000.0), 8192);
121
122 // Init the SDL Audio subsystem
123 memset(&wantspec, 0, sizeof(wantspec));
124 wantspec.callback = Buffer_Callback;
125 wantspec.userdata = NULL;
126 wantspec.freq = fmt->speed;
127 wantspec.format = fmt->width == 1 ? AUDIO_U8 : (fmt->width == 2 ? AUDIO_S16SYS : AUDIO_F32);
128 wantspec.channels = fmt->channels;
129 wantspec.samples = CeilPowerOf2(buffersize); // needs to be a power of 2 on some platforms.
130
131 Con_Printf("Wanted audio Specification:\n"
132 " Channels : %i\n"
133 " Format : 0x%X\n"
134 " Frequency : %i\n"
135 " Samples : %i\n",
136 wantspec.channels, wantspec.format, wantspec.freq, wantspec.samples);
137
138 if ((audio_device = SDL_OpenAudioDevice(NULL, 0, &wantspec, &obtainspec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE)) == 0)
139 {
140 Con_Printf(CON_ERROR "Failed to open the audio device! (%s)\n", SDL_GetError() );
141 return false;
142 }
143
144 Con_Printf("Obtained audio specification:\n"
145 " Channels : %i\n"
146 " Format : 0x%X\n"
147 " Frequency : %i\n"
148 " Samples : %i\n",
149 obtainspec.channels, obtainspec.format, obtainspec.freq, obtainspec.samples);
150
151 fmt->speed = obtainspec.freq;
152 fmt->channels = obtainspec.channels;
153
154 snd_threaded = true;
155
159
160 sdlaudiotime = 0;
161 SDL_PauseAudioDevice(audio_device, 0);
162
163 return true;
164}
void Con_Print(const char *msg)
Prints to all appropriate console targets, and adds timestamps.
Definition console.c:1504
void Con_Printf(const char *fmt,...)
Prints to all appropriate console targets.
Definition console.c:1514
void Con_DPrint(const char *msg)
A Con_Print that only shows up if the "developer" cvar is set.
Definition console.c:1531
#define CON_ERROR
Definition console.h:102
void Cvar_SetValueQuick(cvar_t *var, float value)
Definition cvar.c:473
unsigned int CeilPowerOf2(unsigned int value)
returns the smallest integer greater than or equal to "value", or 0 if "value" is too big
Definition mathlib.c:292
float ceil(float f)
qbool snd_threaded
enables use of snd_usethreadedmixing, provided that no sound hacks are in effect (like timedemo)
Definition snd_main.c:136
cvar_t snd_channellayout
Definition snd_main.c:170
cvar_t snd_bufferlength
Definition snd_main.c:248
#define SND_CHANNELLAYOUT_STANDARD
Definition snd_main.h:135
snd_ringbuffer_t * Snd_CreateRingBuffer(const snd_format_t *format, unsigned int sampleframes, void *buffer)
If "buffer" is NULL, the function allocates one buffer of "sampleframes" sample frames itself (if "sa...
Definition snd_mem.c:43
#define SND_CHANNELLAYOUT_AUTO
Definition snd_main.h:134
static int audio_device
Definition snd_sdl.c:29
static void Buffer_Callback(void *userdata, Uint8 *stream, int len)
Definition snd_sdl.c:34
int integer
Definition cvar.h:73

References audio_device, bound, Buffer_Callback(), ceil(), CeilPowerOf2(), snd_format_t::channels, Con_DPrint(), CON_ERROR, Con_Print(), Con_Printf(), Cvar_SetValueQuick(), cvar_t::integer, NULL, sdlaudiotime, snd_bufferlength, snd_channellayout, SND_CHANNELLAYOUT_AUTO, SND_CHANNELLAYOUT_STANDARD, Snd_CreateRingBuffer(), snd_renderbuffer, snd_threaded, snd_format_t::speed, cvar_t::value, and snd_format_t::width.

Referenced by S_Startup().

◆ SndSys_LockRenderBuffer()

qbool SndSys_LockRenderBuffer ( void )

Get the exclusive lock on "snd_renderbuffer".

Definition at line 222 of file snd_sdl.c.

223{
224 SDL_LockAudioDevice(audio_device);
225 return true;
226}

References audio_device.

Referenced by S_PaintAndSubmit(), S_StopAllSounds(), and S_StopChannel().

◆ SndSys_SendKeyEvents()

void SndSys_SendKeyEvents ( void )

if the sound system can generate events, send them

Definition at line 150 of file snd_null.c.

151{
152}

◆ SndSys_Shutdown()

void SndSys_Shutdown ( void )

Stop the sound card, delete "snd_renderbuffer" and free its other resources.

Definition at line 174 of file snd_sdl.c.

175{
176 if (audio_device > 0) {
177 SDL_CloseAudioDevice(audio_device);
178 audio_device = 0;
179 }
180 if (snd_renderbuffer != NULL)
181 {
185 }
186}
#define Mem_Free(mem)
Definition zone.h:96

References audio_device, Mem_Free, NULL, snd_ringbuffer_t::ring, and snd_renderbuffer.

Referenced by S_Shutdown().

◆ SndSys_Submit()

void SndSys_Submit ( void )

Submit the contents of "snd_renderbuffer" to the sound card.

Definition at line 196 of file snd_sdl.c.

197{
198 // Nothing to do here (this sound module is callback-based)
199}

Referenced by S_PaintAndSubmit().

◆ SndSys_UnlockRenderBuffer()

void SndSys_UnlockRenderBuffer ( void )

Release the exclusive lock on "snd_renderbuffer".

Definition at line 236 of file snd_sdl.c.

237{
238 SDL_UnlockAudioDevice(audio_device);
239}

References audio_device.

Referenced by S_PaintAndSubmit(), S_StopAllSounds(), and S_StopChannel().

Variable Documentation

◆ channels

◆ simsound

qbool simsound
extern

If simsound is true, the sound card is not initialized and no sound is submitted to it.

More generally, all arch-dependent operations are skipped or emulated. Used for isolating performance in the renderer.

Definition at line 149 of file snd_main.c.

Referenced by S_Init(), S_PaintAndSubmit(), S_Shutdown(), S_Startup(), S_StopAllSounds(), and S_StopChannel().

◆ snd_blocked

bool snd_blocked
extern

When true, we submit silence to the audio device.

Definition at line 155 of file snd_main.c.

Referenced by Buffer_Callback(), S_PaintAndSubmit(), and S_Update().

◆ snd_bufferlength

cvar_t snd_bufferlength
extern

Definition at line 248 of file snd_main.c.

248{CF_CLIENT | CF_ARCHIVE, "snd_bufferlength", "20", "Desired length of the SDL2 audio buffer in milliseconds, smaller values reduce latency but can lead to underflow if the system is heavily loaded. Affects only how many sample frames are requested (which will be a power of 2 between 512 and 8192 inclusive)"};
#define CF_CLIENT
cvar/command that only the client can change/execute
Definition cmd.h:48
#define CF_ARCHIVE
cvar should have its set value saved to config.cfg and persist across sessions
Definition cmd.h:53

Referenced by S_Init(), and SndSys_Init().

◆ snd_channellayout

cvar_t snd_channellayout
extern

Definition at line 170 of file snd_main.c.

170{CF_CLIENT, "snd_channellayout", "0", "channel layout. Can be 0 (auto - snd_restart needed), 1 (standard layout), or 2 (ALSA layout)"};

Referenced by S_Init(), S_SetChannelLayout(), S_Update(), and SndSys_Init().

◆ snd_mempool

◆ snd_renderbuffer

◆ snd_streaming

cvar_t snd_streaming
extern

Definition at line 171 of file snd_main.c.

171{CF_CLIENT | CF_ARCHIVE, "snd_streaming", "1", "enables keeping compressed ogg sound files compressed, decompressing them only as needed, otherwise they will be decompressed completely at load (may use a lot of memory); when set to 2, streaming is performed even if this would waste memory"};

Referenced by OGG_LoadVorbisFile(), and S_Init().

◆ snd_streaming_length

cvar_t snd_streaming_length
extern

Definition at line 172 of file snd_main.c.

172{CF_CLIENT | CF_ARCHIVE, "snd_streaming_length", "1", "decompress sounds completely if they are less than this play time when snd_streaming is 1"};

Referenced by OGG_LoadVorbisFile(), and S_Init().

◆ snd_threaded

qbool snd_threaded
extern

enables use of snd_usethreadedmixing, provided that no sound hacks are in effect (like timedemo)

Definition at line 136 of file snd_main.c.

Referenced by S_PaintAndSubmit(), and SndSys_Init().

◆ snd_usethreadedmixing

qbool snd_usethreadedmixing
extern

if true, the main thread does not mix sound, soundtime does not advance, and neither does snd_renderbuffer->endframe, instead the audio thread will call S_MixToBuffer as needed

Definition at line 137 of file snd_main.c.

Referenced by Buffer_Callback(), S_MixToBuffer(), and S_PaintAndSubmit().

◆ snd_waterfx

cvar_t snd_waterfx
extern

Definition at line 173 of file snd_main.c.

173{CF_CLIENT | CF_ARCHIVE, "snd_waterfx", "1", "underwater sound filter strength"};

Referenced by S_Init(), and S_SetUnderwaterIntensity().

◆ total_channels