ffc2a08589
Added version+time+date to segfault lots. try to use vbo+vao as needed. added a manifest file in order to disable uac emulation and its virtual store lies. particles now support a sort of namespace. eg: an effect called "cfg.effect" will load up the 'cfg' particle config and use its 'effect' effect (but not replace any explicit effects). You can still create particle effects called 'cfg.effect' with no issue. Added support for fsarchive plugins. Added a sys_register_file_associations command. .bsp not yet handled, but demo playback should work fine. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4324 fc73d0e0-1445-4013-8a0c-d673dee63da5
164 lines
4.6 KiB
C
164 lines
4.6 KiB
C
#include "quakedef.h"
|
|
#include "winquake.h"
|
|
|
|
#include <SDL.h>
|
|
|
|
#define SELFPAINT
|
|
|
|
//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.
|
|
|
|
static void SSDL_Shutdown(soundcardinfo_t *sc)
|
|
{
|
|
Con_DPrintf("Shutdown SDL sound\n");
|
|
SDL_CloseAudio();
|
|
#ifndef SELFPAINT
|
|
if (sc->sn.buffer)
|
|
free(sc->sn.buffer);
|
|
#endif
|
|
sc->sn.buffer = NULL;
|
|
}
|
|
static unsigned int SSDL_GetDMAPos(soundcardinfo_t *sc)
|
|
{
|
|
sc->sn.samplepos = sc->snd_sent / (sc->sn.samplebits/8);
|
|
return sc->sn.samplepos;
|
|
}
|
|
|
|
//this function is called from inside SDL.
|
|
//transfer the 'dma' buffer into the buffer it requests.
|
|
static void VARGS SSDL_Paint(void *userdata, qbyte *stream, int len)
|
|
{
|
|
soundcardinfo_t *sc = userdata;
|
|
|
|
#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
|
|
int buffersize = sc->sn.samples*(sc->sn.samplebits/8);
|
|
|
|
if (len > buffersize)
|
|
{
|
|
len = buffersize; //whoa nellie!
|
|
}
|
|
|
|
if (len + sc->snd_sent%buffersize > buffersize)
|
|
{ //buffer will wrap, fill in the rest
|
|
memcpy(stream, (char*)sc->sn.buffer + (sc->snd_sent%buffersize), buffersize - (sc->snd_sent%buffersize));
|
|
stream += buffersize - sc->snd_sent%buffersize;
|
|
sc->snd_sent += buffersize - sc->snd_sent%buffersize;
|
|
len -= buffersize - (sc->snd_sent%buffersize);
|
|
if (len < 0)
|
|
return;
|
|
} //and finish from the start
|
|
memcpy(stream, (char*)sc->sn.buffer + (sc->snd_sent%buffersize), len);
|
|
sc->snd_sent += len;
|
|
#endif
|
|
}
|
|
|
|
static void *SSDL_LockBuffer(soundcardinfo_t *sc, unsigned int *sampidx)
|
|
{
|
|
SDL_LockAudio();
|
|
|
|
return sc->sn.buffer;
|
|
}
|
|
|
|
static void SSDL_UnlockBuffer(soundcardinfo_t *sc, void *buffer)
|
|
{
|
|
SDL_UnlockAudio();
|
|
}
|
|
|
|
static void SSDL_SetUnderWater(soundcardinfo_t *sc, qboolean uw)
|
|
{
|
|
}
|
|
|
|
|
|
static void SSDL_Submit(soundcardinfo_t *sc, int start, int end)
|
|
{
|
|
//SDL will call SSDL_Paint to paint when it's time, and the sound buffer is always there...
|
|
}
|
|
|
|
static int SDL_InitCard(soundcardinfo_t *sc, int cardnum)
|
|
{
|
|
SDL_AudioSpec desired, obtained;
|
|
|
|
if (cardnum)
|
|
{ //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.
|
|
}
|
|
|
|
Con_Printf("Initing SDL audio.\n");
|
|
|
|
if(SDL_InitSubSystem(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE))
|
|
{
|
|
Con_Printf("Couldn't initialize SDL audio subsystem\n");
|
|
return false;
|
|
}
|
|
|
|
memset(&desired, 0, sizeof(desired));
|
|
|
|
desired.freq = sc->sn.speed;
|
|
desired.channels = sc->sn.numchannels; //fixme!
|
|
desired.samples = 0x0200; //'Good values seem to range between 512 and 8192 inclusive, depending on the application and CPU speed.'
|
|
desired.format = AUDIO_S16SYS;
|
|
desired.callback = (void*)SSDL_Paint;
|
|
desired.userdata = sc;
|
|
memcpy(&obtained, &desired, sizeof(obtained));
|
|
|
|
#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
|
|
if ( SDL_OpenAudio(&desired, &obtained) < 0 )
|
|
{
|
|
Con_Printf("SDL: SNDDMA_Init: couldn't open sound device (%s).\n", SDL_GetError());
|
|
return false;
|
|
}
|
|
#endif
|
|
sc->sn.numchannels = obtained.channels;
|
|
sc->sn.speed = obtained.freq;
|
|
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
|
|
|
|
#ifdef SELFPAINT
|
|
sc->selfpainting = true;
|
|
#endif
|
|
|
|
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);
|
|
|
|
#ifndef SELFPAINT
|
|
sc->sn.buffer = malloc(sc->sn.samples*sc->sn.samplebits/8);
|
|
#endif
|
|
Con_DPrintf("Got sound %i-%i\n", obtained.freq, obtained.format);
|
|
|
|
sc->Lock = SSDL_LockBuffer;
|
|
sc->Unlock = SSDL_UnlockBuffer;
|
|
sc->SetWaterDistortion = SSDL_SetUnderWater;
|
|
sc->Submit = SSDL_Submit;
|
|
sc->Shutdown = SSDL_Shutdown;
|
|
sc->GetDMAPos = SSDL_GetDMAPos;
|
|
|
|
SDL_PauseAudio(0);
|
|
|
|
return true;
|
|
}
|
|
|
|
sounddriver pSDL_InitCard = &SDL_InitCard;
|
|
|