Add support for AL_SOFT_loop_points. Implement quake-mixer-over-openal as a workaround for weird performance issues in Chromium.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6086 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
5018d3e650
commit
15bd67c8f0
5 changed files with 312 additions and 99 deletions
|
@ -35,9 +35,14 @@ We also have no doppler with WebAudio.
|
|||
#define OPENAL_STATIC //our javascript port doesn't support dynamic linking (bss+data segments get too messy).
|
||||
#define SDRVNAME "WebAudio" //IE doesn't support webaudio, resulting in noticable error messages about no openal, which is technically incorrect. So lets be clear about this.
|
||||
#define SDRVNAMEDESC "WebAudio:"
|
||||
|
||||
#define QMIX_SDRVNAME "qmix" //IE doesn't support webaudio, resulting in noticable error messages about no openal, which is technically incorrect. So lets be clear about this.
|
||||
#define QMIX_SDRVNAMEDESC "QMIX:"
|
||||
#else
|
||||
#define SDRVNAME "OpenAL"
|
||||
#define SDRVNAMEDESC "OAL:"
|
||||
#define QMIX_SDRVNAME "qmix"
|
||||
#define QMIX_SDRVNAMEDESC "OALQ:"
|
||||
#define USEEFX
|
||||
#endif
|
||||
#ifndef HAVE_MIXER
|
||||
|
@ -67,6 +72,7 @@ We also have no doppler with WebAudio.
|
|||
#define palGenBuffers alGenBuffers
|
||||
#define palIsBuffer alIsBuffer
|
||||
#define palBufferData alBufferData
|
||||
#define palBufferiv alBufferiv
|
||||
#define palDeleteBuffers alDeleteBuffers
|
||||
#define palListenerfv alListenerfv
|
||||
#define palSourcefv alSourcefv
|
||||
|
@ -136,6 +142,7 @@ static AL_API void (AL_APIENTRY *palDopplerFactor)( ALfloat value );
|
|||
static AL_API void (AL_APIENTRY *palGenBuffers)( ALsizei n, ALuint* buffers );
|
||||
static AL_API ALboolean (AL_APIENTRY *palIsBuffer)( ALuint bid );
|
||||
static AL_API void (AL_APIENTRY *palBufferData)( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq );
|
||||
static AL_API void (AL_APIENTRY *palBufferiv)(ALuint buffer, ALenum param, const ALint *values);
|
||||
static AL_API void (AL_APIENTRY *palDeleteBuffers)( ALsizei n, const ALuint* buffers );
|
||||
|
||||
static AL_API void (AL_APIENTRY *palListenerfv)( ALenum param, const ALfloat* values );
|
||||
|
@ -326,6 +333,9 @@ static AL_API ALvoid (AL_APIENTRY *palEffectfv)(ALuint effect, ALenum param, con
|
|||
//AL_SOFT_source_spatialize
|
||||
#define AL_SOURCE_SPATIALIZE_SOFT 0x1214
|
||||
|
||||
//AL_SOFT_loop_points
|
||||
#define AL_LOOP_POINTS_SOFT 0x2015
|
||||
|
||||
//ALC_SOFT_HRTF
|
||||
#define ALC_HRTF_SOFT 0x1992
|
||||
#define ALC_DONT_CARE_SOFT 0x0002
|
||||
|
@ -357,7 +367,11 @@ static void S_Info(void);
|
|||
|
||||
static void S_Shutdown_f(void);
|
||||
*/
|
||||
#ifdef FTE_TARGET_WEB
|
||||
static cvar_t s_al_disable = CVARD("s_al_disable", "1", "0: OpenAL works (generally as the highest priority).\n1: OpenAL will be used only when a specific device is selected.\n2: Don't allow ANY use of OpenAl.\nWith OpenAL disabled, audio ouput will fall back to platform-specific output, avoiding miscilaneous third-party openal limitation bugs.");
|
||||
#else
|
||||
static cvar_t s_al_disable = CVARD("s_al_disable", "0", "0: OpenAL works (generally as the highest priority).\n1: OpenAL will be used only when a specific device is selected.\n2: Don't allow ANY use of OpenAl.\nWith OpenAL disabled, audio ouput will fall back to platform-specific output, avoiding miscilaneous third-party openal limitation bugs.");
|
||||
#endif
|
||||
static cvar_t s_al_debug = CVARD("s_al_debug", "0", "Enables periodic checks for OpenAL errors.");
|
||||
static cvar_t s_al_hrtf = CVARD("s_al_hrtf", "", "Enables use of HRTF, and which HRTF table to use.\nempty: auto, depending on openal config to enable it.\n\0: force off.\n1: Use the default HRTF.");
|
||||
static cvar_t s_al_use_reverb = CVARD("s_al_use_reverb", "1", "Controls whether reverb effects will be used. Set to 0 to block them. Reverb requires gamecode to configure the reverb properties, other than underwater.");
|
||||
|
@ -384,6 +398,12 @@ enum distancemodel_e
|
|||
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
ALuint handle;
|
||||
unsigned int queuesize;
|
||||
ALuint queue[64];
|
||||
} qmix;
|
||||
struct
|
||||
{
|
||||
ALuint handle;
|
||||
|
@ -403,11 +423,13 @@ typedef struct
|
|||
ALCdevice *OpenAL_Device;
|
||||
ALCcontext *OpenAL_Context;
|
||||
qboolean can_source_spatialise;
|
||||
qboolean can_looppoints;
|
||||
|
||||
int ListenEnt; //listener's entity number, so we don't get weird sound displacements
|
||||
ALfloat ListenPos[3]; //their origin.
|
||||
ALfloat ListenVel[3]; // Velocity of the listener.
|
||||
ALfloat ListenOri[6]; // Orientation of the listener. (first 3 elements are "at", second 3 are "up")
|
||||
unsigned int listenerdirty;
|
||||
|
||||
#ifdef MIXER_F32
|
||||
qboolean canfloataudio;
|
||||
|
@ -455,7 +477,7 @@ static void PrintALError(char *string)
|
|||
Con_Printf("OpenAL - %s: %x: %s\n",string,err,text);
|
||||
}
|
||||
|
||||
static qboolean OpenAL_LoadCache(oalinfo_t *oali, unsigned int *bufptr, sfxcache_t *sc, float volume)
|
||||
static qboolean OpenAL_LoadCache(oalinfo_t *oali, unsigned int *bufptr, sfxcache_t *sc, float volume, int loopstart)
|
||||
{
|
||||
unsigned int fmt;
|
||||
unsigned int size;
|
||||
|
@ -599,6 +621,12 @@ static qboolean OpenAL_LoadCache(oalinfo_t *oali, unsigned int *bufptr, sfxcache
|
|||
}
|
||||
}
|
||||
|
||||
if (oali->can_looppoints && loopstart>0)
|
||||
{
|
||||
ALint points[2] = {loopstart, sc->length};
|
||||
palBufferiv(*bufptr, AL_LOOP_POINTS_SOFT, points);
|
||||
}
|
||||
|
||||
//FIXME: we need to handle oal-oom error codes
|
||||
|
||||
PrintALError("Buffer Data");
|
||||
|
@ -624,6 +652,7 @@ static void QDECL OpenAL_CvarInit(void)
|
|||
static void OpenAL_ListenerUpdate(soundcardinfo_t *sc, int entnum, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t velocity)
|
||||
{
|
||||
oalinfo_t *oali = sc->handle;
|
||||
vec3_t vel;
|
||||
|
||||
if (snd_doppler.modified)
|
||||
{
|
||||
|
@ -631,26 +660,46 @@ static void OpenAL_ListenerUpdate(soundcardinfo_t *sc, int entnum, vec3_t origin
|
|||
OnChangeALSettings(NULL,NULL);
|
||||
}
|
||||
|
||||
VectorScale(velocity, s_al_velocityscale.value/35.0, oali->ListenVel);
|
||||
VectorCopy(origin, oali->ListenPos);
|
||||
if (!VectorCompare(origin, oali->ListenPos))
|
||||
{
|
||||
VectorCopy(origin, oali->ListenPos);
|
||||
oali->listenerdirty |= 1;
|
||||
}
|
||||
|
||||
VectorScale(velocity, s_al_velocityscale.value/35.0, vel);
|
||||
if (!VectorCompare(vel, oali->ListenVel))
|
||||
{
|
||||
VectorCopy(vel, oali->ListenVel);
|
||||
oali->listenerdirty |= 2;
|
||||
}
|
||||
|
||||
oali->ListenEnt = entnum;
|
||||
oali->ListenOri[0] = forward[0];
|
||||
oali->ListenOri[1] = forward[1];
|
||||
oali->ListenOri[2] = forward[2];
|
||||
oali->ListenOri[3] = up[0];
|
||||
oali->ListenOri[4] = up[1];
|
||||
oali->ListenOri[5] = up[2];
|
||||
if (!VectorCompare(forward, oali->ListenOri) || !VectorCompare(up, oali->ListenOri+3))
|
||||
{
|
||||
oali->ListenOri[0] = forward[0];
|
||||
oali->ListenOri[1] = forward[1];
|
||||
oali->ListenOri[2] = forward[2];
|
||||
oali->ListenOri[3] = up[0];
|
||||
oali->ListenOri[4] = up[1];
|
||||
oali->ListenOri[5] = up[2];
|
||||
oali->listenerdirty |= 4;
|
||||
}
|
||||
|
||||
|
||||
if (!s_al_static_listener.value)
|
||||
{
|
||||
palListenerf(AL_GAIN, 1);
|
||||
palListenerfv(AL_POSITION, oali->ListenPos);
|
||||
//I'm using listenerdirty flags because emscripten's openal stuff seems to be wasting massive amounts of time on these.
|
||||
// palListenerf(AL_GAIN, 1);
|
||||
if (oali->listenerdirty & 1)
|
||||
palListenerfv(AL_POSITION, oali->ListenPos);
|
||||
#ifndef FTE_TARGET_WEB //webaudio sucks.
|
||||
palListenerfv(AL_VELOCITY, oali->ListenVel);
|
||||
if (oali->listenerdirty & 2)
|
||||
palListenerfv(AL_VELOCITY, oali->ListenVel);
|
||||
#endif
|
||||
palListenerfv(AL_ORIENTATION, oali->ListenOri);
|
||||
if (oali->listenerdirty & 4)
|
||||
palListenerfv(AL_ORIENTATION, oali->ListenOri);
|
||||
|
||||
oali->listenerdirty = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -760,6 +809,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
}
|
||||
oali->source[chnum].handle = src;
|
||||
oali->source[chnum].allocated = true;
|
||||
oali->source[chnum].queuesize = 0;
|
||||
schanged |= CUR_EVERYTHING; //should normally be true anyway, but hey
|
||||
}
|
||||
else
|
||||
|
@ -829,7 +879,9 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
cvolume *= mastervolume.value;
|
||||
|
||||
//openal doesn't support loopstart (entire sample loops or not at all), so if we're meant to skip the first half then we need to stream it.
|
||||
stream = sfx->decoder.decodedata || sfx->loopstart > 0;
|
||||
//FIXME: AL_SOFT_loop_points
|
||||
stream = sfx->decoder.decodedata || (sfx->loopstart > 0 && !oali->can_looppoints);
|
||||
srcrel = (chan->flags & CF_NOSPACIALISE) || (chan->entnum && chan->entnum == oali->ListenEnt) || !chan->dist_mult;
|
||||
|
||||
if ((schanged&CUR_SOUNDCHANGE) || stream)
|
||||
{
|
||||
|
@ -892,7 +944,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
{
|
||||
//build a buffer with it and queue it up.
|
||||
//buffer will be purged later on when its unqueued
|
||||
if (OpenAL_LoadCache(oali, &buf, &sbuf, max(1,cvolume)))
|
||||
if (OpenAL_LoadCache(oali, &buf, &sbuf, max(1,cvolume), 0))
|
||||
{
|
||||
palSourceQueueBuffers(src, 1, &buf);
|
||||
oali->source[chnum].queue[oali->source[chnum].queuesize++] = buf;
|
||||
|
@ -907,7 +959,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
silence.data = NULL;
|
||||
silence.length = 0.1 * silence.speed;
|
||||
silence.soundoffset = 0;
|
||||
if (OpenAL_LoadCache(oali, &buf, &silence, 1))
|
||||
if (OpenAL_LoadCache(oali, &buf, &silence, 1, 0))
|
||||
{
|
||||
palSourceQueueBuffers(src, 1, &buf);
|
||||
oali->source[chnum].queue[oali->source[chnum].queuesize++] = buf;
|
||||
|
@ -938,10 +990,12 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
silence.data = NULL;
|
||||
silence.length = 0.1 * silence.speed;
|
||||
silence.soundoffset = 0;
|
||||
if (OpenAL_LoadCache(oali, &buf, &silence, 1))
|
||||
if (OpenAL_LoadCache(oali, &buf, &silence, 1, 0))
|
||||
{
|
||||
palSourceQueueBuffers(src, 1, &buf);
|
||||
oali->source[chnum].queue[oali->source[chnum].queuesize++] = buf;
|
||||
if (oali->can_source_spatialise) //force spacialisation as desired, if supported (this solves browsers forcing stereo on mono files which should mean static audio is full volume...)
|
||||
palSourcei(src, AL_SOURCE_SPATIALIZE_SOFT, !srcrel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -965,7 +1019,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
{ //unstreamed
|
||||
if (!sfx->decoder.buf)
|
||||
return;
|
||||
oali->sounds[sndnum].allocated = OpenAL_LoadCache(oali, &buf, sfx->decoder.buf, 1);
|
||||
oali->sounds[sndnum].allocated = OpenAL_LoadCache(oali, &buf, sfx->decoder.buf, 1, sfx->loopstart);
|
||||
if (!oali->sounds[sndnum].allocated)
|
||||
return;
|
||||
oali->sounds[sndnum].buffer = buf;
|
||||
|
@ -985,10 +1039,11 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
}
|
||||
#endif
|
||||
palSourcei(src, AL_BUFFER, buf);
|
||||
if (oali->can_source_spatialise) //force spacialisation as desired, if supported (this solves browsers forcing stereo on mono files which should mean static audio is full volume...)
|
||||
palSourcei(src, AL_SOURCE_SPATIALIZE_SOFT, !srcrel);
|
||||
}
|
||||
}
|
||||
palSourcef(src, AL_GAIN, min(cvolume, 1)); //openal only supports a max volume of 1. anything above is an error and will be clamped.
|
||||
srcrel = (chan->flags & CF_NOSPACIALISE) || (chan->entnum && chan->entnum == oali->ListenEnt) || !chan->dist_mult;
|
||||
if (srcrel)
|
||||
{
|
||||
palSourcefv(src, AL_POSITION, vec3_origin);
|
||||
|
@ -1004,9 +1059,6 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
#endif
|
||||
}
|
||||
|
||||
if (oali->can_source_spatialise) //force spacialisation as desired, if supported (this solves browsers forcing stereo on mono files which should mean static audio is full volume...)
|
||||
palSourcei(src, AL_SOURCE_SPATIALIZE_SOFT, !srcrel);
|
||||
|
||||
if (schanged)
|
||||
{
|
||||
if (schanged == CUR_UPDATE && chan->pos)
|
||||
|
@ -1028,7 +1080,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
}
|
||||
#endif
|
||||
|
||||
palSourcei(src, AL_LOOPING, (!stream && ((chan->flags & CF_FORCELOOP)||sfx->loopstart==0))?AL_TRUE:AL_FALSE);
|
||||
palSourcei(src, AL_LOOPING, (!stream && ((chan->flags & CF_FORCELOOP)||(sfx->loopstart>=0&&!stream)))?AL_TRUE:AL_FALSE);
|
||||
if (srcrel)
|
||||
{
|
||||
palSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE);
|
||||
|
@ -1148,6 +1200,7 @@ static qboolean OpenAL_InitLibrary(void)
|
|||
{(void*)&palGenBuffers, "alGenBuffers"},
|
||||
{(void*)&palIsBuffer, "alIsBuffer"},
|
||||
{(void*)&palBufferData, "alBufferData"},
|
||||
{(void*)&palBufferiv, "alBufferiv"},
|
||||
{(void*)&palDeleteBuffers, "alDeleteBuffers"},
|
||||
{(void*)&palListenerfv, "alListenerfv"},
|
||||
{(void*)&palSourcefv, "alSourcefv"},
|
||||
|
@ -1199,7 +1252,7 @@ static qboolean OpenAL_InitLibrary(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static qboolean OpenAL_Init(soundcardinfo_t *sc, const char *devname)
|
||||
static qboolean OpenAL_Init(soundcardinfo_t *sc, const char *devname, qboolean qmix)
|
||||
{
|
||||
oalinfo_t *oali;
|
||||
|
||||
|
@ -1217,12 +1270,15 @@ static qboolean OpenAL_Init(soundcardinfo_t *sc, const char *devname)
|
|||
|
||||
if (!devname || !*devname)
|
||||
{
|
||||
if (s_al_disable.ival)
|
||||
if (s_al_disable.ival && !qmix)
|
||||
return false; //no default device
|
||||
devname = palcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
|
||||
}
|
||||
Q_snprintfz(sc->name, sizeof(sc->name), "%s", devname);
|
||||
Con_TPrintf("Initiating "SDRVNAME": %s.\n", devname);
|
||||
if (qmix)
|
||||
Con_TPrintf("Initiating "QMIX_SDRVNAME": %s.\n", devname);
|
||||
else
|
||||
Con_TPrintf("Initiating "SDRVNAME": %s.\n", devname);
|
||||
|
||||
oali = Z_Malloc(sizeof(oalinfo_t));
|
||||
sc->handle = oali;
|
||||
|
@ -1235,7 +1291,7 @@ static qboolean OpenAL_Init(soundcardinfo_t *sc, const char *devname)
|
|||
size_t i = 0;
|
||||
ALCint attrs[5];
|
||||
|
||||
palcGetStringiSOFT = (palcIsExtensionPresent(oali->OpenAL_Device, "ALC_SOFT_HRTF"))?palcGetProcAddress(oali->OpenAL_Device, "alcGetStringiSOFT"):NULL;
|
||||
palcGetStringiSOFT = (!qmix&&palcIsExtensionPresent(oali->OpenAL_Device, "ALC_SOFT_HRTF"))?palcGetProcAddress(oali->OpenAL_Device, "alcGetStringiSOFT"):NULL;
|
||||
if (palcGetStringiSOFT)
|
||||
{
|
||||
if (!*s_al_hrtf.string)
|
||||
|
@ -1297,6 +1353,7 @@ static qboolean OpenAL_Init(soundcardinfo_t *sc, const char *devname)
|
|||
memset(oali->source, 0, sizeof(*oali->source)*oali->max_sources);
|
||||
PrintALError("alGensources for normal sources");
|
||||
|
||||
palListenerf(AL_GAIN, 1);
|
||||
palListenerfv(AL_POSITION, oali->ListenPos);
|
||||
#ifndef FTE_TARGET_WEB //webaudio sucks.
|
||||
palListenerfv(AL_VELOCITY, oali->ListenVel);
|
||||
|
@ -1304,6 +1361,7 @@ static qboolean OpenAL_Init(soundcardinfo_t *sc, const char *devname)
|
|||
palListenerfv(AL_ORIENTATION, oali->ListenOri);
|
||||
|
||||
oali->can_source_spatialise = palIsExtensionPresent("AL_SOFT_source_spatialize");
|
||||
oali->can_looppoints = palIsExtensionPresent("AL_SOFT_loop_points");
|
||||
|
||||
if (palcGetStringiSOFT)
|
||||
{
|
||||
|
@ -1576,85 +1634,98 @@ static ALuint OpenAL_LoadEffect(const struct reverbproperties_s *reverb)
|
|||
}
|
||||
#endif
|
||||
|
||||
static qboolean QDECL OpenAL_InitCard(soundcardinfo_t *sc, const char *devname)
|
||||
#ifdef HAVE_MIXER
|
||||
#define CHUNKSAMPLES 1024
|
||||
static void *OAQM_LockBuffer (soundcardinfo_t *sc, unsigned int *sampidx)
|
||||
{
|
||||
oalinfo_t *oali;
|
||||
|
||||
soundcardinfo_t *old;
|
||||
// extern soundcardinfo_t *sndcardinfo;
|
||||
|
||||
//
|
||||
for (old = sndcardinfo; old; old = old->next)
|
||||
oalinfo_t *oali = sc->handle;
|
||||
if (oali->qmix.queuesize==countof(oali->qmix.queue))
|
||||
return NULL; //not available yet.
|
||||
return sc->sn.buffer;
|
||||
}
|
||||
static void OAQM_UnlockBuffer (soundcardinfo_t *sc, void *buffer)
|
||||
{
|
||||
}
|
||||
static void OAQM_Submit (soundcardinfo_t *sc, int start, int end)
|
||||
{
|
||||
oalinfo_t *oali = sc->handle;
|
||||
ALint buf;
|
||||
int framesize = sc->sn.samplebytes*sc->sn.numchannels;
|
||||
if (end==start)
|
||||
return;
|
||||
if (oali->qmix.queuesize == countof(oali->qmix.queue))
|
||||
return;
|
||||
palGenBuffers(1, &buf);
|
||||
switch(sc->sn.sampleformat)
|
||||
{
|
||||
if (old->Shutdown == OpenAL_Shutdown)
|
||||
{
|
||||
//in theory, we could relax this by using alcMakeContextCurrent lots, but we'd also need to do something about the per-sound audio buffer handle hack
|
||||
Con_Printf(CON_ERROR SDRVNAME ": only a single device may be active at once\n");
|
||||
return false;
|
||||
}
|
||||
case QSF_F32:
|
||||
palBufferData(buf, (sc->sn.numchannels>1)?AL_FORMAT_STEREO_FLOAT32:AL_FORMAT_MONO_FLOAT32, sc->sn.buffer, (end-start)*framesize, sc->sn.speed);
|
||||
break;
|
||||
case QSF_S16:
|
||||
palBufferData(buf, (sc->sn.numchannels>1)?AL_FORMAT_STEREO16:AL_FORMAT_MONO16, sc->sn.buffer, (end-start)*framesize, sc->sn.speed);
|
||||
break;
|
||||
case QSF_U8:
|
||||
palBufferData(buf, (sc->sn.numchannels>1)?AL_FORMAT_STEREO8:AL_FORMAT_MONO8, sc->sn.buffer, (end-start)*framesize, sc->sn.speed);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
palSourceQueueBuffers(oali->qmix.handle, 1, &buf);
|
||||
oali->qmix.queue[oali->qmix.queuesize++] = buf;
|
||||
sc->snd_completed += (end-start);
|
||||
|
||||
palGetSourcei(oali->qmix.handle, AL_SOURCE_STATE, &buf);
|
||||
if (buf != AL_PLAYING)
|
||||
palSourcePlay(oali->qmix.handle);
|
||||
}
|
||||
|
||||
/*stub should not be called*/
|
||||
static unsigned int OAQM_GetDMAPos (soundcardinfo_t *sc)
|
||||
{
|
||||
extern cvar_t _snd_mixahead;
|
||||
oalinfo_t *oali = sc->handle;
|
||||
ALint src = oali->qmix.handle;
|
||||
ALint processed = 0;
|
||||
unsigned int avail;
|
||||
palGetSourcei(src, AL_BUFFERS_PROCESSED, &processed);
|
||||
if (processed)
|
||||
{
|
||||
palSourceUnqueueBuffers(src, processed, oali->qmix.queue);
|
||||
palDeleteBuffers(processed, oali->qmix.queue);
|
||||
oali->qmix.queuesize -= processed;
|
||||
memmove(oali->qmix.queue, oali->qmix.queue+processed, oali->qmix.queuesize*sizeof(*oali->qmix.queue));
|
||||
}
|
||||
|
||||
avail = ((_snd_mixahead.value*sc->sn.speed)+CHUNKSAMPLES/2)/CHUNKSAMPLES; //how many buffers we want to try using.
|
||||
avail = bound(2, avail, countof(oali->qmix.queue));
|
||||
if (oali->qmix.queuesize > avail)
|
||||
avail = 0;
|
||||
else
|
||||
avail = avail-oali->qmix.queuesize;
|
||||
avail *= CHUNKSAMPLES;
|
||||
|
||||
if (OpenAL_Init(sc, devname) == false)
|
||||
return false;
|
||||
oali = sc->handle;
|
||||
sc->sn.samplepos = (sc->snd_completed+avail);
|
||||
sc->sn.samplepos *= sc->sn.numchannels;
|
||||
return sc->sn.samplepos;
|
||||
}
|
||||
|
||||
#ifdef FTE_TARGET_WEB
|
||||
Con_DPrintf( "AL_VERSION: %s\n",palGetString(AL_VERSION));
|
||||
Con_DPrintf( "AL_RENDERER: %s\n",palGetString(AL_RENDERER));
|
||||
Con_DPrintf( "AL_VENDOR: %s\n",palGetString(AL_VENDOR));
|
||||
#else
|
||||
Con_Printf( "AL_VERSION: %s\n",palGetString(AL_VERSION));
|
||||
Con_Printf( "AL_RENDERER: %s\n",palGetString(AL_RENDERER));
|
||||
Con_Printf( "AL_VENDOR: %s\n",palGetString(AL_VENDOR));
|
||||
#endif
|
||||
Con_DPrintf("AL_EXTENSIONS: %s\n",palGetString(AL_EXTENSIONS));
|
||||
Con_DPrintf("ALC_EXTENSIONS: %s\n",palcGetString(oali->OpenAL_Device,ALC_EXTENSIONS));
|
||||
static qboolean QDECL OpenAL_Enumerate_QMix(void (QDECL *callback)(const char *driver, const char *devicecode, const char *readabledevice))
|
||||
{
|
||||
const char *devnames;
|
||||
if (!OpenAL_InitLibrary())
|
||||
return true; //enumerate nothing if al is disabled
|
||||
|
||||
sc->Shutdown = OpenAL_Shutdown;
|
||||
#ifdef USEEFX
|
||||
sc->SetEnvironmentReverb = OpenAL_SetReverb;
|
||||
#endif
|
||||
sc->ChannelUpdate = OpenAL_ChannelUpdate;
|
||||
sc->ListenerUpdate = OpenAL_ListenerUpdate;
|
||||
sc->GetChannelPos = OpenAL_GetChannelPos;
|
||||
//these are stubs for our software mixer, and are not used with hardware mixing.
|
||||
sc->Lock = OpenAL_LockBuffer;
|
||||
sc->Unlock = OpenAL_UnlockBuffer;
|
||||
sc->Submit = OpenAL_Submit;
|
||||
sc->GetDMAPos = OpenAL_GetDMAPos;
|
||||
|
||||
#ifdef MIXER_F32
|
||||
oali->canfloataudio = palIsExtensionPresent("AL_EXT_float32");
|
||||
#endif
|
||||
|
||||
sc->inactive_sound = true;
|
||||
sc->selfpainting = true;
|
||||
sc->sn.sampleformat = QSF_EXTERNALMIXER;
|
||||
|
||||
OnChangeALSettings(NULL, NULL);
|
||||
|
||||
#ifdef USEEFX
|
||||
PrintALError("preeffects");
|
||||
palSource3i = palGetProcAddress("alSource3i");
|
||||
palAuxiliaryEffectSloti = palGetProcAddress("alAuxiliaryEffectSloti");
|
||||
palGenAuxiliaryEffectSlots = palGetProcAddress("alGenAuxiliaryEffectSlots");
|
||||
palDeleteAuxiliaryEffectSlots = palGetProcAddress("alDeleteAuxiliaryEffectSlots");
|
||||
palDeleteEffects = palGetProcAddress("alDeleteEffects");
|
||||
palGenEffects = palGetProcAddress("alGenEffects");
|
||||
palEffecti = palGetProcAddress("alEffecti");
|
||||
palEffectiv = palGetProcAddress("alEffectiv");
|
||||
palEffectf = palGetProcAddress("alEffectf");
|
||||
palEffectfv = palGetProcAddress("alEffectfv");
|
||||
|
||||
if (palGenAuxiliaryEffectSlots && s_al_use_reverb.ival)
|
||||
palGenAuxiliaryEffectSlots(1, &oali->effectslot);
|
||||
|
||||
oali->cureffect = ~0;
|
||||
PrintALError("posteffects");
|
||||
#endif
|
||||
devnames = palcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
|
||||
if (!devnames)
|
||||
devnames = palcGetString(NULL, ALC_DEVICE_SPECIFIER);
|
||||
while(*devnames)
|
||||
{
|
||||
callback(QMIX_SDRVNAME, devnames, va(QMIX_SDRVNAMEDESC"%s", devnames));
|
||||
devnames += strlen(devnames)+1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static qboolean QDECL OpenAL_Enumerate(void (QDECL *callback)(const char *driver, const char *devicecode, const char *readabledevice))
|
||||
{
|
||||
|
@ -1673,6 +1744,127 @@ static qboolean QDECL OpenAL_Enumerate(void (QDECL *callback)(const char *driver
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
static qboolean QDECL OpenAL_InitCard2(soundcardinfo_t *sc, const char *devname, qboolean qmix)
|
||||
{
|
||||
oalinfo_t *oali;
|
||||
|
||||
soundcardinfo_t *old;
|
||||
// extern soundcardinfo_t *sndcardinfo;
|
||||
|
||||
//
|
||||
for (old = sndcardinfo; old; old = old->next)
|
||||
{
|
||||
if (old->Shutdown == OpenAL_Shutdown)
|
||||
{
|
||||
//in theory, we could relax this by using alcMakeContextCurrent lots, but we'd also need to do something about the per-sound audio buffer handle hack
|
||||
Con_Printf(CON_ERROR SDRVNAME ": only a single device may be active at once\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (OpenAL_Init(sc, devname, qmix) == false)
|
||||
return false;
|
||||
oali = sc->handle;
|
||||
|
||||
Con_DPrintf( "AL_VERSION: %s\n",palGetString(AL_VERSION));
|
||||
Con_DPrintf( "AL_RENDERER: %s\n",palGetString(AL_RENDERER));
|
||||
Con_DPrintf( "AL_VENDOR: %s\n",palGetString(AL_VENDOR));
|
||||
Con_DPrintf("AL_EXTENSIONS: %s\n",palGetString(AL_EXTENSIONS));
|
||||
Con_DPrintf("ALC_EXTENSIONS: %s\n",palcGetString(oali->OpenAL_Device,ALC_EXTENSIONS));
|
||||
|
||||
#ifdef MIXER_F32
|
||||
oali->canfloataudio = palIsExtensionPresent("AL_EXT_float32");
|
||||
#endif
|
||||
|
||||
sc->inactive_sound = true;
|
||||
sc->Shutdown = OpenAL_Shutdown;
|
||||
if (qmix)
|
||||
{
|
||||
sc->Lock = OAQM_LockBuffer;
|
||||
sc->Unlock = OAQM_UnlockBuffer;
|
||||
sc->GetDMAPos = OAQM_GetDMAPos;
|
||||
sc->Submit = OAQM_Submit;
|
||||
|
||||
sc->sn.numchannels = bound(1, sc->sn.numchannels, 2);
|
||||
sc->sn.samples = CHUNKSAMPLES*sc->sn.numchannels;
|
||||
#ifdef MIXER_F32
|
||||
if (sc->sn.samplebytes == 4 && oali->canfloataudio)
|
||||
{
|
||||
sc->sn.sampleformat = QSF_F32;
|
||||
sc->sn.samplebytes = 4;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (sc->sn.samplebytes > 1)
|
||||
{
|
||||
sc->sn.sampleformat = QSF_S16;
|
||||
sc->sn.samplebytes = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
sc->sn.sampleformat = QSF_U8;
|
||||
sc->sn.samplebytes = 1;
|
||||
}
|
||||
// sc->sn.speed = 11025;
|
||||
sc->sn.buffer = malloc(sc->sn.samples * sc->sn.samplebytes);
|
||||
sc->samplequeue = -1;
|
||||
|
||||
oali->qmix.handle = 0;
|
||||
oali->qmix.queuesize = 0;
|
||||
palGenSources(1, &oali->qmix.handle);
|
||||
palSourcef(oali->qmix.handle, AL_GAIN, 1);
|
||||
palSourcei(oali->qmix.handle, AL_SOURCE_RELATIVE, AL_TRUE);
|
||||
//palSourcePlay(oali->qmix.handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef USEEFX
|
||||
sc->SetEnvironmentReverb = OpenAL_SetReverb;
|
||||
#endif
|
||||
sc->ChannelUpdate = OpenAL_ChannelUpdate;
|
||||
sc->ListenerUpdate = OpenAL_ListenerUpdate;
|
||||
sc->GetChannelPos = OpenAL_GetChannelPos;
|
||||
//these are stubs for our software mixer, and are not used with hardware mixing.
|
||||
sc->Lock = OpenAL_LockBuffer;
|
||||
sc->Unlock = OpenAL_UnlockBuffer;
|
||||
sc->Submit = OpenAL_Submit;
|
||||
sc->GetDMAPos = OpenAL_GetDMAPos;
|
||||
|
||||
sc->selfpainting = true;
|
||||
sc->sn.sampleformat = QSF_EXTERNALMIXER;
|
||||
|
||||
OnChangeALSettings(NULL, NULL);
|
||||
|
||||
#ifdef USEEFX
|
||||
PrintALError("preeffects");
|
||||
palSource3i = palGetProcAddress("alSource3i");
|
||||
palAuxiliaryEffectSloti = palGetProcAddress("alAuxiliaryEffectSloti");
|
||||
palGenAuxiliaryEffectSlots = palGetProcAddress("alGenAuxiliaryEffectSlots");
|
||||
palDeleteAuxiliaryEffectSlots = palGetProcAddress("alDeleteAuxiliaryEffectSlots");
|
||||
palDeleteEffects = palGetProcAddress("alDeleteEffects");
|
||||
palGenEffects = palGetProcAddress("alGenEffects");
|
||||
palEffecti = palGetProcAddress("alEffecti");
|
||||
palEffectiv = palGetProcAddress("alEffectiv");
|
||||
palEffectf = palGetProcAddress("alEffectf");
|
||||
palEffectfv = palGetProcAddress("alEffectfv");
|
||||
|
||||
if (palGenAuxiliaryEffectSlots && s_al_use_reverb.ival)
|
||||
palGenAuxiliaryEffectSlots(1, &oali->effectslot);
|
||||
|
||||
oali->cureffect = ~0;
|
||||
PrintALError("posteffects");
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static qboolean QDECL OpenAL_InitCard(soundcardinfo_t *sc, const char *devname)
|
||||
{
|
||||
return OpenAL_InitCard2(sc, devname, false);
|
||||
}
|
||||
|
||||
sounddriver_t OPENAL_Output =
|
||||
{
|
||||
SDRVNAME,
|
||||
|
@ -1680,6 +1872,19 @@ sounddriver_t OPENAL_Output =
|
|||
OpenAL_Enumerate,
|
||||
OpenAL_CvarInit
|
||||
};
|
||||
#ifdef HAVE_MIXER
|
||||
static qboolean QDECL OpenAL_InitCard_QMix(soundcardinfo_t *sc, const char *devname)
|
||||
{
|
||||
return OpenAL_InitCard2(sc, devname, true);
|
||||
}
|
||||
sounddriver_t OPENAL_Output_Lame =
|
||||
{
|
||||
QMIX_SDRVNAME,
|
||||
OpenAL_InitCard_QMix,
|
||||
OpenAL_Enumerate_QMix,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(VOICECHAT)
|
||||
|
|
|
@ -1843,6 +1843,7 @@ extern sounddriver_t Pulse_Output;
|
|||
sounddriver_t fte_weakstruct OSS_Output;
|
||||
#ifdef AVAIL_OPENAL
|
||||
extern sounddriver_t OPENAL_Output;
|
||||
extern sounddriver_t OPENAL_Output_Lame;
|
||||
#endif
|
||||
#ifdef __DJGPP__
|
||||
extern sounddriver_t SBLASTER_Output;
|
||||
|
@ -1915,6 +1916,9 @@ static sounddriver_t *outputdrivers[] =
|
|||
#endif
|
||||
&SNDIO_AudioOutput, //prefered on OpenBSD
|
||||
|
||||
#ifdef AVAIL_OPENAL
|
||||
&OPENAL_Output_Lame,//streaming quake's audio via openal instead of using openal properly. used in our browser port to work around issues with webaudio (at least in chromium).
|
||||
#endif
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -393,6 +393,10 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime)
|
|||
else
|
||||
SND_PaintChannel32F_O8I1(ch, scache, count, rate);
|
||||
break;
|
||||
#endif
|
||||
#ifdef FTE_TARGET_WEB
|
||||
case QAF_BLOB:
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
ltime += count;
|
||||
|
|
|
@ -390,7 +390,7 @@ struct soundcardinfo_s { //windows has one defined AFTER directsound
|
|||
void (*Submit) (soundcardinfo_t *sc, int start, int end); //if the ringbuffer is emulated, this is where you should push it to the device.
|
||||
void (*Shutdown) (soundcardinfo_t *sc); //kill the device
|
||||
unsigned int (*GetDMAPos) (soundcardinfo_t *sc); //get the current point that the hardware is reading from (the return value should not wrap, at least not very often)
|
||||
void (*SetEnvironmentReverb) (soundcardinfo_t *sc, size_t reverb); //if you have eax enabled, change the environment. fixme. generally this is a stub. optional.
|
||||
void (*SetEnvironmentReverb) (soundcardinfo_t *sc, size_t reverb); //if you have eax enabled, change the environment. generally this is a stub. optional.
|
||||
void (*Restore) (soundcardinfo_t *sc); //called before lock/unlock/lock/unlock/submit. optional
|
||||
void (*ChannelUpdate) (soundcardinfo_t *sc, channel_t *channel, chanupdatereason_t schanged); //properties of a sound effect changed. this is to notify hardware mixers. optional.
|
||||
void (*ListenerUpdate) (soundcardinfo_t *sc, int entnum, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t velocity); //player moved or something. this is to notify hardware mixers. optional.
|
||||
|
|
|
@ -302,7 +302,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#undef MAP_PROC //meh
|
||||
#define HALFLIFEMODELS //blurgh
|
||||
#undef SUPPORT_ICE //requires udp, so not usable. webrtc could be used instead, but that logic is out of our hands.
|
||||
#undef HAVE_MIXER //depend upon openal instead.
|
||||
// #undef HAVE_MIXER //depend upon openal instead.
|
||||
|
||||
//extra features stripped to try to reduce memory footprints
|
||||
#undef RUNTIMELIGHTING //too slow anyway
|
||||
|
|
Loading…
Reference in a new issue