2004-12-09 23:37:29 +00:00
|
|
|
#include "quakedef.h"
|
2004-12-24 08:45:56 +00:00
|
|
|
#include "winquake.h"
|
|
|
|
|
|
|
|
#include <SDL.h>
|
2013-04-13 08:15:18 +00:00
|
|
|
|
|
|
|
#define SELFPAINT
|
2004-12-24 08:45:56 +00:00
|
|
|
|
2005-11-07 00:59:22 +00:00
|
|
|
//SDL calls a callback each time it needs to repaint the 'hardware' buffers
|
|
|
|
//This results in extra latency.
|
|
|
|
//SDL runs does this multithreaded.
|
|
|
|
//So we tell it a fairly pathetically sized buffer and try and get it to copy often
|
|
|
|
//hopefully this lowers sound latency, and has no suddenly starting sounds and stuff.
|
|
|
|
//It still has greater latency than direct access, of course.
|
|
|
|
|
|
|
|
//FIXME: One thing I saw in quakeforge was that quakeforge basically leaves the audio locked except for a really short period of time.
|
|
|
|
//An interesting idea, which ensures the driver can only paint in a small time-frame. this would possibly allow lower latency painting.
|
2004-12-24 08:45:56 +00:00
|
|
|
|
2005-06-14 04:52:10 +00:00
|
|
|
static void SSDL_Shutdown(soundcardinfo_t *sc)
|
2004-12-09 23:37:29 +00:00
|
|
|
{
|
2013-04-13 08:15:18 +00:00
|
|
|
Con_DPrintf("Shutdown SDL sound\n");
|
2005-06-14 04:52:10 +00:00
|
|
|
SDL_CloseAudio();
|
2013-04-13 08:15:18 +00:00
|
|
|
#ifndef SELFPAINT
|
2005-06-14 04:52:10 +00:00
|
|
|
if (sc->sn.buffer)
|
|
|
|
free(sc->sn.buffer);
|
2013-04-13 08:15:18 +00:00
|
|
|
#endif
|
2005-06-14 04:52:10 +00:00
|
|
|
sc->sn.buffer = NULL;
|
2004-12-09 23:37:29 +00:00
|
|
|
}
|
2005-06-14 04:52:10 +00:00
|
|
|
static unsigned int SSDL_GetDMAPos(soundcardinfo_t *sc)
|
2004-12-09 23:37:29 +00:00
|
|
|
{
|
2010-03-14 14:35:56 +00:00
|
|
|
sc->sn.samplepos = sc->snd_sent / (sc->sn.samplebits/8);
|
2005-01-12 08:38:31 +00:00
|
|
|
return sc->sn.samplepos;
|
|
|
|
}
|
|
|
|
|
2005-06-14 04:52:10 +00:00
|
|
|
//this function is called from inside SDL.
|
|
|
|
//transfer the 'dma' buffer into the buffer it requests.
|
2010-03-14 14:35:56 +00:00
|
|
|
static void VARGS SSDL_Paint(void *userdata, qbyte *stream, int len)
|
2005-01-12 08:38:31 +00:00
|
|
|
{
|
2005-06-14 04:52:10 +00:00
|
|
|
soundcardinfo_t *sc = userdata;
|
|
|
|
|
2013-04-13 08:15:18 +00:00
|
|
|
#ifdef SELFPAINT
|
|
|
|
sc->sn.buffer = stream;
|
|
|
|
sc->sn.samples = len / (sc->sn.samplebits/8);
|
|
|
|
sc->samplequeue = sc->sn.samples;
|
|
|
|
S_MixerThread(sc);
|
|
|
|
sc->snd_sent += len;
|
|
|
|
#else
|
2013-05-03 04:28:08 +00:00
|
|
|
int buffersize = sc->sn.samples*(sc->sn.samplebits/8);
|
|
|
|
|
2005-11-07 00:59:22 +00:00
|
|
|
if (len > buffersize)
|
|
|
|
{
|
|
|
|
len = buffersize; //whoa nellie!
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len + sc->snd_sent%buffersize > buffersize)
|
2005-01-12 08:38:31 +00:00
|
|
|
{ //buffer will wrap, fill in the rest
|
2005-11-07 00:59:22 +00:00
|
|
|
memcpy(stream, (char*)sc->sn.buffer + (sc->snd_sent%buffersize), buffersize - (sc->snd_sent%buffersize));
|
|
|
|
stream += buffersize - sc->snd_sent%buffersize;
|
2010-12-13 23:13:16 +00:00
|
|
|
sc->snd_sent += buffersize - sc->snd_sent%buffersize;
|
2005-11-07 00:59:22 +00:00
|
|
|
len -= buffersize - (sc->snd_sent%buffersize);
|
|
|
|
if (len < 0)
|
|
|
|
return;
|
2005-01-12 08:38:31 +00:00
|
|
|
} //and finish from the start
|
2005-11-07 00:59:22 +00:00
|
|
|
memcpy(stream, (char*)sc->sn.buffer + (sc->snd_sent%buffersize), len);
|
2005-06-14 04:52:10 +00:00
|
|
|
sc->snd_sent += len;
|
2013-04-13 08:15:18 +00:00
|
|
|
#endif
|
2005-06-14 04:52:10 +00:00
|
|
|
}
|
|
|
|
|
2012-04-09 19:12:12 +00:00
|
|
|
static void *SSDL_LockBuffer(soundcardinfo_t *sc, unsigned int *sampidx)
|
2005-06-14 04:52:10 +00:00
|
|
|
{
|
|
|
|
SDL_LockAudio();
|
2005-11-07 00:59:22 +00:00
|
|
|
|
2005-06-14 04:52:10 +00:00
|
|
|
return sc->sn.buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SSDL_UnlockBuffer(soundcardinfo_t *sc, void *buffer)
|
|
|
|
{
|
|
|
|
SDL_UnlockAudio();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SSDL_SetUnderWater(soundcardinfo_t *sc, qboolean uw)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-26 16:46:43 +00:00
|
|
|
static void SSDL_Submit(soundcardinfo_t *sc, int start, int end)
|
2005-06-14 04:52:10 +00:00
|
|
|
{
|
|
|
|
//SDL will call SSDL_Paint to paint when it's time, and the sound buffer is always there...
|
2004-12-09 23:37:29 +00:00
|
|
|
}
|
|
|
|
|
2005-06-14 04:52:10 +00:00
|
|
|
static int SDL_InitCard(soundcardinfo_t *sc, int cardnum)
|
2004-12-09 23:37:29 +00:00
|
|
|
{
|
2004-12-24 08:45:56 +00:00
|
|
|
SDL_AudioSpec desired, obtained;
|
|
|
|
|
2005-06-14 04:52:10 +00:00
|
|
|
if (cardnum)
|
2005-01-12 08:38:31 +00:00
|
|
|
{ //our init code actually calls this function multiple times, in the case that the user has multiple sound cards
|
|
|
|
return 2; //erm. SDL won't allow multiple sound cards anyway.
|
|
|
|
}
|
2005-06-14 04:52:10 +00:00
|
|
|
|
2005-11-07 00:59:22 +00:00
|
|
|
Con_Printf("Initing SDL audio.\n");
|
|
|
|
|
2005-02-09 19:32:09 +00:00
|
|
|
if(SDL_InitSubSystem(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE))
|
2004-12-24 08:45:56 +00:00
|
|
|
{
|
2005-09-26 08:07:26 +00:00
|
|
|
Con_Printf("Couldn't initialize SDL audio subsystem\n");
|
2004-12-24 08:45:56 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&desired, 0, sizeof(desired));
|
|
|
|
|
|
|
|
desired.freq = sc->sn.speed;
|
2010-03-14 14:35:56 +00:00
|
|
|
desired.channels = sc->sn.numchannels; //fixme!
|
2013-04-13 08:15:18 +00:00
|
|
|
desired.samples = 0x0200; //'Good values seem to range between 512 and 8192 inclusive, depending on the application and CPU speed.'
|
2005-11-07 00:59:22 +00:00
|
|
|
desired.format = AUDIO_S16SYS;
|
2010-08-28 17:14:38 +00:00
|
|
|
desired.callback = (void*)SSDL_Paint;
|
2005-06-14 04:52:10 +00:00
|
|
|
desired.userdata = sc;
|
2005-11-07 00:59:22 +00:00
|
|
|
memcpy(&obtained, &desired, sizeof(obtained));
|
2005-01-12 08:38:31 +00:00
|
|
|
|
2013-04-02 05:18:17 +00:00
|
|
|
#ifdef FTE_TARGET_WEB
|
|
|
|
if ( SDL_OpenAudio(&desired, NULL) < 0 )
|
|
|
|
{
|
|
|
|
Con_Printf("SDL: SNDDMA_Init: couldn't open sound device (%s).\n", SDL_GetError());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
obtained = desired;
|
|
|
|
#else
|
2004-12-24 08:45:56 +00:00
|
|
|
if ( SDL_OpenAudio(&desired, &obtained) < 0 )
|
|
|
|
{
|
|
|
|
Con_Printf("SDL: SNDDMA_Init: couldn't open sound device (%s).\n", SDL_GetError());
|
|
|
|
return false;
|
|
|
|
}
|
2013-04-02 05:18:17 +00:00
|
|
|
#endif
|
2005-01-12 08:38:31 +00:00
|
|
|
sc->sn.numchannels = obtained.channels;
|
2005-11-01 23:25:15 +00:00
|
|
|
sc->sn.speed = obtained.freq;
|
2005-11-07 00:59:22 +00:00
|
|
|
sc->sn.samplebits = obtained.format&0xff;
|
|
|
|
sc->sn.samples = 32768;//*sc->sn.numchannels; //doesn't really matter, so long as it's higher than obtained.samples
|
|
|
|
|
2013-04-13 08:15:18 +00:00
|
|
|
#ifdef SELFPAINT
|
|
|
|
sc->selfpainting = true;
|
|
|
|
#endif
|
|
|
|
|
2005-11-07 00:59:22 +00:00
|
|
|
Con_DPrintf("channels: %i\n", sc->sn.numchannels);
|
|
|
|
Con_DPrintf("Speed: %i\n", sc->sn.speed);
|
|
|
|
Con_DPrintf("Samplebits: %i\n", sc->sn.samplebits);
|
|
|
|
Con_DPrintf("SDLSamples: %i (low for latency)\n", obtained.samples);
|
|
|
|
Con_DPrintf("FakeSamples: %i\n", sc->sn.samples);
|
|
|
|
|
2013-04-13 08:15:18 +00:00
|
|
|
#ifndef SELFPAINT
|
2005-11-07 00:59:22 +00:00
|
|
|
sc->sn.buffer = malloc(sc->sn.samples*sc->sn.samplebits/8);
|
2013-04-13 08:15:18 +00:00
|
|
|
#endif
|
2005-11-07 00:59:22 +00:00
|
|
|
Con_DPrintf("Got sound %i-%i\n", obtained.freq, obtained.format);
|
2004-12-09 23:37:29 +00:00
|
|
|
|
2005-06-14 04:52:10 +00:00
|
|
|
sc->Lock = SSDL_LockBuffer;
|
|
|
|
sc->Unlock = SSDL_UnlockBuffer;
|
|
|
|
sc->SetWaterDistortion = SSDL_SetUnderWater;
|
|
|
|
sc->Submit = SSDL_Submit;
|
|
|
|
sc->Shutdown = SSDL_Shutdown;
|
|
|
|
sc->GetDMAPos = SSDL_GetDMAPos;
|
|
|
|
|
2005-11-07 00:59:22 +00:00
|
|
|
SDL_PauseAudio(0);
|
|
|
|
|
2005-06-14 04:52:10 +00:00
|
|
|
return true;
|
2004-12-09 23:37:29 +00:00
|
|
|
}
|
2005-01-12 08:38:31 +00:00
|
|
|
|
2005-06-14 04:52:10 +00:00
|
|
|
sounddriver pSDL_InitCard = &SDL_InitCard;
|
2005-11-07 00:59:22 +00:00
|
|
|
|