DarkPlaces
Game engine based on the Quake 1 engine by id Software, developed by LadyHavoc
 
snd_sdl.c File Reference
#include <math.h>
#include <SDL.h>
#include "darkplaces.h"
#include "vid.h"
#include "snd_main.h"
+ Include dependency graph for snd_sdl.c:

Go to the source code of this file.

Functions

static void Buffer_Callback (void *userdata, Uint8 *stream, int len)
 
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

static int audio_device = 0
 
static unsigned int sdlaudiotime = 0
 

Function Documentation

◆ Buffer_Callback()

static void Buffer_Callback ( void * userdata,
Uint8 * stream,
int len )
static

Definition at line 34 of file snd_sdl.c.

35{
36 unsigned int factor, RequestedFrames, MaxFrames, FrameCount;
37 unsigned int StartOffset, EndOffset;
38
40 if ((unsigned int)len % factor != 0)
41 Sys_Error("SDL sound: invalid buffer length passed to Buffer_Callback (%d bytes)\n", len);
42
43 RequestedFrames = (unsigned int)len / factor;
44
46 {
47 S_MixToBuffer(stream, RequestedFrames);
48 if (snd_blocked)
49 memset(stream, snd_renderbuffer->format.width == 1 ? 0x80 : 0, len);
50 return;
51 }
52
53 // Transfert up to a chunk of samples from snd_renderbuffer to stream
55 if (MaxFrames > RequestedFrames)
56 FrameCount = RequestedFrames;
57 else
58 FrameCount = MaxFrames;
60 EndOffset = (snd_renderbuffer->startframe + FrameCount) % snd_renderbuffer->maxframes;
61 if (snd_blocked)
62 memset(stream, snd_renderbuffer->format.width == 1 ? 0x80 : 0, len);
63 else if (StartOffset > EndOffset) // if the buffer wraps
64 {
65 unsigned int PartialLength1, PartialLength2;
66
67 PartialLength1 = (snd_renderbuffer->maxframes - StartOffset) * factor;
68 memcpy(stream, &snd_renderbuffer->ring[StartOffset * factor], PartialLength1);
69
70 PartialLength2 = FrameCount * factor - PartialLength1;
71 memcpy(&stream[PartialLength1], &snd_renderbuffer->ring[0], PartialLength2);
72
73 // As of SDL 2.0 buffer needs to be fully initialized, so fill leftover part with silence
74 // FIXME this is another place that assumes 8bit is always unsigned and others always signed
75 memset(&stream[PartialLength1 + PartialLength2], snd_renderbuffer->format.width == 1 ? 0x80 : 0, len - (PartialLength1 + PartialLength2));
76 }
77 else
78 {
79 memcpy(stream, &snd_renderbuffer->ring[StartOffset * factor], FrameCount * factor);
80
81 // As of SDL 2.0 buffer needs to be fully initialized, so fill leftover part with silence
82 // FIXME this is another place that assumes 8bit is always unsigned and others always signed
83 memset(&stream[FrameCount * factor], snd_renderbuffer->format.width == 1 ? 0x80 : 0, len - (FrameCount * factor));
84 }
85
86 snd_renderbuffer->startframe += FrameCount;
87
88 if (FrameCount < RequestedFrames && developer_insane.integer && vid_activewindow)
89 Con_DPrintf("SDL sound: %u sample frames missing\n", RequestedFrames - FrameCount);
90
91 sdlaudiotime += RequestedFrames;
92}
void Con_DPrintf(const char *fmt,...)
A Con_Printf that only shows up if the "developer" cvar is set.
Definition console.c:1544
static int(ZEXPORT *qz_inflate)(z_stream *strm
cvar_t developer_insane
Definition host.c:50
bool snd_blocked
When true, we submit silence to the audio device.
Definition snd_main.c:155
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
void S_MixToBuffer(void *stream, unsigned int frames)
Definition snd_mix.c:369
static unsigned int sdlaudiotime
Definition snd_sdl.c:28
int integer
Definition cvar.h:73
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 char * ring
Definition snd_main.h:48
unsigned int startframe
index of the first frame in the buffer if startframe == endframe, the bufffer is empty
Definition snd_main.h:52
unsigned int maxframes
max size (buffer size), in sample frames
Definition snd_main.h:49
unsigned int endframe
index of the first EMPTY frame in the "ring" buffer may be smaller than startframe if the "ring" buff...
Definition snd_main.h:55
void Sys_Error(const char *error,...) DP_FUNC_PRINTF(1) DP_FUNC_NORETURN
Causes the entire program to exit ASAP.
Definition sys_shared.c:724
qbool vid_activewindow
Definition vid_shared.c:77

References snd_format_t::channels, Con_DPrintf(), developer_insane, snd_ringbuffer_t::endframe, snd_ringbuffer_t::format, int(), cvar_t::integer, snd_ringbuffer_t::maxframes, snd_ringbuffer_t::ring, S_MixToBuffer(), sdlaudiotime, snd_blocked, snd_renderbuffer, snd_usethreadedmixing, snd_ringbuffer_t::startframe, Sys_Error(), vid_activewindow, and snd_format_t::width.

Referenced by 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}

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
#define bound(min, num, max)
Definition mathlib.h:34
float ceil(float f)
#define NULL
Definition qtypes.h:12
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
float value
Definition cvar.h:74
unsigned int speed
Definition snd_main.h:32

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 248 of file snd_sdl.c.

249{
250 // not supported
251}

◆ 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

◆ audio_device

int audio_device = 0
static

◆ sdlaudiotime

unsigned int sdlaudiotime = 0
static

Definition at line 28 of file snd_sdl.c.

Referenced by Buffer_Callback(), SndSys_GetSoundTime(), and SndSys_Init().