From 9ee0341d14562ad6863ce28d402861c1a311c9dc Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Sat, 7 Apr 2012 13:06:10 +0000 Subject: [PATCH 01/29] Create an OpenAL branch From 7e0a44825e1cbe7c417966b8ba3ac8d2fde8a6dc Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 15 Apr 2012 02:58:01 +0000 Subject: [PATCH 02/29] OpenAL support, from Q2Pro Copied and adapted (hopefully) all relevant code from Q2Pro. Did some small refactorings when needed. Still TODO: * Adapt Makefile * OGG support when using OpenAL * A cvar that switches between OpenAL and DMA/SDL * Actually compiling and testing this stuff ;) --- src/client/sound/header/local.h | 37 +++ src/client/sound/header/qal_api.h | 107 +++++++++ src/client/sound/qal_api.c | 131 +++++++++++ src/client/sound/snd_al.c | 361 ++++++++++++++++++++++++++++++ src/client/sound/snd_dma.c | 242 +++++++++++++------- src/client/sound/snd_mem.c | 12 +- src/client/sound/snd_mix.c | 2 +- src/client/sound/snd_vorbis.c | 3 - src/client/sound/snd_wav.c | 3 + src/sdl/sound.c | 3 + 10 files changed, 808 insertions(+), 93 deletions(-) create mode 100644 src/client/sound/header/qal_api.h create mode 100644 src/client/sound/qal_api.c create mode 100644 src/client/sound/snd_al.c diff --git a/src/client/sound/header/local.h b/src/client/sound/header/local.h index 060d3f47..1cfe08d4 100644 --- a/src/client/sound/header/local.h +++ b/src/client/sound/header/local.h @@ -37,6 +37,10 @@ typedef struct { int loopstart; int speed; /* not needed, because converted on load? */ int width; +#if USE_OPENAL + int size; + int bufnum; +#endif int stereo; byte data[1]; /* variable sized */ } sfxcache_t; @@ -87,6 +91,10 @@ typedef struct { int master_vol; /* 0-255 master volume */ qboolean fixed_origin; /* use origin instead of fetching entnum's origin */ qboolean autosound; /* from an entity->sound, cleared each frame */ +#if USE_OPENAL + int autoframe; + int srcnum; +#endif } channel_t; typedef struct { @@ -98,6 +106,13 @@ typedef struct { int dataofs; /* chunk starts this many bytes from file start */ } wavinfo_t; +typedef enum { + SS_NOT = 0, // soundsystem not started + SS_DMA, // soundsystem started, using DMA/SDL + SS_OAL // soundsystem started, using OpenAL +} sndstarted_t; + +extern sndstarted_t sound_started; /* initializes cycling through a DMA buffer and returns information on it */ @@ -113,6 +128,7 @@ void SNDDMA_Submit(void); #define MAX_CHANNELS 32 extern channel_t channels[MAX_CHANNELS]; +extern int s_numchannels; extern int paintedtime; extern int s_rawend; @@ -133,6 +149,7 @@ extern cvar_t *s_khz; extern cvar_t *s_show; extern cvar_t *s_mixahead; extern cvar_t *s_testsound; +extern cvar_t *s_ambient; wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength); void S_InitScaletable (void); @@ -146,5 +163,25 @@ channel_t *S_PickChannel(int entnum, int entchannel); /* spatializes a channel */ void S_Spatialize(channel_t *ch); +void S_BuildSoundList( int *sounds ); + +#if USE_OPENAL +// this stuff was taken from Q2Pro +// only begin attenuating sound volumes when outside the FULLVOLUME range +#define SOUND_FULLVOLUME 80 +#define SOUND_LOOPATTENUATE 0.003 + +// for snd_al.c - copied from Q2Pro and adapted +void AL_SoundInfo( void ); +qboolean AL_Init( void ); +void AL_Shutdown( void ); +sfxcache_t *AL_UploadSfx( sfx_t *s, wavinfo_t *s_info, byte *data ); +void AL_DeleteSfx( sfx_t *s ); +void AL_StopChannel( channel_t *ch ); +void AL_PlayChannel( channel_t *ch ); +void AL_StopAllChannels( void ); +void AL_Update( void ); +#endif + #endif diff --git a/src/client/sound/header/qal_api.h b/src/client/sound/header/qal_api.h new file mode 100644 index 00000000..7948df72 --- /dev/null +++ b/src/client/sound/header/qal_api.h @@ -0,0 +1,107 @@ +/* +This Source File was taken from the Q2Pro Port. + +Copyright (C) 2010 skuller.net + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#define AL_NO_PROTOTYPES +#include + +#define QAL_IMP \ + QAL( LPALENABLE, alEnable ); \ + QAL( LPALDISABLE, alDisable ); \ + QAL( LPALISENABLED, alIsEnabled ); \ + QAL( LPALGETSTRING, alGetString ); \ + QAL( LPALGETBOOLEANV, alGetBooleanv ); \ + QAL( LPALGETINTEGERV, alGetIntegerv ); \ + QAL( LPALGETFLOATV, alGetFloatv ); \ + QAL( LPALGETDOUBLEV, alGetDoublev ); \ + QAL( LPALGETBOOLEAN, alGetBoolean ); \ + QAL( LPALGETINTEGER, alGetInteger ); \ + QAL( LPALGETFLOAT, alGetFloat ); \ + QAL( LPALGETDOUBLE, alGetDouble ); \ + QAL( LPALGETERROR, alGetError ); \ + QAL( LPALISEXTENSIONPRESENT, alIsExtensionPresent ); \ + QAL( LPALGETPROCADDRESS, alGetProcAddress ); \ + QAL( LPALGETENUMVALUE, alGetEnumValue ); \ + QAL( LPALLISTENERF, alListenerf ); \ + QAL( LPALLISTENER3F, alListener3f ); \ + QAL( LPALLISTENERFV, alListenerfv ); \ + QAL( LPALLISTENERI, alListeneri ); \ + QAL( LPALLISTENER3I, alListener3i ); \ + QAL( LPALLISTENERIV, alListeneriv ); \ + QAL( LPALGETLISTENERF, alGetListenerf ); \ + QAL( LPALGETLISTENER3F, alGetListener3f ); \ + QAL( LPALGETLISTENERFV, alGetListenerfv ); \ + QAL( LPALGETLISTENERI, alGetListeneri ); \ + QAL( LPALGETLISTENER3I, alGetListener3i ); \ + QAL( LPALGETLISTENERIV, alGetListeneriv ); \ + QAL( LPALGENSOURCES, alGenSources ); \ + QAL( LPALDELETESOURCES, alDeleteSources ); \ + QAL( LPALISSOURCE, alIsSource ); \ + QAL( LPALSOURCEF, alSourcef ); \ + QAL( LPALSOURCE3F, alSource3f ); \ + QAL( LPALSOURCEFV, alSourcefv ); \ + QAL( LPALSOURCEI, alSourcei ); \ + QAL( LPALSOURCE3I, alSource3i ); \ + QAL( LPALSOURCEIV, alSourceiv ); \ + QAL( LPALGETSOURCEF, alGetSourcef ); \ + QAL( LPALGETSOURCE3F, alGetSource3f ); \ + QAL( LPALGETSOURCEFV, alGetSourcefv ); \ + QAL( LPALGETSOURCEI, alGetSourcei ); \ + QAL( LPALGETSOURCE3I, alGetSource3i ); \ + QAL( LPALGETSOURCEIV, alGetSourceiv ); \ + QAL( LPALSOURCEPLAYV, alSourcePlayv ); \ + QAL( LPALSOURCESTOPV, alSourceStopv ); \ + QAL( LPALSOURCEREWINDV, alSourceRewindv ); \ + QAL( LPALSOURCEPAUSEV, alSourcePausev ); \ + QAL( LPALSOURCEPLAY, alSourcePlay ); \ + QAL( LPALSOURCESTOP, alSourceStop ); \ + QAL( LPALSOURCEREWIND, alSourceRewind ); \ + QAL( LPALSOURCEPAUSE, alSourcePause ); \ + QAL( LPALSOURCEQUEUEBUFFERS, alSourceQueueBuffers ); \ + QAL( LPALSOURCEUNQUEUEBUFFERS, alSourceUnqueueBuffers ); \ + QAL( LPALGENBUFFERS, alGenBuffers ); \ + QAL( LPALDELETEBUFFERS, alDeleteBuffers ); \ + QAL( LPALISBUFFER, alIsBuffer ); \ + QAL( LPALBUFFERDATA, alBufferData ); \ + QAL( LPALBUFFERF, alBufferf ); \ + QAL( LPALBUFFER3F, alBuffer3f ); \ + QAL( LPALBUFFERFV, alBufferfv ); \ + QAL( LPALBUFFERI, alBufferi ); \ + QAL( LPALBUFFER3I, alBuffer3i ); \ + QAL( LPALBUFFERIV, alBufferiv ); \ + QAL( LPALGETBUFFERF, alGetBufferf ); \ + QAL( LPALGETBUFFER3F, alGetBuffer3f ); \ + QAL( LPALGETBUFFERFV, alGetBufferfv ); \ + QAL( LPALGETBUFFERI, alGetBufferi ); \ + QAL( LPALGETBUFFER3I, alGetBuffer3i ); \ + QAL( LPALGETBUFFERIV, alGetBufferiv ); \ + QAL( LPALDOPPLERFACTOR, alDopplerFactor ); \ + QAL( LPALDOPPLERVELOCITY, alDopplerVelocity ); \ + QAL( LPALSPEEDOFSOUND, alSpeedOfSound ); \ + QAL( LPALDISTANCEMODEL, alDistanceModel ); + +#define QAL(type,func) extern type q##func; +QAL_IMP +#undef QAL + +qboolean QAL_Init( void ); +void QAL_Shutdown( void ); + diff --git a/src/client/sound/qal_api.c b/src/client/sound/qal_api.c new file mode 100644 index 00000000..0ff579b5 --- /dev/null +++ b/src/client/sound/qal_api.c @@ -0,0 +1,131 @@ +/* +This Source File was taken from the Q2Pro Port. + +Copyright (C) 2010 skuller.net + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "common.h" +#include "header/qal_api.h" +#include + +#define QALC_IMP \ + QAL( LPALCCREATECONTEXT, alcCreateContext ); \ + QAL( LPALCMAKECONTEXTCURRENT, alcMakeContextCurrent ); \ + QAL( LPALCPROCESSCONTEXT, alcProcessContext ); \ + QAL( LPALCSUSPENDCONTEXT, alcSuspendContext ); \ + QAL( LPALCDESTROYCONTEXT, alcDestroyContext ); \ + QAL( LPALCGETCURRENTCONTEXT, alcGetCurrentContext ); \ + QAL( LPALCGETCONTEXTSDEVICE, alcGetContextsDevice ); \ + QAL( LPALCOPENDEVICE, alcOpenDevice ); \ + QAL( LPALCCLOSEDEVICE, alcCloseDevice ); \ + QAL( LPALCGETERROR, alcGetError ); \ + QAL( LPALCISEXTENSIONPRESENT, alcIsExtensionPresent ); \ + QAL( LPALCGETPROCADDRESS, alcGetProcAddress ); \ + QAL( LPALCGETENUMVALUE, alcGetEnumValue ); \ + QAL( LPALCGETSTRING, alcGetString ); \ + QAL( LPALCGETINTEGERV, alcGetIntegerv ); \ + QAL( LPALCCAPTUREOPENDEVICE, alcCaptureOpenDevice ); \ + QAL( LPALCCAPTURECLOSEDEVICE, alcCaptureCloseDevice ); \ + QAL( LPALCCAPTURESTART, alcCaptureStart ); \ + QAL( LPALCCAPTURESTOP, alcCaptureStop ); \ + QAL( LPALCCAPTURESAMPLES, alcCaptureSamples ); + +static cvar_t *al_driver; +static cvar_t *al_device; + +static void *handle; +static ALCdevice *device; +static ALCcontext *context; + +#define QAL(type,func) static type q##func; +QALC_IMP +#undef QAL + +#define QAL(type,func) type q##func; +QAL_IMP +#undef QAL + +void QAL_Shutdown( void ) { + if( context ) { + qalcMakeContextCurrent( NULL ); + qalcDestroyContext( context ); + context = NULL; + } + if( device ) { + qalcCloseDevice( device ); + device = NULL; + } + +#define QAL(type,func) q##func = NULL; +QALC_IMP +QAL_IMP +#undef QAL + + Sys_FreeLibrary( handle ); + handle = NULL; + + al_driver->flags &= ~CVAR_SOUND; + al_device->flags &= ~CVAR_SOUND; +} + +qboolean QAL_Init( void ) { + al_driver = Cvar_Get( "al_driver", DEFAULT_OPENAL_DRIVER, CVAR_SOUND ); + al_device = Cvar_Get( "al_device", "", CVAR_SOUND ); + + Sys_LoadLibrary( al_driver->string, NULL, &handle ); + if( !handle ) { + return false; + } + +#define QAL(type,func) q##func = Sys_GetProcAddress( handle, #func ); +QALC_IMP +QAL_IMP +#undef QAL + + Com_DPrintf( "...opening OpenAL device: " ); + device = qalcOpenDevice( al_device->string[0] ? al_device->string : NULL ); + if( !device ) { + goto fail; + } + Com_DPrintf( "ok\n" ); + + Com_DPrintf( "...creating OpenAL context: " ); + context = qalcCreateContext( device, NULL ); + if( !context ) { + goto fail; + } + Com_DPrintf( "ok\n" ); + + Com_DPrintf( "...making context current: " ); + if( !qalcMakeContextCurrent( context ) ) { + goto fail; + } + Com_DPrintf( "ok\n" ); + + al_driver->flags |= CVAR_SOUND; + al_device->flags |= CVAR_SOUND; + + return true; + +fail: + Com_DPrintf( "failed\n" ); + QAL_Shutdown(); + return false; +} + diff --git a/src/client/sound/snd_al.c b/src/client/sound/snd_al.c new file mode 100644 index 00000000..8ba869a8 --- /dev/null +++ b/src/client/sound/snd_al.c @@ -0,0 +1,361 @@ +/* +This Source File was taken from the Q2Pro Port. + +Copyright (C) 2010 skuller.net + 2012 Some changes by the Yamagi Quake2 developers + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifdef USE_OPENAL + +#include "../header/client.h" +#include "header/local.h" +#include "qal_api.h" + +// translates from AL coordinate system to quake +#define AL_UnpackVector(v) -v[1],v[2],-v[0] +#define AL_CopyVector(a,b) ((b)[0]=-(a)[1],(b)[1]=(a)[2],(b)[2]=-(a)[0]) + +// OpenAL implementation should support at least this number of sources +#define MIN_CHANNELS 16 + +static ALuint s_srcnums[MAX_CHANNELS]; +static int s_framecount; + +void AL_SoundInfo( void ) { + Com_Printf( "AL_VENDOR: %s\n", qalGetString( AL_VENDOR ) ); + Com_Printf( "AL_RENDERER: %s\n", qalGetString( AL_RENDERER ) ); + Com_Printf( "AL_VERSION: %s\n", qalGetString( AL_VERSION ) ); + Com_Printf( "AL_EXTENSIONS: %s\n", qalGetString( AL_EXTENSIONS ) ); + Com_Printf( "Number of sources: %d\n", s_numchannels ); +} + +qboolean AL_Init( void ) { + int i; + + if( !QAL_Init() ) { + Com_EPrintf( "OpenAL failed to initialize.\n" ); + return false; + } + + // check for linear distance extension + if( !qalIsExtensionPresent( "AL_EXT_LINEAR_DISTANCE" ) ) { + Com_EPrintf( "Required AL_EXT_LINEAR_DISTANCE extension is missing.\n" ); + goto fail; + } + + // generate source names + qalGetError(); + for( i = 0; i < MAX_CHANNELS; i++ ) { + qalGenSources( 1, &s_srcnums[i] ); + if( qalGetError() != AL_NO_ERROR ) { + break; + } + } + + if( i < MIN_CHANNELS ) { + Com_EPrintf( "Required at least %d sources, but got %d.\n", MIN_CHANNELS, i ); + goto fail; + } + + s_numchannels = i; + + Com_Printf( "OpenAL initialized.\n" ); + return true; + +fail: + QAL_Shutdown(); + return false; +} + +void AL_Shutdown( void ) { + Com_Printf( "Shutting down OpenAL.\n" ); + + if( s_numchannels ) { + // delete source names + qalDeleteSources( s_numchannels, s_srcnums ); + memset( s_srcnums, 0, sizeof( s_srcnums ) ); + s_numchannels = 0; + } + + QAL_Shutdown(); +} + +sfxcache_t *AL_UploadSfx( sfx_t *s, wavinfo_t *s_info, byte *data ) { + sfxcache_t *sc; + ALsizei size = s_info->samples * s_info->width; + ALenum format = s_info->width == 2 ? AL_FORMAT_MONO16 : AL_FORMAT_MONO8; + ALuint name; + + if( !size ) { + // s->error = Q_ERR_TOO_FEW; FIXME: do I want this information? + return NULL; + } + + qalGetError(); + qalGenBuffers( 1, &name ); + qalBufferData( name, format, data, size, s_info->rate ); + if( qalGetError() != AL_NO_ERROR ) { + // s->error = Q_ERR_LIBRARY_ERROR; FIXME: do I want this info? + return NULL; + } + + // allocate placeholder sfxcache + sc = s->cache = S_Malloc( sizeof( *sc ) ); + sc->length = s_info->samples * 1000 / s_info->rate; // in msec + sc->loopstart = s_info->loopstart; + sc->width = s_info->width; + sc->size = size; + sc->bufnum = name; + + return sc; +} + +void AL_DeleteSfx( sfx_t *s ) { + sfxcache_t *sc; + ALuint name; + + sc = s->cache; + if( !sc ) { + return; + } + + name = sc->bufnum; + qalDeleteBuffers( 1, &name ); +} + +void AL_StopChannel( channel_t *ch ) { +#ifdef _DEBUG + if (s_show->integer > 1) + Com_Printf("%s: %s\n", __func__, ch->sfx->name ); +#endif + + // stop it + qalSourceStop( ch->srcnum ); + qalSourcei( ch->srcnum, AL_BUFFER, AL_NONE ); + memset (ch, 0, sizeof(*ch)); +} + +static void AL_Spatialize( channel_t *ch ) { + vec3_t origin; + + // anything coming from the view entity will always be full volume + // no attenuation = no spatialization + if( ch->entnum == -1 || ch->entnum == cl.playernum + 1 || !ch->dist_mult ) { + VectorCopy( listener_origin, origin ); + } else if( ch->fixed_origin ) { + VectorCopy( ch->origin, origin ); + } else { + CL_GetEntitySoundOrigin( ch->entnum, origin ); + } + + qalSource3f( ch->srcnum, AL_POSITION, AL_UnpackVector( origin ) ); +} + +void AL_PlayChannel( channel_t *ch ) { + sfxcache_t *sc = ch->sfx->cache; + +#ifdef _DEBUG + if (s_show->integer > 1) + Com_Printf("%s: %s\n", __func__, ch->sfx->name ); +#endif + + ch->srcnum = s_srcnums[ch - channels]; + qalGetError(); + qalSourcei( ch->srcnum, AL_BUFFER, sc->bufnum ); + //qalSourcei( ch->srcnum, AL_LOOPING, sc->loopstart == -1 ? AL_FALSE : AL_TRUE ); + qalSourcei( ch->srcnum, AL_LOOPING, ch->autosound ? AL_TRUE : AL_FALSE ); + qalSourcef( ch->srcnum, AL_GAIN, ch->master_vol ); + qalSourcef( ch->srcnum, AL_REFERENCE_DISTANCE, SOUND_FULLVOLUME ); + qalSourcef( ch->srcnum, AL_MAX_DISTANCE, 8192 ); + qalSourcef( ch->srcnum, AL_ROLLOFF_FACTOR, ch->dist_mult * ( 8192 - SOUND_FULLVOLUME ) ); + + AL_Spatialize( ch ); + + // play it + qalSourcePlay( ch->srcnum ); + if( qalGetError() != AL_NO_ERROR ) { + AL_StopChannel( ch ); + } +} + +void AL_StopAllChannels( void ) { + int i; + channel_t *ch; + + ch = channels; + for( i = 0; i < s_numchannels; i++, ch++ ) { + if (!ch->sfx) + continue; + AL_StopChannel( ch ); + } +} + +static channel_t *AL_FindLoopingSound( int entnum, sfx_t *sfx ) { + int i; + channel_t *ch; + + ch = channels; + for( i = 0; i < s_numchannels; i++, ch++ ) { + if( !ch->sfx ) + continue; + if( !ch->autosound ) + continue; + if( ch->entnum != entnum ) + continue; + if( ch->sfx != sfx ) + continue; + return ch; + } + + return NULL; +} + +static void AL_AddLoopSounds( void ) { + int i; + int sounds[64]; // 64 is MAX_PACKET_ENTITIES in YQ2 (there's no define for it, though :/) + channel_t *ch; + sfx_t *sfx; + sfxcache_t *sc; + int num; + entity_state_t *ent; + + if( cls.state != ca_active || sv_paused->value || !s_ambient->value ) { + return; + } + + S_BuildSoundList( sounds ); + + for( i = 0; i < cl.frame.numEntities; i++ ) { + if (!sounds[i]) + continue; + + sfx = S_SfxForHandle( cl.sound_precache[sounds[i]] ); + if (!sfx) + continue; // bad sound effect + sc = sfx->cache; + if (!sc) + continue; + + num = ( cl.frame.firstEntity + i ) & (MAX_PARSE_ENTITIES-1); + ent = &cl.entityStates[num]; + + ch = AL_FindLoopingSound( ent->number, sfx ); + if( ch ) { + ch->autoframe = s_framecount; + ch->end = paintedtime + sc->length; + continue; + } + + // allocate a channel + ch = S_PickChannel(0, 0); + if (!ch) + continue; + + ch->autosound = true; // remove next frame + ch->autoframe = s_framecount; + ch->sfx = sfx; + ch->entnum = ent->number; + ch->master_vol = 1; + ch->dist_mult = SOUND_LOOPATTENUATE; + ch->end = paintedtime + sc->length; + + AL_PlayChannel( ch ); + } +} + +static void AL_IssuePlaysounds( void ) { + playsound_t *ps; + + // start any playsounds + while (1) { + ps = s_pendingplays.next; + if (ps == &s_pendingplays) + break; // no more pending sounds + if (ps->begin > paintedtime) + break; + S_IssuePlaysound (ps); + } +} + +void AL_Update( void ) { + int i; + channel_t *ch; + vec_t orientation[6]; + + /* + if( !s_active ) { + return; + } + */ + + paintedtime = cl.time; + + // set listener parameters + qalListener3f( AL_POSITION, AL_UnpackVector( listener_origin ) ); + AL_CopyVector( listener_forward, orientation ); + AL_CopyVector( listener_up, orientation + 3 ); + qalListenerfv( AL_ORIENTATION, orientation ); + qalListenerf( AL_GAIN, s_volume->value ); + qalDistanceModel( AL_LINEAR_DISTANCE_CLAMPED ); + + // update spatialization for dynamic sounds + ch = channels; + for( i = 0; i < s_numchannels; i++, ch++ ) { + if( !ch->sfx ) + continue; + + if( ch->autosound ) { + // autosounds are regenerated fresh each frame + if( ch->autoframe != s_framecount ) { + AL_StopChannel( ch ); + continue; + } + } else { + ALenum state; + + qalGetError(); + qalGetSourcei( ch->srcnum, AL_SOURCE_STATE, &state ); + if( qalGetError() != AL_NO_ERROR || state == AL_STOPPED ) { + AL_StopChannel( ch ); + continue; + } + } + +#ifdef _DEBUG + if (s_show->integer) { + Com_Printf ("%.1f %s\n", ch->master_vol, ch->sfx->name); + // total++; + } +#endif + + AL_Spatialize(ch); // respatialize channel + } + + s_framecount++; + + // add loopsounds + AL_AddLoopSounds (); + + // FIXME: About here some ogg vorbis stuff (maybe calling OGG_Stream() + // like in S_Update()) should be done. + + AL_IssuePlaysounds(); +} + +#endif // USE_OPENAL diff --git a/src/client/sound/snd_dma.c b/src/client/sound/snd_dma.c index 20273b42..12b83edc 100644 --- a/src/client/sound/snd_dma.c +++ b/src/client/sound/snd_dma.c @@ -32,7 +32,6 @@ void S_Play ( void ); void S_SoundList ( void ); -void S_Update_ (); void S_StopAllSounds ( void ); /* only begin attenuating sound volumes when outside the FULLVOLUME range */ @@ -42,9 +41,10 @@ void S_StopAllSounds ( void ); int s_registration_sequence; channel_t channels [ MAX_CHANNELS ]; +int s_numchannels; qboolean snd_initialized = false; -int sound_started = 0; +sndstarted_t sound_started = SS_NOT; dma_t dma; @@ -79,6 +79,7 @@ cvar_t *s_loadas8bit; cvar_t *s_khz; cvar_t *s_mixahead; cvar_t *s_show; +cvar_t *s_ambient; int s_rawend; portable_samplepair_t s_rawsamples [ MAX_RAW_SAMPLES ]; @@ -86,15 +87,8 @@ portable_samplepair_t s_rawsamples [ MAX_RAW_SAMPLES ]; /* * User-setable variables */ -void -S_SoundInfo_f ( void ) -{ - if ( !sound_started ) - { - Com_Printf( "sound system not started\n" ); - return; - } +static void DMA_SoundInfo (void) { Com_Printf( "%5d stereo\n", dma.channels - 1 ); Com_Printf( "%5d samples\n", dma.samples ); Com_Printf( "%5d samplepos\n", dma.samplepos ); @@ -104,6 +98,25 @@ S_SoundInfo_f ( void ) Com_Printf( "%p dma buffer\n", dma.buffer ); } +void +S_SoundInfo_f ( void ) +{ + if ( !sound_started ) + { + Com_Printf( "sound system not started\n" ); + return; + } +#if USE_OPENAL + if(sound_started == SS_OAL) { + AL_SoundInfo(); + } else +#endif + DMA_SoundInfo(); + +} + + + void S_Init ( void ) { @@ -116,16 +129,15 @@ S_Init ( void ) if ( !cv->value ) { Com_Printf( "not initializing.\n" ); - } + } else { - else - { s_volume = Cvar_Get( "s_volume", "0.7", CVAR_ARCHIVE ); s_khz = Cvar_Get( "s_khz", "44", CVAR_ARCHIVE ); s_loadas8bit = Cvar_Get( "s_loadas8bit", "0", CVAR_ARCHIVE ); s_mixahead = Cvar_Get( "s_mixahead", "0.14", CVAR_ARCHIVE ); s_show = Cvar_Get( "s_show", "0", 0 ); s_testsound = Cvar_Get( "s_testsound", "0", 0 ); + s_ambient = Cvar_Get( "s_ambient", "1", 0); Cmd_AddCommand( "play", S_Play ); Cmd_AddCommand( "stopsound", S_StopAllSounds ); @@ -133,15 +145,21 @@ S_Init ( void ) Cmd_AddCommand( "soundinfo", S_SoundInfo_f ); Cmd_AddCommand( "ogg_init", OGG_Init ); Cmd_AddCommand( "ogg_shutdown", OGG_Shutdown ); - - if ( !SNDDMA_Init() ) - { - return; +#if USE_OPENAL + // FIXME: cvar for soundsystem to use? + if( AL_Init() ) { + sound_started = SS_OAL; } + else +#endif + if ( SNDDMA_Init() ) + { + sound_started = SS_DMA; + } else { + sound_started = SS_NOT; + return; + } - S_InitScaletable(); - - sound_started = 1; num_sfx = 0; soundtime = 0; @@ -170,6 +188,8 @@ S_Shutdown ( void ) return; } + S_StopAllSounds(); + /* free all sounds */ for ( i = 0, sfx = known_sfx; i < num_sfx; i++, sfx++ ) { @@ -177,20 +197,38 @@ S_Shutdown ( void ) { continue; } - +#if USE_OPENAL + if ( sound_started == SS_OAL ) + { + AL_DeleteSfx( sfx ); + } +#endif if ( sfx->cache ) { Z_Free( sfx->cache ); } + if ( sfx->truename ) + { + Z_Free( sfx-> truename ); + } } memset( known_sfx, 0, sizeof ( known_sfx ) ); num_sfx = 0; - sound_started = 0; + sound_started = SS_NOT; OGG_Shutdown(); - SNDDMA_Shutdown(); + +#if USE_OPENAL + if( sound_started == SS_OAL ) + { + AL_Shutdown(); + } else +#endif + SNDDMA_Shutdown(); + + s_numchannels = 0; Cmd_RemoveCommand( "soundlist" ); Cmd_RemoveCommand( "soundinfo" ); @@ -399,7 +437,7 @@ S_PickChannel ( int entnum, int entchannel ) first_to_die = -1; life_left = 0x7fffffff; - for ( ch_idx = 0; ch_idx < MAX_CHANNELS; ch_idx++ ) + for ( ch_idx = 0; ch_idx < s_numchannels; ch_idx++ ) { /* channel 0 never overrides */ if ( ( entchannel != 0 ) && @@ -430,6 +468,13 @@ S_PickChannel ( int entnum, int entchannel ) } ch = &channels [ first_to_die ]; + +#if USE_OPENAL + if( sound_started == SS_OAL && ch->sfx ) + { + AL_StopChannel( ch ); + } +#endif memset( ch, 0, sizeof ( *ch ) ); return ( ch ); @@ -585,6 +630,13 @@ S_IssuePlaysound ( playsound_t *ps ) return; } + sc = S_LoadSound( ps->sfx ); + if( !sc ) { + Com_Printf( "S_IssuePlaysound: couldn't load %s\n", ps->sfx->name ); + S_FreePlaysound( ps ); + return; + } + /* spatialize */ if ( ps->attenuation == ATTN_STATIC ) { @@ -603,16 +655,15 @@ S_IssuePlaysound ( playsound_t *ps ) VectorCopy( ps->origin, ch->origin ); ch->fixed_origin = ps->fixed_origin; - S_Spatialize( ch ); +#if USE_OPENAL + if( sound_started == SS_OAL) + { + AL_PlayChannel( ch ); + } else +#endif + S_Spatialize( ch ); ch->pos = 0; - sc = S_LoadSound( ch->sfx ); - - if (!sc) - { - return; - } - ch->end = paintedtime + sc->length; /* free the playsound */ @@ -682,6 +733,28 @@ S_RegisterSexedSound ( entity_state_t *ent, char *base ) return ( sfx ); } +static int DMA_DriftBeginofs( float timeofs ) { + /* drift s_beginofs */ + int start = (int) ( cl.frame.servertime * 0.001f * dma.speed + s_beginofs ); + + if ( start < paintedtime ) + { + start = paintedtime; + s_beginofs = (int) ( start - ( cl.frame.servertime * 0.001f * dma.speed ) ); + } + else if ( start > paintedtime + 0.3f * dma.speed ) + { + start = (int) ( paintedtime + 0.1f * dma.speed ); + s_beginofs = (int) ( start - ( cl.frame.servertime * 0.001f * dma.speed ) ); + } + else + { + s_beginofs -= 10; + } + + return timeofs ? start + timeofs * dma.speed : paintedtime; +} + /* * Validates the parms and ques the sound up if pos is NULL, the sound * will be dynamically sourced from the entity Entchannel 0 will never @@ -693,7 +766,6 @@ S_StartSound ( vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol sfxcache_t *sc; int vol; playsound_t *ps, *sort; - int start; if ( !sound_started ) { @@ -708,6 +780,9 @@ S_StartSound ( vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol if ( sfx->name [ 0 ] == '*' ) { sfx = S_RegisterSexedSound( &cl_entities [ entnum ].current, sfx->name ); + if( !sfx ) { + return; + } } /* make sure the sound is loaded */ @@ -744,34 +819,12 @@ S_StartSound ( vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol ps->volume = vol; ps->sfx = sfx; - /* drift s_beginofs */ - start = (int) ( cl.frame.servertime * 0.001f * dma.speed + s_beginofs ); - - if ( start < paintedtime ) - { - start = paintedtime; - s_beginofs = (int) ( start - ( cl.frame.servertime * 0.001f * dma.speed ) ); - } - else if ( start > paintedtime + 0.3f * dma.speed ) - { - start = (int) ( paintedtime + 0.1f * dma.speed ); - s_beginofs = (int) ( start - ( cl.frame.servertime * 0.001f * dma.speed ) ); - } - else - { - s_beginofs -= 10; - } - - if ( !timeofs ) - { - ps->begin = paintedtime; - } - else - { - ps->begin = (int) ( start + timeofs * dma.speed ); - } - - ps->volume = fvol * 255; +#if USE_OPENAL + if( sound_started == SS_OAL ) { + ps->begin = paintedtime + timeofs * 1000; + } else +#endif + ps->begin = DMA_DriftBeginofs(timeofs); /* sort into the pending sound list */ for ( sort = s_pendingplays.next; @@ -872,10 +925,34 @@ S_StopAllSounds ( void ) s_playsounds [ i ].next->prev = &s_playsounds [ i ]; } +#if USE_OPENAL + if( sound_started == SS_OAL ) { + AL_StopAllChannels(); + } else +#endif + S_ClearBuffer(); + /* clear all the channels */ memset( channels, 0, sizeof ( channels ) ); +} - S_ClearBuffer(); +void S_BuildSoundList( int *sounds ) { + int i; + int num; + entity_state_t *ent; + + for ( i = 0; i < cl.frame.num_entities; i++ ) + { + num = ( cl.frame.parse_entities + i ) & ( MAX_PARSE_ENTITIES - 1 ); + ent = &cl_parse_entities [ num ]; + if( s_ambient->value == 2 && !ent->modelindex ) { + sounds[i] = 0; + } else if( s_ambient->value == 3 && ent->number != cl.playernum + 1) { + sounds[i] = 0; + } else { + sounds[i] = ent->sound; + } + } } /* @@ -906,17 +983,12 @@ S_AddLoopSounds ( void ) return; } - if ( !cl.sound_prepped ) + if ( !cl.sound_prepped || !s_ambient->value || sv_paused->value ) { return; } - for ( i = 0; i < cl.frame.num_entities; i++ ) - { - num = ( cl.frame.parse_entities + i ) & ( MAX_PARSE_ENTITIES - 1 ); - ent = &cl_parse_entities [ num ]; - sounds [ i ] = ent->sound; - } + S_BuildSoundList( sounds ); for ( i = 0; i < cl.frame.num_entities; i++ ) { @@ -1171,21 +1243,29 @@ S_Update ( vec3_t origin, vec3_t forward, vec3_t right, vec3_t up ) return; } - /* rebuild scale tables if volume is modified */ - if ( s_volume->modified ) - { - S_InitScaletable(); - } - VectorCopy( origin, listener_origin ); VectorCopy( forward, listener_forward ); VectorCopy( right, listener_right ); VectorCopy( up, listener_up ); + +#if USE_OPENAL + if( sound_started == SS_OAL ) { + AL_Update(); + return; + } +#endif + + /* rebuild scale tables if volume is modified */ + if ( s_volume->modified ) + { + S_InitScaletable(); + } + /* update spatialization for dynamic sounds */ ch = channels; - for ( i = 0; i < MAX_CHANNELS; i++, ch++ ) + for ( i = 0; i < s_numchannels; i++, ch++ ) { if ( !ch->sfx ) { @@ -1217,7 +1297,7 @@ S_Update ( vec3_t origin, vec3_t forward, vec3_t right, vec3_t up ) total = 0; ch = channels; - for ( i = 0; i < MAX_CHANNELS; i++, ch++ ) + for ( i = 0; i < s_numchannels; i++, ch++ ) { if ( ch->sfx && ( ch->leftvol || ch->rightvol ) ) { @@ -1231,12 +1311,6 @@ S_Update ( vec3_t origin, vec3_t forward, vec3_t right, vec3_t up ) /* stream music */ OGG_Stream(); - - /* mix some sound */ - if ( !sound_started ) - { - return; - } SNDDMA_BeginPainting(); @@ -1274,7 +1348,7 @@ S_Update ( vec3_t origin, vec3_t forward, vec3_t right, vec3_t up ) S_PaintChannels( endtime ); - SNDDMA_Submit(); + SNDDMA_Submit(); } void diff --git a/src/client/sound/snd_mem.c b/src/client/sound/snd_mem.c index 9bcdb6b8..97848c10 100644 --- a/src/client/sound/snd_mem.c +++ b/src/client/sound/snd_mem.c @@ -149,10 +149,7 @@ S_LoadSound ( sfx_t *s ) if ( name [ 0 ] == '#' ) { strcpy( namebuffer, &name [ 1 ] ); - } - - else - { + } else { Com_sprintf( namebuffer, sizeof ( namebuffer ), "sound/%s", name ); } @@ -199,7 +196,12 @@ S_LoadSound ( sfx_t *s ) sc->width = info.width; sc->stereo = info.channels; - ResampleSfx( s, sc->speed, sc->width, data + info.dataofs ); +#if USE_OPENAL + if (sound_started == SS_OAL) + sc = AL_UploadSfx(s, &info, data + info.dataofs); + else +#endif + ResampleSfx( s, sc->speed, sc->width, data + info.dataofs ); FS_FreeFile( data ); diff --git a/src/client/sound/snd_mix.c b/src/client/sound/snd_mix.c index a2ed5d6a..b7c01a07 100644 --- a/src/client/sound/snd_mix.c +++ b/src/client/sound/snd_mix.c @@ -265,7 +265,7 @@ S_PaintChannels ( int endtime ) /* paint in the channels. */ ch = channels; - for ( i = 0; i < MAX_CHANNELS; i++, ch++ ) + for ( i = 0; i < s_numchannels; i++, ch++ ) { ltime = paintedtime; diff --git a/src/client/sound/snd_vorbis.c b/src/client/sound/snd_vorbis.c index 3ce12525..76a18f29 100644 --- a/src/client/sound/snd_vorbis.c +++ b/src/client/sound/snd_vorbis.c @@ -37,9 +37,6 @@ #include "header/local.h" #include "header/vorbis.h" -extern int sound_started; /* Sound initialization flag. */ -extern cvar_t *fs_basedir; /* Path to "music". */ - qboolean ogg_first_init = true; /* First initialization flag. */ qboolean ogg_started = false; /* Initialization flag. */ int ogg_bigendian = 0; diff --git a/src/client/sound/snd_wav.c b/src/client/sound/snd_wav.c index 59cfc046..4cdc6061 100644 --- a/src/client/sound/snd_wav.c +++ b/src/client/sound/snd_wav.c @@ -27,6 +27,9 @@ #include "../header/client.h" #include "header/local.h" +// FIXME: this code is really fucked up, those global variables make me sick. +// someone should clean this up one day.. + byte *data_p; byte *iff_end; byte *last_chunk; diff --git a/src/sdl/sound.c b/src/sdl/sound.c index 5f9c9fac..3ff21337 100644 --- a/src/sdl/sound.c +++ b/src/sdl/sound.c @@ -208,6 +208,9 @@ SNDDMA_Init(void) dmasize = (dmabackend->samples * (dmabackend->samplebits / 8)); dmabackend->buffer = calloc(1, dmasize); + s_numchannels = MAX_CHANNELS; + S_InitScaletable(); + SDL_PauseAudio(0); Com_Printf("SDL audio initialized.\n"); From f4d5040a73704cd6398957a831a0f29339243a51 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 22 Apr 2012 00:24:50 +0000 Subject: [PATCH 03/29] Add OpenAL stuff to Makefile, make it compile and work (no streaming sound yet) It works \o/ It's still hacky so it needs more work. And streaming sound (OGG music, sound from videos) is still missing. --- Makefile | 6 +++-- src/client/sound/qal_api.c | 24 +++++++++++-------- src/client/sound/snd_al.c | 48 ++++++++++++++++++++++++++++++-------- src/client/sound/snd_dma.c | 10 +++++--- src/client/sound/snd_mem.c | 45 ++++++++++++++++++----------------- 5 files changed, 86 insertions(+), 47 deletions(-) diff --git a/Makefile b/Makefile index b4647039..a9f2a645 100644 --- a/Makefile +++ b/Makefile @@ -134,9 +134,9 @@ client: build/client/%.o: %.c @echo '===> CC $<' ${Q}mkdir -p $(@D) - ${Q}$(CC) -c $(CFLAGS) $(X11CFLAGS) $(SDLCFLAGS) $(INCLUDE) -o $@ $< + ${Q}$(CC) -c $(CFLAGS) $(X11CFLAGS) $(SDLCFLAGS) $(INCLUDE) -DUSE_OPENAL -DDEFAULT_OPENAL_DRIVER='"libopenal.so.1"' -o $@ $< -release/quake2 : LDFLAGS += -lvorbis -lvorbisfile -logg -lz +release/quake2 : LDFLAGS += -lvorbis -lvorbisfile -logg -lz -lopenal # ---------- @@ -262,6 +262,8 @@ CLIENT_OBJS_ := \ src/client/menu/menu.o \ src/client/menu/qmenu.o \ src/client/menu/videomenu.o \ + src/client/sound/qal_api.o \ + src/client/sound/snd_al.o \ src/client/sound/snd_dma.o \ src/client/sound/snd_mem.o \ src/client/sound/snd_mix.o \ diff --git a/src/client/sound/qal_api.c b/src/client/sound/qal_api.c index 0ff579b5..5844d587 100644 --- a/src/client/sound/qal_api.c +++ b/src/client/sound/qal_api.c @@ -20,9 +20,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "common.h" +#include "../../common/header/common.h" #include "header/qal_api.h" #include +#include #define QALC_IMP \ QAL( LPALCCREATECONTEXT, alcCreateContext ); \ @@ -77,23 +78,26 @@ QALC_IMP QAL_IMP #undef QAL - Sys_FreeLibrary( handle ); + //Sys_FreeLibrary( handle ); + dlclose(handle); handle = NULL; - al_driver->flags &= ~CVAR_SOUND; - al_device->flags &= ~CVAR_SOUND; + al_driver->flags &= ~CVAR_ARCHIVE; + al_device->flags &= ~CVAR_ARCHIVE; } qboolean QAL_Init( void ) { - al_driver = Cvar_Get( "al_driver", DEFAULT_OPENAL_DRIVER, CVAR_SOUND ); - al_device = Cvar_Get( "al_device", "", CVAR_SOUND ); + // DEFAULT_OPENAL_DRIVER is a define from the Makefile + al_driver = Cvar_Get( "al_driver", DEFAULT_OPENAL_DRIVER, CVAR_ARCHIVE ); + al_device = Cvar_Get( "al_device", "", CVAR_ARCHIVE ); - Sys_LoadLibrary( al_driver->string, NULL, &handle ); + handle = dlopen( al_driver->string, RTLD_LAZY ); + //Sys_LoadLibrary( al_driver->string, NULL, &handle ); if( !handle ) { return false; } -#define QAL(type,func) q##func = Sys_GetProcAddress( handle, #func ); +#define QAL(type,func) q##func = dlsym( handle, #func ); QALC_IMP QAL_IMP #undef QAL @@ -118,8 +122,8 @@ QAL_IMP } Com_DPrintf( "ok\n" ); - al_driver->flags |= CVAR_SOUND; - al_device->flags |= CVAR_SOUND; + al_driver->flags |= CVAR_ARCHIVE; + al_device->flags |= CVAR_ARCHIVE; return true; diff --git a/src/client/sound/snd_al.c b/src/client/sound/snd_al.c index 8ba869a8..be5cae4e 100644 --- a/src/client/sound/snd_al.c +++ b/src/client/sound/snd_al.c @@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../header/client.h" #include "header/local.h" -#include "qal_api.h" +#include "header/qal_api.h" // translates from AL coordinate system to quake #define AL_UnpackVector(v) -v[1],v[2],-v[0] @@ -49,13 +49,13 @@ qboolean AL_Init( void ) { int i; if( !QAL_Init() ) { - Com_EPrintf( "OpenAL failed to initialize.\n" ); + Com_Printf( "ERROR: OpenAL failed to initialize.\n" ); return false; } // check for linear distance extension if( !qalIsExtensionPresent( "AL_EXT_LINEAR_DISTANCE" ) ) { - Com_EPrintf( "Required AL_EXT_LINEAR_DISTANCE extension is missing.\n" ); + Com_Printf( "ERROR: Required AL_EXT_LINEAR_DISTANCE extension is missing.\n" ); goto fail; } @@ -69,7 +69,7 @@ qboolean AL_Init( void ) { } if( i < MIN_CHANNELS ) { - Com_EPrintf( "Required at least %d sources, but got %d.\n", MIN_CHANNELS, i ); + Com_Printf( "ERROR: Required at least %d sources, but got %d.\n", MIN_CHANNELS, i ); goto fail; } @@ -116,7 +116,7 @@ sfxcache_t *AL_UploadSfx( sfx_t *s, wavinfo_t *s_info, byte *data ) { } // allocate placeholder sfxcache - sc = s->cache = S_Malloc( sizeof( *sc ) ); + sc = s->cache = Z_TagMalloc(sizeof(*sc), 0); // FIXME: TAG_SOUND instead of 0 - this possibly leaks! sc->length = s_info->samples * 1000 / s_info->rate; // in msec sc->loopstart = s_info->loopstart; sc->width = s_info->width; @@ -235,25 +235,25 @@ static void AL_AddLoopSounds( void ) { int num; entity_state_t *ent; - if( cls.state != ca_active || sv_paused->value || !s_ambient->value ) { + if( cls.state != ca_active || !s_ambient->value ) { // FIXME: sv_paused->value || return; } S_BuildSoundList( sounds ); - for( i = 0; i < cl.frame.numEntities; i++ ) { + for( i = 0; i < cl.frame.num_entities; i++ ) { if (!sounds[i]) continue; - sfx = S_SfxForHandle( cl.sound_precache[sounds[i]] ); + sfx = cl.sound_precache[sounds[i]]; if (!sfx) continue; // bad sound effect sc = sfx->cache; if (!sc) continue; - num = ( cl.frame.firstEntity + i ) & (MAX_PARSE_ENTITIES-1); - ent = &cl.entityStates[num]; + num = ( cl.frame.parse_entities + i ) & ( MAX_PARSE_ENTITIES - 1 ); + ent = &cl_parse_entities [ num ]; ch = AL_FindLoopingSound( ent->number, sfx ); if( ch ) { @@ -291,6 +291,34 @@ static void AL_IssuePlaysounds( void ) { break; S_IssuePlaysound (ps); } + // TODO: streaming sounds from s_rawsamples, equivalent to code below - see also ioq3's code + +#if 0 + /* clear the paint buffer */ + if ( s_rawend < paintedtime ) + { + memset( paintbuffer, 0, ( end - paintedtime ) * sizeof ( portable_samplepair_t ) ); + } + else + { + /* copy from the streaming sound source */ + int s; + int stop; + + stop = ( end < s_rawend ) ? end : s_rawend; + + for ( i = paintedtime; i < stop; i++ ) + { + s = i & ( MAX_RAW_SAMPLES - 1 ); + paintbuffer [ i - paintedtime ] = s_rawsamples [ s ]; + } + + for ( ; i < end; i++ ) + { + paintbuffer [ i - paintedtime ].left = paintbuffer [ i - paintedtime ].right = 0; + } + } +#endif } void AL_Update( void ) { diff --git a/src/client/sound/snd_dma.c b/src/client/sound/snd_dma.c index 12b83edc..2c09927a 100644 --- a/src/client/sound/snd_dma.c +++ b/src/client/sound/snd_dma.c @@ -216,7 +216,6 @@ S_Shutdown ( void ) memset( known_sfx, 0, sizeof ( known_sfx ) ); num_sfx = 0; - sound_started = SS_NOT; OGG_Shutdown(); @@ -228,6 +227,7 @@ S_Shutdown ( void ) #endif SNDDMA_Shutdown(); + sound_started = SS_NOT; s_numchannels = 0; Cmd_RemoveCommand( "soundlist" ); @@ -983,7 +983,7 @@ S_AddLoopSounds ( void ) return; } - if ( !cl.sound_prepped || !s_ambient->value || sv_paused->value ) + if ( !cl.sound_prepped || !s_ambient->value ) // FIXME: || sv_paused->value ) { return; } @@ -1101,12 +1101,16 @@ S_RawSamples ( int samples, int rate, int width, int channels, byte *data, float return; } + // FIXME!! + if( sound_started == SS_OAL ) + return; + if ( s_rawend < paintedtime ) { s_rawend = paintedtime; } - scale = (float) rate / dma.speed; + scale = (float) rate / dma.speed; // FIXME: dma.speed is not available (0) when using openal intVolume = (int) (256 * volume); if ( ( channels == 2 ) && ( width == 2 ) ) diff --git a/src/client/sound/snd_mem.c b/src/client/sound/snd_mem.c index 97848c10..81a2d19f 100644 --- a/src/client/sound/snd_mem.c +++ b/src/client/sound/snd_mem.c @@ -170,32 +170,33 @@ S_LoadSound ( sfx_t *s ) FS_FreeFile( data ); return ( NULL ); } + if (sound_started != SS_OAL) { + stepscale = (float) info.rate / dma.speed; + len = (int) ( info.samples / stepscale ); - stepscale = (float) info.rate / dma.speed; - len = (int) ( info.samples / stepscale ); + if ( ( info.samples == 0 ) || ( len == 0 ) ) + { + Com_Printf( "WARNING: Zero length sound encountered: %s\n", s->name ); + FS_FreeFile( data ); + return ( NULL ); + } - if ( ( info.samples == 0 ) || ( len == 0 ) ) - { - Com_Printf( "WARNING: Zero length sound encountered: %s\n", s->name ); - FS_FreeFile( data ); - return ( NULL ); + len = len * info.width * info.channels; + sc = s->cache = Z_Malloc( len + sizeof ( sfxcache_t ) ); + + if ( !sc ) + { + FS_FreeFile( data ); + return ( NULL ); + } + + sc->length = info.samples; + sc->loopstart = info.loopstart; + sc->speed = info.rate; + sc->width = info.width; + sc->stereo = info.channels; } - len = len * info.width * info.channels; - sc = s->cache = Z_Malloc( len + sizeof ( sfxcache_t ) ); - - if ( !sc ) - { - FS_FreeFile( data ); - return ( NULL ); - } - - sc->length = info.samples; - sc->loopstart = info.loopstart; - sc->speed = info.rate; - sc->width = info.width; - sc->stereo = info.channels; - #if USE_OPENAL if (sound_started == SS_OAL) sc = AL_UploadSfx(s, &info, data + info.dataofs); From 6384b850f1987d8061367c73dab4c6181cbfaccd Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 22 Apr 2012 15:57:59 +0000 Subject: [PATCH 04/29] Remove redundancy --- src/client/sound/snd_mix.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/client/sound/snd_mix.c b/src/client/sound/snd_mix.c index b7c01a07..85f9661b 100644 --- a/src/client/sound/snd_mix.c +++ b/src/client/sound/snd_mix.c @@ -202,12 +202,6 @@ S_PaintChannels ( int endtime ) end = paintedtime + PAINTBUFFER_SIZE; } - /* start any playsounds */ - if ( endtime - paintedtime > PAINTBUFFER_SIZE ) - { - end = paintedtime + PAINTBUFFER_SIZE; - } - /* start any playsounds */ for ( ; ; ) { @@ -258,6 +252,7 @@ S_PaintChannels ( int endtime ) for ( ; i < end; i++ ) { + // TODO: this could be done with memset paintbuffer [ i - paintedtime ].left = paintbuffer [ i - paintedtime ].right = 0; } } From 04fd7f2cda178aedec9a299c9ab3c429f379479f Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 22 Apr 2012 15:59:18 +0000 Subject: [PATCH 05/29] OpenAL Streaming Sound stuff from zeq2, but adapted/stripped down for our needs. Videos work (for me), music does not (yet) --- src/client/sound/header/local.h | 1 + src/client/sound/snd_al.c | 242 ++++++++++++++++++++++++++------ src/client/sound/snd_dma.c | 18 ++- src/client/sound/snd_vorbis.c | 2 +- 4 files changed, 211 insertions(+), 52 deletions(-) diff --git a/src/client/sound/header/local.h b/src/client/sound/header/local.h index 1cfe08d4..74e9700b 100644 --- a/src/client/sound/header/local.h +++ b/src/client/sound/header/local.h @@ -181,6 +181,7 @@ void AL_StopChannel( channel_t *ch ); void AL_PlayChannel( channel_t *ch ); void AL_StopAllChannels( void ); void AL_Update( void ); +void AL_RawSamples( int samples, int rate, int width, int channels, byte *data, float volume ); #endif #endif diff --git a/src/client/sound/snd_al.c b/src/client/sound/snd_al.c index be5cae4e..8629c224 100644 --- a/src/client/sound/snd_al.c +++ b/src/client/sound/snd_al.c @@ -1,8 +1,9 @@ /* -This Source File was taken from the Q2Pro Port. +This Source File - except for the last few functions - see the other copyright +notice further down the - was taken from the Q2Pro Port. Copyright (C) 2010 skuller.net - 2012 Some changes by the Yamagi Quake2 developers + 2012 Some changes by the Yamagi Quake II developers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -26,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../header/client.h" #include "header/local.h" #include "header/qal_api.h" +#include "header/vorbis.h" // translates from AL coordinate system to quake #define AL_UnpackVector(v) -v[1],v[2],-v[0] @@ -34,9 +36,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // OpenAL implementation should support at least this number of sources #define MIN_CHANNELS 16 -static ALuint s_srcnums[MAX_CHANNELS]; +qboolean streamPlaying; +static ALuint streamSource; + +static ALuint s_srcnums[MAX_CHANNELS-1]; static int s_framecount; +// Forward Declarations +static void S_AL_StreamUpdate( void ); +static void S_AL_StreamDie( void ); +// /Forward Declarations + void AL_SoundInfo( void ) { Com_Printf( "AL_VENDOR: %s\n", qalGetString( AL_VENDOR ) ); Com_Printf( "AL_RENDERER: %s\n", qalGetString( AL_RENDERER ) ); @@ -45,6 +55,18 @@ void AL_SoundInfo( void ) { Com_Printf( "Number of sources: %d\n", s_numchannels ); } +static void AL_InitStreamSource() { + qalSourcei (streamSource, AL_BUFFER, 0 ); + qalSourcei (streamSource, AL_LOOPING, AL_FALSE ); + qalSource3f(streamSource, AL_POSITION, 0.0, 0.0, 0.0); + qalSource3f(streamSource, AL_VELOCITY, 0.0, 0.0, 0.0); + qalSource3f(streamSource, AL_DIRECTION, 0.0, 0.0, 0.0); + qalSourcef (streamSource, AL_ROLLOFF_FACTOR, 0.0 ); + qalSourcei (streamSource, AL_SOURCE_RELATIVE, AL_TRUE ); + + // srcList[cursrc].scaleGain = 0.0f; FIXME - something like that? +} + qboolean AL_Init( void ) { int i; @@ -61,19 +83,29 @@ qboolean AL_Init( void ) { // generate source names qalGetError(); - for( i = 0; i < MAX_CHANNELS; i++ ) { - qalGenSources( 1, &s_srcnums[i] ); - if( qalGetError() != AL_NO_ERROR ) { - break; - } - } + qalGenSources( 1, &streamSource ); + if( qalGetError() != AL_NO_ERROR ) + { + Com_Printf( "ERROR: Couldn't get a single Source.\n" ); + goto fail; - if( i < MIN_CHANNELS ) { - Com_Printf( "ERROR: Required at least %d sources, but got %d.\n", MIN_CHANNELS, i ); - goto fail; + } else { + // -1 because we already got one channel for streaming + for( i = 0; i < MAX_CHANNELS - 1; i++ ) { + qalGenSources( 1, &s_srcnums[i] ); + if( qalGetError() != AL_NO_ERROR ) { + break; + } + } + + if( i < MIN_CHANNELS - 1 ) { + Com_Printf( "ERROR: Required at least %d sources, but got %d.\n", MIN_CHANNELS, i+1 ); + goto fail; + } } s_numchannels = i; + AL_InitStreamSource(); Com_Printf( "OpenAL initialized.\n" ); return true; @@ -92,7 +124,7 @@ void AL_Shutdown( void ) { memset( s_srcnums, 0, sizeof( s_srcnums ) ); s_numchannels = 0; } - + S_AL_StreamDie(); QAL_Shutdown(); } @@ -204,6 +236,8 @@ void AL_StopAllChannels( void ) { continue; AL_StopChannel( ch ); } + s_rawend = 0; + S_AL_StreamDie(); } static channel_t *AL_FindLoopingSound( int entnum, sfx_t *sfx ) { @@ -291,34 +325,6 @@ static void AL_IssuePlaysounds( void ) { break; S_IssuePlaysound (ps); } - // TODO: streaming sounds from s_rawsamples, equivalent to code below - see also ioq3's code - -#if 0 - /* clear the paint buffer */ - if ( s_rawend < paintedtime ) - { - memset( paintbuffer, 0, ( end - paintedtime ) * sizeof ( portable_samplepair_t ) ); - } - else - { - /* copy from the streaming sound source */ - int s; - int stop; - - stop = ( end < s_rawend ) ? end : s_rawend; - - for ( i = paintedtime; i < stop; i++ ) - { - s = i & ( MAX_RAW_SAMPLES - 1 ); - paintbuffer [ i - paintedtime ] = s_rawsamples [ s ]; - } - - for ( ; i < end; i++ ) - { - paintbuffer [ i - paintedtime ].left = paintbuffer [ i - paintedtime ].right = 0; - } - } -#endif } void AL_Update( void ) { @@ -326,13 +332,13 @@ void AL_Update( void ) { channel_t *ch; vec_t orientation[6]; - /* + /* FIXME if( !s_active ) { return; } */ - paintedtime = cl.time; + // paintedtime = cl.time; // FIXME: this does *not* make music work. // set listener parameters qalListener3f( AL_POSITION, AL_UnpackVector( listener_origin ) ); @@ -380,10 +386,156 @@ void AL_Update( void ) { // add loopsounds AL_AddLoopSounds (); - // FIXME: About here some ogg vorbis stuff (maybe calling OGG_Stream() - // like in S_Update()) should be done. + // add music + OGG_Stream(); + S_AL_StreamUpdate(); AL_IssuePlaysounds(); + + //paintedtime = ; ?? + // evtl paintedtime = soundtime falls paintedtime < soundtime - aber soundtime ist eigentlich DMA spezifisch + // paintedtime = cl.time; FIXME: das allein reicht nicht damit musik funktioniert + +} + +/* +=========================================================================== +* The remaining functions in this file are from zeq2 who seem to have got +* them from ioquake3. Adapted for Yamagi Quake II (e.g. we only need one +* non-spatialized stream) +* +* They came with the following copyright notice (modified to make clear +* that only the rest of this file is affected): + +Copyright (C) 1999-2005 Id Software, Inc. +Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com) + 2012 Some changes by the Yamagi Quake II developers + +The rest of this file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== + */ + +static void S_AL_StreamDie( void ) +{ + int numBuffers; + + + streamPlaying = false; + qalSourceStop(streamSource); + + // Un-queue any buffers, and delete them + qalGetSourcei( streamSource, AL_BUFFERS_PROCESSED, &numBuffers ); + while( numBuffers-- ) + { + ALuint buffer; + qalSourceUnqueueBuffers(streamSource, 1, &buffer); + qalDeleteBuffers(1, &buffer); + } + + // S_AL_FreeStreamChannel(stream); +} + +static void S_AL_StreamUpdate( void ) +{ + int numBuffers; + ALint state; + + // Un-queue any buffers, and delete them + qalGetSourcei( streamSource, AL_BUFFERS_PROCESSED, &numBuffers ); + while( numBuffers-- ) + { + ALuint buffer; + qalSourceUnqueueBuffers(streamSource, 1, &buffer); + qalDeleteBuffers(1, &buffer); + } + + // Start the streamSource playing if necessary + qalGetSourcei( streamSource, AL_BUFFERS_QUEUED, &numBuffers ); + + qalGetSourcei(streamSource, AL_SOURCE_STATE, &state); + if(state == AL_STOPPED) + { + streamPlaying = false; + + // If there are no buffers queued up, release the streamSource + //if( !numBuffers ) + // S_AL_FreeStreamChannel( stream ); + } + + if( !streamPlaying && numBuffers ) + { + qalSourcePlay( streamSource ); + streamPlaying = true; + } +} + +static ALuint S_AL_Format(int width, int channels) +{ + ALuint format = AL_FORMAT_MONO16; + + // Work out format + if(width == 1) + { + if(channels == 1) + format = AL_FORMAT_MONO8; + else if(channels == 2) + format = AL_FORMAT_STEREO8; + } + else if(width == 2) + { + if(channels == 1) + format = AL_FORMAT_MONO16; + else if(channels == 2) + format = AL_FORMAT_STEREO16; + } + + return format; +} + +void AL_RawSamples( int samples, int rate, int width, int channels, byte *data, float volume ) +{ + ALuint buffer; + ALuint format; + + format = S_AL_Format( width, channels ); + + // Create a buffer, and stuff the data into it + qalGenBuffers(1, &buffer); + qalBufferData(buffer, format, (ALvoid *)data, (samples * width * channels), rate); + + // set volume + qalSourcef( streamSource, AL_GAIN, volume ); + + // Shove the data onto the streamSource + qalSourceQueueBuffers(streamSource, 1, &buffer); + + // emulate behavior of S_RawSamples for s_rawend + s_rawend += samples; + /* + // get this buffers speed/frequency + ALint speed = 0; + qalGetBufferi(buffer, AL_FREQUENCY, &speed); + // FIXME: the buffers are leaking I think + float scale = (float) rate / speed; + + if( samples > 0 && scale >= 0.0f ) { + s_rawend += samples/scale; + } + */ } #endif // USE_OPENAL diff --git a/src/client/sound/snd_dma.c b/src/client/sound/snd_dma.c index 2c09927a..86fa0d96 100644 --- a/src/client/sound/snd_dma.c +++ b/src/client/sound/snd_dma.c @@ -1101,16 +1101,20 @@ S_RawSamples ( int samples, int rate, int width, int channels, byte *data, float return; } - // FIXME!! - if( sound_started == SS_OAL ) - return; - if ( s_rawend < paintedtime ) { s_rawend = paintedtime; } - scale = (float) rate / dma.speed; // FIXME: dma.speed is not available (0) when using openal +#if USE_OPENAL + if( sound_started == SS_OAL ) + { + AL_RawSamples(samples, rate, width, channels, data, volume); + return; + } +#endif + + scale = (float) rate / dma.speed; intVolume = (int) (256 * volume); if ( ( channels == 2 ) && ( width == 2 ) ) @@ -1243,7 +1247,9 @@ S_Update ( vec3_t origin, vec3_t forward, vec3_t right, vec3_t up ) * dma buffer while loading */ if ( cls.disable_screen ) { - S_ClearBuffer(); + if (sound_started == SS_DMA ) { + S_ClearBuffer(); + } return; } diff --git a/src/client/sound/snd_vorbis.c b/src/client/sound/snd_vorbis.c index 76a18f29..f22af971 100644 --- a/src/client/sound/snd_vorbis.c +++ b/src/client/sound/snd_vorbis.c @@ -602,7 +602,7 @@ OGG_Stream ( void ) return; } - while ( ogg_status == PLAY && paintedtime + MAX_RAW_SAMPLES - 2048 > s_rawend ) + while ( ogg_status == PLAY && paintedtime + MAX_RAW_SAMPLES - 2048 > s_rawend ) { OGG_Read(); } From e388a425b4c9a9abb564aeb980a9663b24265f12 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Sun, 22 Apr 2012 17:50:15 +0000 Subject: [PATCH 06/29] Enable OGG/Vorbis playback in OpenAL mode. --- src/client/sound/header/local.h | 3 +++ src/client/sound/snd_al.c | 7 +++++++ src/client/sound/snd_vorbis.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/src/client/sound/header/local.h b/src/client/sound/header/local.h index 74e9700b..8e7f95e6 100644 --- a/src/client/sound/header/local.h +++ b/src/client/sound/header/local.h @@ -171,6 +171,9 @@ void S_BuildSoundList( int *sounds ); #define SOUND_FULLVOLUME 80 #define SOUND_LOOPATTENUATE 0.003 +// number of buffers in flight (needed for ogg) +extern int active_buffers; + // for snd_al.c - copied from Q2Pro and adapted void AL_SoundInfo( void ); qboolean AL_Init( void ); diff --git a/src/client/sound/snd_al.c b/src/client/sound/snd_al.c index 8629c224..75875833 100644 --- a/src/client/sound/snd_al.c +++ b/src/client/sound/snd_al.c @@ -37,6 +37,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MIN_CHANNELS 16 qboolean streamPlaying; +int active_buffers; + static ALuint streamSource; static ALuint s_srcnums[MAX_CHANNELS-1]; @@ -142,6 +144,7 @@ sfxcache_t *AL_UploadSfx( sfx_t *s, wavinfo_t *s_info, byte *data ) { qalGetError(); qalGenBuffers( 1, &name ); qalBufferData( name, format, data, size, s_info->rate ); + active_buffers++; if( qalGetError() != AL_NO_ERROR ) { // s->error = Q_ERR_LIBRARY_ERROR; FIXME: do I want this info? return NULL; @@ -169,6 +172,7 @@ void AL_DeleteSfx( sfx_t *s ) { name = sc->bufnum; qalDeleteBuffers( 1, &name ); + active_buffers--; } void AL_StopChannel( channel_t *ch ) { @@ -444,6 +448,7 @@ static void S_AL_StreamDie( void ) ALuint buffer; qalSourceUnqueueBuffers(streamSource, 1, &buffer); qalDeleteBuffers(1, &buffer); + active_buffers--; } // S_AL_FreeStreamChannel(stream); @@ -461,6 +466,7 @@ static void S_AL_StreamUpdate( void ) ALuint buffer; qalSourceUnqueueBuffers(streamSource, 1, &buffer); qalDeleteBuffers(1, &buffer); + active_buffers--; } // Start the streamSource playing if necessary @@ -516,6 +522,7 @@ void AL_RawSamples( int samples, int rate, int width, int channels, byte *data, // Create a buffer, and stuff the data into it qalGenBuffers(1, &buffer); qalBufferData(buffer, format, (ALvoid *)data, (samples * width * channels), rate); + active_buffers++; // set volume qalSourcef( streamSource, AL_GAIN, volume ); diff --git a/src/client/sound/snd_vorbis.c b/src/client/sound/snd_vorbis.c index f22af971..6f616224 100644 --- a/src/client/sound/snd_vorbis.c +++ b/src/client/sound/snd_vorbis.c @@ -602,10 +602,38 @@ OGG_Stream ( void ) return; } +#ifdef USE_OPENAL + /* + */ + if ( ogg_status == PLAY ) + { + + /* active_buffers are all active OpenAL buffers, + buffering normal sfx _and_ ogg/vorbis samples. + Empirical testing showed that there are most + likly never more than 256 sfx buffers active. + Read ogg samples into buffers until there are + 384 active buffers. This keeps at least 128 + ogg buffers (128 * 4096 Byte = 512 KByte) in + the memory. That's about 30 second of music + playback, more than enough to rule out buffer + underruns even at very, very, very low frame + rates. */ + while ( active_buffers <= 384 ) + { + OGG_Read(); + } + } +#else + /* Read that number samples into the buffer, that + were played since the last call to this function. + This keeps the buffer at all times at an "optimal" + fill level. */ while ( ogg_status == PLAY && paintedtime + MAX_RAW_SAMPLES - 2048 > s_rawend ) { OGG_Read(); } +#endif } /* From 65914b342ded083498e8cc103614581b331839e2 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 22 Apr 2012 17:59:03 +0000 Subject: [PATCH 07/29] Allow DMA/SDL sound in OGG_Stream when compiling with USE_OPENAL --- src/client/sound/snd_vorbis.c | 60 +++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/src/client/sound/snd_vorbis.c b/src/client/sound/snd_vorbis.c index 6f616224..f2432ca6 100644 --- a/src/client/sound/snd_vorbis.c +++ b/src/client/sound/snd_vorbis.c @@ -602,38 +602,42 @@ OGG_Stream ( void ) return; } -#ifdef USE_OPENAL - /* - */ + if ( ogg_status == PLAY ) { - - /* active_buffers are all active OpenAL buffers, - buffering normal sfx _and_ ogg/vorbis samples. - Empirical testing showed that there are most - likly never more than 256 sfx buffers active. - Read ogg samples into buffers until there are - 384 active buffers. This keeps at least 128 - ogg buffers (128 * 4096 Byte = 512 KByte) in - the memory. That's about 30 second of music - playback, more than enough to rule out buffer - underruns even at very, very, very low frame - rates. */ - while ( active_buffers <= 384 ) +#ifdef USE_OPENAL + if( sound_started == SS_OAL ) { - OGG_Read(); - } - } -#else - /* Read that number samples into the buffer, that - were played since the last call to this function. - This keeps the buffer at all times at an "optimal" - fill level. */ - while ( ogg_status == PLAY && paintedtime + MAX_RAW_SAMPLES - 2048 > s_rawend ) - { - OGG_Read(); - } + /* active_buffers are all active OpenAL buffers, + buffering normal sfx _and_ ogg/vorbis samples. + Empirical testing showed that there are most + likly never more than 256 sfx buffers active. + Read ogg samples into buffers until there are + 384 active buffers. This keeps at least 128 + ogg buffers (128 * 4096 Byte = 512 KByte) in + the memory. That's about 30 second of music + playback, more than enough to rule out buffer + underruns even at very, very, very low frame + rates. */ + while ( active_buffers <= 384 ) + { + OGG_Read(); + } + } else { // using DMA/SDL #endif + /* Read that number samples into the buffer, that + were played since the last call to this function. + This keeps the buffer at all times at an "optimal" + fill level. */ + while ( paintedtime + MAX_RAW_SAMPLES - 2048 > s_rawend ) + { + OGG_Read(); + } +#ifdef USE_OPENAL + } // using DMA/SDL +#endif + } // ogg_status == PLAY + } /* From efd85a76c6e8b10b639e19350a094a632e9e403d Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 22 Apr 2012 20:14:56 +0000 Subject: [PATCH 08/29] Updated paintedtime in OpenAL mode so shotgun sounds right probably fixes other issues as well. --- src/client/sound/snd_al.c | 7 +------ src/client/sound/snd_dma.c | 1 - 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/client/sound/snd_al.c b/src/client/sound/snd_al.c index 75875833..df7a526f 100644 --- a/src/client/sound/snd_al.c +++ b/src/client/sound/snd_al.c @@ -342,7 +342,7 @@ void AL_Update( void ) { } */ - // paintedtime = cl.time; // FIXME: this does *not* make music work. + paintedtime = cl.time; // set listener parameters qalListener3f( AL_POSITION, AL_UnpackVector( listener_origin ) ); @@ -395,11 +395,6 @@ void AL_Update( void ) { S_AL_StreamUpdate(); AL_IssuePlaysounds(); - - //paintedtime = ; ?? - // evtl paintedtime = soundtime falls paintedtime < soundtime - aber soundtime ist eigentlich DMA spezifisch - // paintedtime = cl.time; FIXME: das allein reicht nicht damit musik funktioniert - } /* diff --git a/src/client/sound/snd_dma.c b/src/client/sound/snd_dma.c index 86fa0d96..e9a05e70 100644 --- a/src/client/sound/snd_dma.c +++ b/src/client/sound/snd_dma.c @@ -877,7 +877,6 @@ S_ClearBuffer ( void ) { clear = 0x80; } - else { clear = 0; From 8bfc61b56412d5219f7d18d1a830c4ce37b56276 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 22 Apr 2012 20:27:02 +0000 Subject: [PATCH 09/29] Introduce s_openal to enable/disable OpenAL And fix possible dangling else problem in that code --- src/client/sound/snd_dma.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/client/sound/snd_dma.c b/src/client/sound/snd_dma.c index e9a05e70..4266d9fd 100644 --- a/src/client/sound/snd_dma.c +++ b/src/client/sound/snd_dma.c @@ -145,12 +145,18 @@ S_Init ( void ) Cmd_AddCommand( "soundinfo", S_SoundInfo_f ); Cmd_AddCommand( "ogg_init", OGG_Init ); Cmd_AddCommand( "ogg_shutdown", OGG_Shutdown ); -#if USE_OPENAL - // FIXME: cvar for soundsystem to use? - if( AL_Init() ) { + +#if ! USE_OPENAL + cv = Cvar_Get( "s_openal", 0, CVAR_ARCHIVE); + if( cv->value ) { + Com_Printf("Warning: Ignoring s_openal, as this binary has no OpenAL support!"); + } +#else + cv = Cvar_Get( "s_openal", 1, CVAR_ARCHIVE); + if( cv->value && AL_Init() ) { sound_started = SS_OAL; } - else + else { #endif if ( SNDDMA_Init() ) { @@ -159,6 +165,9 @@ S_Init ( void ) sound_started = SS_NOT; return; } +#if USE_OPENAL + } // this is a bit ugly but prevents dangling else problems +#endif num_sfx = 0; From 3d7013e12bfc16352c65dba1ba3a97dd46388cd9 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 22 Apr 2012 20:28:41 +0000 Subject: [PATCH 10/29] Fix: Cvar_Get needs a string as default value, not an int.. --- src/client/sound/snd_dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/sound/snd_dma.c b/src/client/sound/snd_dma.c index 4266d9fd..388bfdc2 100644 --- a/src/client/sound/snd_dma.c +++ b/src/client/sound/snd_dma.c @@ -147,12 +147,12 @@ S_Init ( void ) Cmd_AddCommand( "ogg_shutdown", OGG_Shutdown ); #if ! USE_OPENAL - cv = Cvar_Get( "s_openal", 0, CVAR_ARCHIVE); + cv = Cvar_Get( "s_openal", "0", CVAR_ARCHIVE); if( cv->value ) { Com_Printf("Warning: Ignoring s_openal, as this binary has no OpenAL support!"); } #else - cv = Cvar_Get( "s_openal", 1, CVAR_ARCHIVE); + cv = Cvar_Get( "s_openal", "1", CVAR_ARCHIVE); if( cv->value && AL_Init() ) { sound_started = SS_OAL; } From 3bce2a212a7340e73caccf581662b6078d0b1b14 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Mon, 23 Apr 2012 07:59:39 +0000 Subject: [PATCH 11/29] - Use a better way to calculate the number of buffers used by OGG/Vorbis. 24 buffers are enough for smooth and stutter free playback and ensure, that OGG_Stop() is effective nearly immediately. - Change C99 comments to C89, since snd_vorbis.c is a C89 file. Caedes will beat me for this :/ --- src/client/sound/snd_vorbis.c | 41 ++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/src/client/sound/snd_vorbis.c b/src/client/sound/snd_vorbis.c index f2432ca6..9d44a9b0 100644 --- a/src/client/sound/snd_vorbis.c +++ b/src/client/sound/snd_vorbis.c @@ -54,6 +54,7 @@ cvar_t *ogg_sequence; /* Sequence play indicator. */ cvar_t *ogg_volume; /* Music volume. */ OggVorbis_File ovFile; /* Ogg Vorbis file. */ vorbis_info *ogg_info; /* Ogg Vorbis file information */ +int ogg_numbufs; /* Number of buffers for OpenAL */ /* * Initialize the Ogg Vorbis subsystem. @@ -583,6 +584,7 @@ OGG_Stop ( void ) ov_clear( &ovFile ); ogg_status = STOP; ogg_info = NULL; + ogg_numbufs = 0; if ( ogg_buffer != NULL ) { @@ -606,24 +608,32 @@ OGG_Stream ( void ) if ( ogg_status == PLAY ) { #ifdef USE_OPENAL - if( sound_started == SS_OAL ) + if ( sound_started == SS_OAL ) { + /* Calculate the number of buffers used + for storing decoded OGG/Vorbis data. + We take the number of active buffers + at startup (at this point most of the + samples should be precached and loaded + into buffers) and add 24. Empircal + testing showed, that at most times + at least 12 buffers remain available + for OGG/Vorbis, enough for about 0.5 + seconds playback. The music won't + stutter as long as the framerate + stayes over 3 FPS. */ + if ( ogg_numbufs == 0 ) + { + ogg_numbufs = active_buffers + 24; + } + /* active_buffers are all active OpenAL buffers, - buffering normal sfx _and_ ogg/vorbis samples. - Empirical testing showed that there are most - likly never more than 256 sfx buffers active. - Read ogg samples into buffers until there are - 384 active buffers. This keeps at least 128 - ogg buffers (128 * 4096 Byte = 512 KByte) in - the memory. That's about 30 second of music - playback, more than enough to rule out buffer - underruns even at very, very, very low frame - rates. */ - while ( active_buffers <= 384 ) + buffering normal sfx _and_ ogg/vorbis samples. */ + while ( active_buffers <= ogg_numbufs ) { OGG_Read(); } - } else { // using DMA/SDL + } else { /* using DMA/SDL */ #endif /* Read that number samples into the buffer, that were played since the last call to this function. @@ -634,9 +644,9 @@ OGG_Stream ( void ) OGG_Read(); } #ifdef USE_OPENAL - } // using DMA/SDL + } /* using DMA/SDL */ #endif - } // ogg_status == PLAY + } /* ogg_status == PLAY */ } @@ -722,6 +732,7 @@ OGG_PauseCmd ( void ) if ( ogg_status == PLAY ) { ogg_status = PAUSE; + ogg_numbufs = 0; } } From 678e50bf8d04d370acf9308dc0d3a2da991f4659 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Mon, 23 Apr 2012 13:23:47 +0000 Subject: [PATCH 12/29] Raise the volume of a positioned sample by 384 instead of 255 when using OpenAL. This makes them much more distinguishable from the background music. --- src/client/sound/snd_dma.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/client/sound/snd_dma.c b/src/client/sound/snd_dma.c index 388bfdc2..d709444f 100644 --- a/src/client/sound/snd_dma.c +++ b/src/client/sound/snd_dma.c @@ -773,7 +773,6 @@ void S_StartSound ( vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs ) { sfxcache_t *sc; - int vol; playsound_t *ps, *sort; if ( !sound_started ) @@ -802,8 +801,6 @@ S_StartSound ( vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol return; /* couldn't load the sound's data */ } - vol = fvol * 255; - /* make the playsound_t */ ps = S_AllocPlaysound(); @@ -825,15 +822,19 @@ S_StartSound ( vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol ps->entnum = entnum; ps->entchannel = entchannel; ps->attenuation = attenuation; - ps->volume = vol; ps->sfx = sfx; #if USE_OPENAL if( sound_started == SS_OAL ) { ps->begin = paintedtime + timeofs * 1000; - } else + ps->volume = fvol * 384; + } + else #endif + { ps->begin = DMA_DriftBeginofs(timeofs); + ps->volume = fvol * 255; + } /* sort into the pending sound list */ for ( sort = s_pendingplays.next; From 134878e99609e90c14a1555be7562ed13f5391cf Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Mon, 23 Apr 2012 13:44:12 +0000 Subject: [PATCH 13/29] - Some more minor style cleanup - Much improved startup log messages --- src/client/sound/qal_api.c | 13 +++++++------ src/client/sound/snd_al.c | 3 ++- src/client/sound/snd_dma.c | 17 +++++++++++------ 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/client/sound/qal_api.c b/src/client/sound/qal_api.c index 5844d587..065ad2f7 100644 --- a/src/client/sound/qal_api.c +++ b/src/client/sound/qal_api.c @@ -91,6 +91,7 @@ qboolean QAL_Init( void ) { al_driver = Cvar_Get( "al_driver", DEFAULT_OPENAL_DRIVER, CVAR_ARCHIVE ); al_device = Cvar_Get( "al_device", "", CVAR_ARCHIVE ); + Com_Printf("LoadLibrary(%s)\n", al_driver->string); handle = dlopen( al_driver->string, RTLD_LAZY ); //Sys_LoadLibrary( al_driver->string, NULL, &handle ); if( !handle ) { @@ -102,25 +103,25 @@ QALC_IMP QAL_IMP #undef QAL - Com_DPrintf( "...opening OpenAL device: " ); + Com_Printf( "...opening OpenAL device: " ); device = qalcOpenDevice( al_device->string[0] ? al_device->string : NULL ); if( !device ) { goto fail; } - Com_DPrintf( "ok\n" ); + Com_Printf( "ok\n" ); - Com_DPrintf( "...creating OpenAL context: " ); + Com_Printf( "...creating OpenAL context: " ); context = qalcCreateContext( device, NULL ); if( !context ) { goto fail; } - Com_DPrintf( "ok\n" ); + Com_Printf( "ok\n" ); - Com_DPrintf( "...making context current: " ); + Com_Printf( "...making context current: " ); if( !qalcMakeContextCurrent( context ) ) { goto fail; } - Com_DPrintf( "ok\n" ); + Com_Printf( "ok\n" ); al_driver->flags |= CVAR_ARCHIVE; al_device->flags |= CVAR_ARCHIVE; diff --git a/src/client/sound/snd_al.c b/src/client/sound/snd_al.c index df7a526f..a8a4ca63 100644 --- a/src/client/sound/snd_al.c +++ b/src/client/sound/snd_al.c @@ -109,7 +109,8 @@ qboolean AL_Init( void ) { s_numchannels = i; AL_InitStreamSource(); - Com_Printf( "OpenAL initialized.\n" ); + Com_Printf("\nOpenAL setting:\n"); + AL_SoundInfo(); return true; fail: diff --git a/src/client/sound/snd_dma.c b/src/client/sound/snd_dma.c index d709444f..83b7e922 100644 --- a/src/client/sound/snd_dma.c +++ b/src/client/sound/snd_dma.c @@ -166,7 +166,7 @@ S_Init ( void ) return; } #if USE_OPENAL - } // this is a bit ugly but prevents dangling else problems + } /* this is a bit ugly but prevents dangling else problems */ #endif num_sfx = 0; @@ -174,7 +174,14 @@ S_Init ( void ) soundtime = 0; paintedtime = 0; - Com_Printf( "sound sampling rate: %i\n", dma.speed ); +#if USE_OPENAL + if(sound_started == SS_DMA) + { + Com_Printf( "Sound sampling rate: %i\n", dma.speed ); + } +#else + Com_Printf( "Sound sampling rate: %i\n", dma.speed ); +#endif S_StopAllSounds(); OGG_Init(); @@ -825,7 +832,8 @@ S_StartSound ( vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol ps->sfx = sfx; #if USE_OPENAL - if( sound_started == SS_OAL ) { + if( sound_started == SS_OAL ) + { ps->begin = paintedtime + timeofs * 1000; ps->volume = fvol * 384; } @@ -1175,9 +1183,6 @@ S_RawSamples ( int samples, int rate, int width, int channels, byte *data, float dst = s_rawend & ( MAX_RAW_SAMPLES - 1 ); s_rawend++; - // s_rawsamples [dst].left = ((char *) data)[src * 2] * intVolume; - // s_rawsamples [dst].right = ((char *) data)[src * 2 + 1] * intVolume; - /* the above doesn't work for me with U8, only the unsigned ones below do */ s_rawsamples [dst].left = (((byte *) data)[src * 2] - 128) * intVolume; s_rawsamples [dst].right = (((byte *) data)[src * 2 + 1] - 128) * intVolume; } From bdba132db7426018c03c1ae0d101acece084c9af Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Mon, 23 Apr 2012 13:45:37 +0000 Subject: [PATCH 14/29] Add TODO --- TODO | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 00000000..92f66164 --- /dev/null +++ b/TODO @@ -0,0 +1,3 @@ +- Dateien neu ordnen (vielleicht besser nach dem Merge...) +- Das Makro-Gefrickel in qal_api.c ist ja wohl widerlichST. + Lass uns da lieber ein paar Codeblöcke haben, als DAS DA! From e9066663c4c0117f91c24fae8f3b45a7dd939fd2 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Mon, 23 Apr 2012 13:54:57 +0000 Subject: [PATCH 15/29] More TODO --- TODO | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/TODO b/TODO index 92f66164..345ea4a7 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,11 @@ - Dateien neu ordnen (vielleicht besser nach dem Merge...) - Das Makro-Gefrickel in qal_api.c ist ja wohl widerlichST. Lass uns da lieber ein paar Codeblöcke haben, als DAS DA! +- Doku anpassen +- yq2-Lizenzheader und Inhaltsbeschreibungen +- Den Kram hinter _DEBUG raus oder konsistent mit dem Rest + vom Source +- Die zwei Lizenzheader in snd_al.c sind irgendwie seltsam. + Ich habe da grundsätzlich nichts gegen, aber da Anwälte + kreativ sein können, sollte man das vielleicht doch noch + in 2 Dateien spalten oder so From 90d08111856e9f86e9b4b8856ddd9bfd5558102b Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Mon, 23 Apr 2012 13:55:25 +0000 Subject: [PATCH 16/29] Delete all OpenAL sources at shutdown --- src/client/sound/snd_al.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/client/sound/snd_al.c b/src/client/sound/snd_al.c index a8a4ca63..6954a138 100644 --- a/src/client/sound/snd_al.c +++ b/src/client/sound/snd_al.c @@ -121,6 +121,8 @@ fail: void AL_Shutdown( void ) { Com_Printf( "Shutting down OpenAL.\n" ); + qalDeleteSources(1, &streamSource); + if( s_numchannels ) { // delete source names qalDeleteSources( s_numchannels, s_srcnums ); From 479aae4a9c350a369d67197acc0772e6c14961b7 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Mon, 23 Apr 2012 13:57:36 +0000 Subject: [PATCH 17/29] *gna* This \n got lost on the way --- src/client/sound/snd_al.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/client/sound/snd_al.c b/src/client/sound/snd_al.c index 6954a138..c61f69ff 100644 --- a/src/client/sound/snd_al.c +++ b/src/client/sound/snd_al.c @@ -111,6 +111,7 @@ qboolean AL_Init( void ) { Com_Printf("\nOpenAL setting:\n"); AL_SoundInfo(); + Com_Printf("\n"); return true; fail: From 79c137254a75fe4222ad8945474f09726876554c Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Tue, 24 Apr 2012 13:22:05 +0000 Subject: [PATCH 18/29] Rework qal_api.c and qal_api.h: - Reformat to match "our" coding style - Unroll all unreadable macros - Remove the use of goto --- src/client/sound/header/qal_api.h | 209 +++++++------ src/client/sound/qal_api.c | 487 ++++++++++++++++++++++++------ 2 files changed, 499 insertions(+), 197 deletions(-) diff --git a/src/client/sound/header/qal_api.h b/src/client/sound/header/qal_api.h index 7948df72..24911463 100644 --- a/src/client/sound/header/qal_api.h +++ b/src/client/sound/header/qal_api.h @@ -1,107 +1,118 @@ /* -This Source File was taken from the Q2Pro Port. + * Copyright (C) 2012 Yamagi Burmeister + * Copyright (C) 2010 skuller.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + * + * ======================================================================= + * + * Header file to the low level "qal" API implementation. This source file + * was taken from Q2Pro and modified by the YQ2 authors. + * + * ======================================================================= + */ -Copyright (C) 2010 skuller.net - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#define AL_NO_PROTOTYPES #include -#define QAL_IMP \ - QAL( LPALENABLE, alEnable ); \ - QAL( LPALDISABLE, alDisable ); \ - QAL( LPALISENABLED, alIsEnabled ); \ - QAL( LPALGETSTRING, alGetString ); \ - QAL( LPALGETBOOLEANV, alGetBooleanv ); \ - QAL( LPALGETINTEGERV, alGetIntegerv ); \ - QAL( LPALGETFLOATV, alGetFloatv ); \ - QAL( LPALGETDOUBLEV, alGetDoublev ); \ - QAL( LPALGETBOOLEAN, alGetBoolean ); \ - QAL( LPALGETINTEGER, alGetInteger ); \ - QAL( LPALGETFLOAT, alGetFloat ); \ - QAL( LPALGETDOUBLE, alGetDouble ); \ - QAL( LPALGETERROR, alGetError ); \ - QAL( LPALISEXTENSIONPRESENT, alIsExtensionPresent ); \ - QAL( LPALGETPROCADDRESS, alGetProcAddress ); \ - QAL( LPALGETENUMVALUE, alGetEnumValue ); \ - QAL( LPALLISTENERF, alListenerf ); \ - QAL( LPALLISTENER3F, alListener3f ); \ - QAL( LPALLISTENERFV, alListenerfv ); \ - QAL( LPALLISTENERI, alListeneri ); \ - QAL( LPALLISTENER3I, alListener3i ); \ - QAL( LPALLISTENERIV, alListeneriv ); \ - QAL( LPALGETLISTENERF, alGetListenerf ); \ - QAL( LPALGETLISTENER3F, alGetListener3f ); \ - QAL( LPALGETLISTENERFV, alGetListenerfv ); \ - QAL( LPALGETLISTENERI, alGetListeneri ); \ - QAL( LPALGETLISTENER3I, alGetListener3i ); \ - QAL( LPALGETLISTENERIV, alGetListeneriv ); \ - QAL( LPALGENSOURCES, alGenSources ); \ - QAL( LPALDELETESOURCES, alDeleteSources ); \ - QAL( LPALISSOURCE, alIsSource ); \ - QAL( LPALSOURCEF, alSourcef ); \ - QAL( LPALSOURCE3F, alSource3f ); \ - QAL( LPALSOURCEFV, alSourcefv ); \ - QAL( LPALSOURCEI, alSourcei ); \ - QAL( LPALSOURCE3I, alSource3i ); \ - QAL( LPALSOURCEIV, alSourceiv ); \ - QAL( LPALGETSOURCEF, alGetSourcef ); \ - QAL( LPALGETSOURCE3F, alGetSource3f ); \ - QAL( LPALGETSOURCEFV, alGetSourcefv ); \ - QAL( LPALGETSOURCEI, alGetSourcei ); \ - QAL( LPALGETSOURCE3I, alGetSource3i ); \ - QAL( LPALGETSOURCEIV, alGetSourceiv ); \ - QAL( LPALSOURCEPLAYV, alSourcePlayv ); \ - QAL( LPALSOURCESTOPV, alSourceStopv ); \ - QAL( LPALSOURCEREWINDV, alSourceRewindv ); \ - QAL( LPALSOURCEPAUSEV, alSourcePausev ); \ - QAL( LPALSOURCEPLAY, alSourcePlay ); \ - QAL( LPALSOURCESTOP, alSourceStop ); \ - QAL( LPALSOURCEREWIND, alSourceRewind ); \ - QAL( LPALSOURCEPAUSE, alSourcePause ); \ - QAL( LPALSOURCEQUEUEBUFFERS, alSourceQueueBuffers ); \ - QAL( LPALSOURCEUNQUEUEBUFFERS, alSourceUnqueueBuffers ); \ - QAL( LPALGENBUFFERS, alGenBuffers ); \ - QAL( LPALDELETEBUFFERS, alDeleteBuffers ); \ - QAL( LPALISBUFFER, alIsBuffer ); \ - QAL( LPALBUFFERDATA, alBufferData ); \ - QAL( LPALBUFFERF, alBufferf ); \ - QAL( LPALBUFFER3F, alBuffer3f ); \ - QAL( LPALBUFFERFV, alBufferfv ); \ - QAL( LPALBUFFERI, alBufferi ); \ - QAL( LPALBUFFER3I, alBuffer3i ); \ - QAL( LPALBUFFERIV, alBufferiv ); \ - QAL( LPALGETBUFFERF, alGetBufferf ); \ - QAL( LPALGETBUFFER3F, alGetBuffer3f ); \ - QAL( LPALGETBUFFERFV, alGetBufferfv ); \ - QAL( LPALGETBUFFERI, alGetBufferi ); \ - QAL( LPALGETBUFFER3I, alGetBuffer3i ); \ - QAL( LPALGETBUFFERIV, alGetBufferiv ); \ - QAL( LPALDOPPLERFACTOR, alDopplerFactor ); \ - QAL( LPALDOPPLERVELOCITY, alDopplerVelocity ); \ - QAL( LPALSPEEDOFSOUND, alSpeedOfSound ); \ - QAL( LPALDISTANCEMODEL, alDistanceModel ); - -#define QAL(type,func) extern type q##func; -QAL_IMP -#undef QAL +/* Function pointers used to tie + the qal API to the OpenAL API */ +extern LPALENABLE qalEnable; +extern LPALDISABLE qalDisable; +extern LPALISENABLED qalIsEnabled; +extern LPALGETSTRING qalGetString; +extern LPALGETBOOLEANV qalGetBooleanv; +extern LPALGETINTEGERV qalGetIntegerv; +extern LPALGETFLOATV qalGetFloatv; +extern LPALGETDOUBLEV qalGetDoublev; +extern LPALGETBOOLEAN qalGetBoolean; +extern LPALGETINTEGER qalGetInteger; +extern LPALGETFLOAT qalGetFloat; +extern LPALGETDOUBLE qalGetDouble; +extern LPALGETERROR qalGetError; +extern LPALISEXTENSIONPRESENT qalIsExtensionPresent; +extern LPALGETPROCADDRESS qalGetProcAddress; +extern LPALGETENUMVALUE qalGetEnumValue; +extern LPALLISTENERF qalListenerf; +extern LPALLISTENER3F qalListener3f; +extern LPALLISTENERFV qalListenerfv; +extern LPALLISTENERI qalListeneri; +extern LPALLISTENER3I qalListener3i; +extern LPALLISTENERIV qalListeneriv; +extern LPALGETLISTENERF qalGetListenerf; +extern LPALGETLISTENER3F qalGetListener3f; +extern LPALGETLISTENERFV qalGetListenerfv; +extern LPALGETLISTENERI qalGetListeneri; +extern LPALGETLISTENER3I qalGetListener3i; +extern LPALGETLISTENERIV qalGetListeneriv; +extern LPALGENSOURCES qalGenSources; +extern LPALDELETESOURCES qalDeleteSources; +extern LPALISSOURCE qalIsSource; +extern LPALSOURCEF qalSourcef; +extern LPALSOURCE3F qalSource3f; +extern LPALSOURCEFV qalSourcefv; +extern LPALSOURCEI qalSourcei; +extern LPALSOURCE3I qalSource3i; +extern LPALSOURCEIV qalSourceiv; +extern LPALGETSOURCEF qalGetSourcef; +extern LPALGETSOURCE3F qalGetSource3f; +extern LPALGETSOURCEFV qalGetSourcefv; +extern LPALGETSOURCEI qalGetSourcei; +extern LPALGETSOURCE3I qalGetSource3i; +extern LPALGETSOURCEIV qalGetSourceiv; +extern LPALSOURCEPLAYV qalSourcePlayv; +extern LPALSOURCESTOPV qalSourceStopv; +extern LPALSOURCEREWINDV qalSourceRewindv; +extern LPALSOURCEPAUSEV qalSourcePausev; +extern LPALSOURCEPLAY qalSourcePlay; +extern LPALSOURCESTOP qalSourceStop; +extern LPALSOURCEREWIND qalSourceRewind; +extern LPALSOURCEPAUSE qalSourcePause; +extern LPALSOURCEQUEUEBUFFERS qalSourceQueueBuffers; +extern LPALSOURCEUNQUEUEBUFFERS qalSourceUnqueueBuffers; +extern LPALGENBUFFERS qalGenBuffers; +extern LPALDELETEBUFFERS qalDeleteBuffers; +extern LPALISBUFFER qalIsBuffer; +extern LPALBUFFERDATA qalBufferData; +extern LPALBUFFERF qalBufferf; +extern LPALBUFFER3F qalBuffer3f; +extern LPALBUFFERFV qalBufferfv; +extern LPALBUFFERI qalBufferi; +extern LPALBUFFER3I qalBuffer3i; +extern LPALBUFFERIV qalBufferiv; +extern LPALGETBUFFERF qalGetBufferf; +extern LPALGETBUFFER3F qalGetBuffer3f; +extern LPALGETBUFFERFV qalGetBufferfv; +extern LPALGETBUFFERI qalGetBufferi; +extern LPALGETBUFFER3I qalGetBuffer3i; +extern LPALGETBUFFERIV qalGetBufferiv; +extern LPALDOPPLERFACTOR qalDopplerFactor; +extern LPALDOPPLERVELOCITY qalDopplerVelocity; +extern LPALSPEEDOFSOUND qalSpeedOfSound; +extern LPALDISTANCEMODEL qalDistanceModel; +/* + * Loads the OpenAL shared lib, creates + * a context and device handle. + */ qboolean QAL_Init( void ); + +/* + * Shuts OpenAL down, frees all context and + * device handles and unloads the shared lib. + */ void QAL_Shutdown( void ); diff --git a/src/client/sound/qal_api.c b/src/client/sound/qal_api.c index 065ad2f7..5bf7393a 100644 --- a/src/client/sound/qal_api.c +++ b/src/client/sound/qal_api.c @@ -1,136 +1,427 @@ /* -This Source File was taken from the Q2Pro Port. + * Copyright (C) 2012 Yamagi Burmeister + * Copyright (C) 2010 skuller.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + * + * ======================================================================= + * + * Low level, platform depended "qal" API implementation. This files + * provides functions to load, initialize, shutdown und unload the + * OpenAL library and connects the "qal" funtion pointers to the + * OpenAL functions. This source file was taken from Q2Pro and + * modified by the YQ2 authors. + * + * ======================================================================= + */ -Copyright (C) 2010 skuller.net - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ +#include +#include #include "../../common/header/common.h" #include "header/qal_api.h" -#include -#include -#define QALC_IMP \ - QAL( LPALCCREATECONTEXT, alcCreateContext ); \ - QAL( LPALCMAKECONTEXTCURRENT, alcMakeContextCurrent ); \ - QAL( LPALCPROCESSCONTEXT, alcProcessContext ); \ - QAL( LPALCSUSPENDCONTEXT, alcSuspendContext ); \ - QAL( LPALCDESTROYCONTEXT, alcDestroyContext ); \ - QAL( LPALCGETCURRENTCONTEXT, alcGetCurrentContext ); \ - QAL( LPALCGETCONTEXTSDEVICE, alcGetContextsDevice ); \ - QAL( LPALCOPENDEVICE, alcOpenDevice ); \ - QAL( LPALCCLOSEDEVICE, alcCloseDevice ); \ - QAL( LPALCGETERROR, alcGetError ); \ - QAL( LPALCISEXTENSIONPRESENT, alcIsExtensionPresent ); \ - QAL( LPALCGETPROCADDRESS, alcGetProcAddress ); \ - QAL( LPALCGETENUMVALUE, alcGetEnumValue ); \ - QAL( LPALCGETSTRING, alcGetString ); \ - QAL( LPALCGETINTEGERV, alcGetIntegerv ); \ - QAL( LPALCCAPTUREOPENDEVICE, alcCaptureOpenDevice ); \ - QAL( LPALCCAPTURECLOSEDEVICE, alcCaptureCloseDevice ); \ - QAL( LPALCCAPTURESTART, alcCaptureStart ); \ - QAL( LPALCCAPTURESTOP, alcCaptureStop ); \ - QAL( LPALCCAPTURESAMPLES, alcCaptureSamples ); - -static cvar_t *al_driver; -static cvar_t *al_device; - -static void *handle; -static ALCdevice *device; static ALCcontext *context; +static ALCdevice *device; +static cvar_t *al_device; +static cvar_t *al_driver; +static void *handle; -#define QAL(type,func) static type q##func; -QALC_IMP -#undef QAL +/* Function pointers for OpenAL management */ +static LPALCCREATECONTEXT qalcCreateContext; +static LPALCMAKECONTEXTCURRENT qalcMakeContextCurrent; +static LPALCPROCESSCONTEXT qalcProcessContext; +static LPALCSUSPENDCONTEXT qalcSuspendContext; +static LPALCDESTROYCONTEXT qalcDestroyContext; +static LPALCGETCURRENTCONTEXT qalcGetCurrentContext; +static LPALCGETCONTEXTSDEVICE qalcGetContextsDevice; +static LPALCOPENDEVICE qalcOpenDevice; +static LPALCCLOSEDEVICE qalcCloseDevice; +static LPALCGETERROR qalcGetError; +static LPALCISEXTENSIONPRESENT qalcIsExtensionPresent; +static LPALCGETPROCADDRESS qalcGetProcAddress; +static LPALCGETENUMVALUE qalcGetEnumValue; +static LPALCGETSTRING qalcGetString; +static LPALCGETINTEGERV qalcGetIntegerv; +static LPALCCAPTUREOPENDEVICE qalcCaptureOpenDevice; +static LPALCCAPTURECLOSEDEVICE qalcCaptureCloseDevice; +static LPALCCAPTURESTART qalcCaptureStart; +static LPALCCAPTURESTOP qalcCaptureStop; +static LPALCCAPTURESAMPLES qalcCaptureSamples ; -#define QAL(type,func) type q##func; -QAL_IMP -#undef QAL - -void QAL_Shutdown( void ) { - if( context ) { +/* Declaration of function pointers used + to connect OpenAL to our internal API */ +LPALENABLE qalEnable; +LPALDISABLE qalDisable; +LPALISENABLED qalIsEnabled; +LPALGETSTRING qalGetString; +LPALGETBOOLEANV qalGetBooleanv; +LPALGETINTEGERV qalGetIntegerv; +LPALGETFLOATV qalGetFloatv; +LPALGETDOUBLEV qalGetDoublev; +LPALGETBOOLEAN qalGetBoolean; +LPALGETINTEGER qalGetInteger; +LPALGETFLOAT qalGetFloat; +LPALGETDOUBLE qalGetDouble; +LPALGETERROR qalGetError; +LPALISEXTENSIONPRESENT qalIsExtensionPresent; +LPALGETPROCADDRESS qalGetProcAddress; +LPALGETENUMVALUE qalGetEnumValue; +LPALLISTENERF qalListenerf; +LPALLISTENER3F qalListener3f; +LPALLISTENERFV qalListenerfv; +LPALLISTENERI qalListeneri; +LPALLISTENER3I qalListener3i; +LPALLISTENERIV qalListeneriv; +LPALGETLISTENERF qalGetListenerf; +LPALGETLISTENER3F qalGetListener3f; +LPALGETLISTENERFV qalGetListenerfv; +LPALGETLISTENERI qalGetListeneri; +LPALGETLISTENER3I qalGetListener3i; +LPALGETLISTENERIV qalGetListeneriv; +LPALGENSOURCES qalGenSources; +LPALDELETESOURCES qalDeleteSources; +LPALISSOURCE qalIsSource; +LPALSOURCEF qalSourcef; +LPALSOURCE3F qalSource3f; +LPALSOURCEFV qalSourcefv; +LPALSOURCEI qalSourcei; +LPALSOURCE3I qalSource3i; +LPALSOURCEIV qalSourceiv; +LPALGETSOURCEF qalGetSourcef; +LPALGETSOURCE3F qalGetSource3f; +LPALGETSOURCEFV qalGetSourcefv; +LPALGETSOURCEI qalGetSourcei; +LPALGETSOURCE3I qalGetSource3i; +LPALGETSOURCEIV qalGetSourceiv; +LPALSOURCEPLAYV qalSourcePlayv; +LPALSOURCESTOPV qalSourceStopv; +LPALSOURCEREWINDV qalSourceRewindv; +LPALSOURCEPAUSEV qalSourcePausev; +LPALSOURCEPLAY qalSourcePlay; +LPALSOURCESTOP qalSourceStop; +LPALSOURCEREWIND qalSourceRewind; +LPALSOURCEPAUSE qalSourcePause; +LPALSOURCEQUEUEBUFFERS qalSourceQueueBuffers; +LPALSOURCEUNQUEUEBUFFERS qalSourceUnqueueBuffers; +LPALGENBUFFERS qalGenBuffers; +LPALDELETEBUFFERS qalDeleteBuffers; +LPALISBUFFER qalIsBuffer; +LPALBUFFERDATA qalBufferData; +LPALBUFFERF qalBufferf; +LPALBUFFER3F qalBuffer3f; +LPALBUFFERFV qalBufferfv; +LPALBUFFERI qalBufferi; +LPALBUFFER3I qalBuffer3i; +LPALBUFFERIV qalBufferiv; +LPALGETBUFFERF qalGetBufferf; +LPALGETBUFFER3F qalGetBuffer3f; +LPALGETBUFFERFV qalGetBufferfv; +LPALGETBUFFERI qalGetBufferi; +LPALGETBUFFER3I qalGetBuffer3i; +LPALGETBUFFERIV qalGetBufferiv; +LPALDOPPLERFACTOR qalDopplerFactor; +LPALDOPPLERVELOCITY qalDopplerVelocity; +LPALSPEEDOFSOUND qalSpeedOfSound; +LPALDISTANCEMODEL qalDistanceModel; + +/* + * Shuts OpenAL down, frees all context and + * device handles and unloads the shared lib. + */ +void +QAL_Shutdown() +{ + if (context) + { qalcMakeContextCurrent( NULL ); qalcDestroyContext( context ); context = NULL; } - if( device ) { + + if (device) + { qalcCloseDevice( device ); device = NULL; } -#define QAL(type,func) q##func = NULL; -QALC_IMP -QAL_IMP -#undef QAL + /* Disconnect function pointers used + for OpenAL management calls */ + qalcCreateContext = NULL; + qalcMakeContextCurrent = NULL; + qalcProcessContext = NULL; + qalcSuspendContext = NULL; + qalcDestroyContext = NULL; + qalcGetCurrentContext = NULL; + qalcGetContextsDevice = NULL; + qalcOpenDevice = NULL; + qalcCloseDevice = NULL; + qalcGetError = NULL; + qalcIsExtensionPresent = NULL; + qalcGetProcAddress = NULL; + qalcGetEnumValue = NULL; + qalcGetString = NULL; + qalcGetIntegerv = NULL; + qalcCaptureOpenDevice = NULL; + qalcCaptureCloseDevice = NULL; + qalcCaptureStart = NULL; + qalcCaptureStop = NULL; + qalcCaptureSamples = NULL; - //Sys_FreeLibrary( handle ); + /* Disconnect OpenAL + * function pointers */ + qalEnable = NULL; + qalDisable = NULL; + qalIsEnabled = NULL; + qalGetString = NULL; + qalGetBooleanv = NULL; + qalGetIntegerv = NULL; + qalGetFloatv = NULL; + qalGetDoublev = NULL; + qalGetBoolean = NULL; + qalGetInteger = NULL; + qalGetFloat = NULL; + qalGetDouble = NULL; + qalGetError = NULL; + qalIsExtensionPresent = NULL; + qalGetProcAddress = NULL; + qalGetEnumValue = NULL; + qalListenerf = NULL; + qalListener3f = NULL; + qalListenerfv = NULL; + qalListeneri = NULL; + qalListener3i = NULL; + qalListeneriv = NULL; + qalGetListenerf = NULL; + qalGetListener3f = NULL; + qalGetListenerfv = NULL; + qalGetListeneri = NULL; + qalGetListener3i = NULL; + qalGetListeneriv = NULL; + qalGenSources = NULL; + qalDeleteSources = NULL; + qalIsSource = NULL; + qalSourcef = NULL; + qalSource3f = NULL; + qalSourcefv = NULL; + qalSourcei = NULL; + qalSource3i = NULL; + qalSourceiv = NULL; + qalGetSourcef = NULL; + qalGetSource3f = NULL; + qalGetSourcefv = NULL; + qalGetSourcei = NULL; + qalGetSource3i = NULL; + qalGetSourceiv = NULL; + qalSourcePlayv = NULL; + qalSourceStopv = NULL; + qalSourceRewindv = NULL; + qalSourcePausev = NULL; + qalSourcePlay = NULL; + qalSourceStop = NULL; + qalSourceRewind = NULL; + qalSourcePause = NULL; + qalSourceQueueBuffers = NULL; + qalSourceUnqueueBuffers = NULL; + qalGenBuffers = NULL; + qalDeleteBuffers = NULL; + qalIsBuffer = NULL; + qalBufferData = NULL; + qalBufferf = NULL; + qalBuffer3f = NULL; + qalBufferfv = NULL; + qalBufferi = NULL; + qalBuffer3i = NULL; + qalBufferiv = NULL; + qalGetBufferf = NULL; + qalGetBuffer3f = NULL; + qalGetBufferfv = NULL; + qalGetBufferi = NULL; + qalGetBuffer3i = NULL; + qalGetBufferiv = NULL; + qalDopplerFactor = NULL; + qalDopplerVelocity = NULL; + qalSpeedOfSound = NULL; + qalDistanceModel = NULL; + + /* Unload the shared lib */ dlclose(handle); handle = NULL; - - al_driver->flags &= ~CVAR_ARCHIVE; - al_device->flags &= ~CVAR_ARCHIVE; } -qboolean QAL_Init( void ) { - // DEFAULT_OPENAL_DRIVER is a define from the Makefile +/* + * Loads the OpenAL shared lib, creates + * a context and device handle. + */ +qboolean +QAL_Init() +{ + /* DEFAULT_OPENAL_DRIVER is defined at compile time via the compiler */ al_driver = Cvar_Get( "al_driver", DEFAULT_OPENAL_DRIVER, CVAR_ARCHIVE ); al_device = Cvar_Get( "al_device", "", CVAR_ARCHIVE ); Com_Printf("LoadLibrary(%s)\n", al_driver->string); + + /* Load the library */ handle = dlopen( al_driver->string, RTLD_LAZY ); - //Sys_LoadLibrary( al_driver->string, NULL, &handle ); - if( !handle ) { + + if (!handle) + { return false; } -#define QAL(type,func) q##func = dlsym( handle, #func ); -QALC_IMP -QAL_IMP -#undef QAL + /* Connect function pointers to management functions */ + qalcCreateContext = dlsym(handle, "alcCreateContext"); + qalcMakeContextCurrent = dlsym(handle, "alcMakeContextCurrent"); + qalcProcessContext = dlsym(handle, "alcProcessContext"); + qalcSuspendContext = dlsym(handle, "alcSuspendContext"); + qalcDestroyContext = dlsym(handle, "alcDestroyContext"); + qalcGetCurrentContext = dlsym(handle, "alcGetCurrentContext"); + qalcGetContextsDevice = dlsym(handle, "alcGetContextsDevice"); + qalcOpenDevice = dlsym(handle, "alcOpenDevice"); + qalcCloseDevice = dlsym(handle, "alcCloseDevice"); + qalcGetError = dlsym(handle, "alcGetError"); + qalcIsExtensionPresent = dlsym(handle, "alcIsExtensionPresent"); + qalcGetProcAddress = dlsym(handle, "alcGetProcAddress"); + qalcGetEnumValue = dlsym(handle, "alcGetEnumValue"); + qalcGetString = dlsym(handle, "alcGetString"); + qalcGetIntegerv = dlsym(handle, "alcGetIntegerv"); + qalcCaptureOpenDevice = dlsym(handle, "alcCaptureOpenDevice"); + qalcCaptureCloseDevice = dlsym(handle, "alcCaptureCloseDevice"); + qalcCaptureStart = dlsym(handle, "alcCaptureStart"); + qalcCaptureStop = dlsym(handle, "alcCaptureStop"); + qalcCaptureSamples = dlsym(handle, "alcCaptureSamples"); - Com_Printf( "...opening OpenAL device: " ); - device = qalcOpenDevice( al_device->string[0] ? al_device->string : NULL ); - if( !device ) { - goto fail; - } - Com_Printf( "ok\n" ); + /* Connect function pointers to + to OpenAL API functions */ + qalEnable = dlsym(handle, "alEnable"); + qalDisable = dlsym(handle, "alDisable"); + qalIsEnabled = dlsym(handle, "alIsEnabled"); + qalGetString = dlsym(handle, "alGetString"); + qalGetBooleanv = dlsym(handle, "alGetBooleanv"); + qalGetIntegerv = dlsym(handle, "alGetIntegerv"); + qalGetFloatv = dlsym(handle, "alGetFloatv"); + qalGetDoublev = dlsym(handle, "alGetDoublev"); + qalGetBoolean = dlsym(handle, "alGetBoolean"); + qalGetInteger = dlsym(handle, "alGetInteger"); + qalGetFloat = dlsym(handle, "alGetFloat"); + qalGetDouble = dlsym(handle, "alGetDouble"); + qalGetError = dlsym(handle, "alGetError"); + qalIsExtensionPresent = dlsym(handle, "alIsExtensionPresent"); + qalGetProcAddress = dlsym(handle, "alGetProcAddress"); + qalGetEnumValue = dlsym(handle, "alGetEnumValue"); + qalListenerf = dlsym(handle, "alListenerf"); + qalListener3f = dlsym(handle, "alListener3f"); + qalListenerfv = dlsym(handle, "alListenerfv"); + qalListeneri = dlsym(handle, "alListeneri"); + qalListener3i = dlsym(handle, "alListener3i"); + qalListeneriv = dlsym(handle, "alListeneriv"); + qalGetListenerf = dlsym(handle, "alGetListenerf"); + qalGetListener3f = dlsym(handle, "alGetListener3f"); + qalGetListenerfv = dlsym(handle, "alGetListenerfv"); + qalGetListeneri = dlsym(handle, "alGetListeneri"); + qalGetListener3i = dlsym(handle, "alGetListener3i"); + qalGetListeneriv = dlsym(handle, "alGetListeneriv"); + qalGenSources = dlsym(handle, "alGenSources"); + qalDeleteSources = dlsym(handle, "alDeleteSources"); + qalIsSource = dlsym(handle, "alIsSource"); + qalSourcef = dlsym(handle, "alSourcef"); + qalSource3f = dlsym(handle, "alSource3f"); + qalSourcefv = dlsym(handle, "alSourcefv"); + qalSourcei = dlsym(handle, "alSourcei"); + qalSource3i = dlsym(handle, "alSource3i"); + qalSourceiv = dlsym(handle, "alSourceiv"); + qalGetSourcef = dlsym(handle, "alGetSourcef"); + qalGetSource3f = dlsym(handle, "alGetSource3f"); + qalGetSourcefv = dlsym(handle, "alGetSourcefv"); + qalGetSourcei = dlsym(handle, "alGetSourcei"); + qalGetSource3i = dlsym(handle, "alGetSource3i"); + qalGetSourceiv = dlsym(handle, "alGetSourceiv"); + qalSourcePlayv = dlsym(handle, "alSourcePlayv"); + qalSourceStopv = dlsym(handle, "alSourceStopv"); + qalSourceRewindv = dlsym(handle, "alSourceRewindv"); + qalSourcePausev = dlsym(handle, "alSourcePausev"); + qalSourcePlay = dlsym(handle, "alSourcePlay"); + qalSourceStop = dlsym(handle, "alSourceStop"); + qalSourceRewind = dlsym(handle, "alSourceRewind"); + qalSourcePause = dlsym(handle, "alSourcePause"); + qalSourceQueueBuffers = dlsym(handle, "alSourceQueueBuffers"); + qalSourceUnqueueBuffers = dlsym(handle, "alSourceUnqueueBuffers"); + qalGenBuffers = dlsym(handle, "alGenBuffers"); + qalDeleteBuffers = dlsym(handle, "alDeleteBuffers"); + qalIsBuffer = dlsym(handle, "alIsBuffer"); + qalBufferData = dlsym(handle, "alBufferData"); + qalBufferf = dlsym(handle, "alBufferf"); + qalBuffer3f = dlsym(handle, "alBuffer3f"); + qalBufferfv = dlsym(handle, "alBufferfv"); + qalBufferi = dlsym(handle, "alBufferi"); + qalBuffer3i = dlsym(handle, "alBuffer3i"); + qalBufferiv = dlsym(handle, "alBufferiv"); + qalGetBufferf = dlsym(handle, "alGetBufferf"); + qalGetBuffer3f = dlsym(handle, "alGetBuffer3f"); + qalGetBufferfv = dlsym(handle, "alGetBufferfv"); + qalGetBufferi = dlsym(handle, "alGetBufferi"); + qalGetBuffer3i = dlsym(handle, "alGetBuffer3i"); + qalGetBufferiv = dlsym(handle, "alGetBufferiv"); + qalDopplerFactor = dlsym(handle, "alDopplerFactor"); + qalDopplerVelocity = dlsym(handle, "alDopplerVelocity"); + qalSpeedOfSound = dlsym(handle, "alSpeedOfSound"); + qalDistanceModel = dlsym(handle, "alDistanceModel"); - Com_Printf( "...creating OpenAL context: " ); - context = qalcCreateContext( device, NULL ); - if( !context ) { - goto fail; - } - Com_Printf( "ok\n" ); + /* Open the OpenAL device */ + Com_Printf("...opening OpenAL device:"); + + device = qalcOpenDevice(al_device->string[0] ? al_device->string : NULL); - Com_Printf( "...making context current: " ); - if( !qalcMakeContextCurrent( context ) ) { - goto fail; - } - Com_Printf( "ok\n" ); + if(!device) + { + Com_DPrintf("failed\n"); + QAL_Shutdown(); + return false; + } - al_driver->flags |= CVAR_ARCHIVE; - al_device->flags |= CVAR_ARCHIVE; + Com_Printf("ok\n"); + + /* Create the OpenAL context */ + Com_Printf("...creating OpenAL context: "); + + context = qalcCreateContext(device, NULL); + + if(!context) + { + Com_DPrintf("failed\n"); + QAL_Shutdown(); + return false; + } + + Com_Printf("ok\n"); + + /* Set the created context as current context */ + Com_Printf("...making context current: "); + + if (!qalcMakeContextCurrent(context)) + { + Com_DPrintf("failed\n"); + QAL_Shutdown(); + return false; + } + + Com_Printf("ok\n"); return true; - -fail: - Com_DPrintf( "failed\n" ); - QAL_Shutdown(); - return false; } From bf6d491af3948b2708b9267ec2a760f0cca5e221 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Tue, 24 Apr 2012 14:07:33 +0000 Subject: [PATCH 19/29] - Refactor AL_SoundInfo() into the platform dependent QAL_SoundInfo(). - Use QAL_SoundInfo() to print the OpenAL infos at startup and by the "soundinfo" command. - Implement printing of all available OpenAL devices at startup and by the "soundinfo" command. --- src/client/sound/header/qal_api.h | 15 ++++++-- src/client/sound/qal_api.c | 60 ++++++++++++++++++++++++++++++- src/client/sound/snd_al.c | 13 ++----- src/client/sound/snd_dma.c | 4 ++- 4 files changed, 77 insertions(+), 15 deletions(-) diff --git a/src/client/sound/header/qal_api.h b/src/client/sound/header/qal_api.h index 24911463..bdee3ebc 100644 --- a/src/client/sound/header/qal_api.h +++ b/src/client/sound/header/qal_api.h @@ -26,6 +26,9 @@ * ======================================================================= */ +#ifndef _QAL_API_H_ +#define _QAL_API_H_ + #include /* Function pointers used to tie @@ -104,15 +107,23 @@ extern LPALDOPPLERVELOCITY qalDopplerVelocity; extern LPALSPEEDOFSOUND qalSpeedOfSound; extern LPALDISTANCEMODEL qalDistanceModel; +/* + * Gives information over the OpenAL + * implementation and it's state + */ +void QAL_SoundInfo(void); + /* * Loads the OpenAL shared lib, creates * a context and device handle. */ -qboolean QAL_Init( void ); +qboolean QAL_Init(void); /* * Shuts OpenAL down, frees all context and * device handles and unloads the shared lib. */ -void QAL_Shutdown( void ); +void QAL_Shutdown(void); + +#endif /* _QAL_API_H_ */ diff --git a/src/client/sound/qal_api.c b/src/client/sound/qal_api.c index 5bf7393a..a06b102c 100644 --- a/src/client/sound/qal_api.c +++ b/src/client/sound/qal_api.c @@ -30,7 +30,9 @@ */ #include +#include #include +#include #include "../../common/header/common.h" #include "header/qal_api.h" @@ -138,7 +140,58 @@ LPALDOPPLERFACTOR qalDopplerFactor; LPALDOPPLERVELOCITY qalDopplerVelocity; LPALSPEEDOFSOUND qalSpeedOfSound; LPALDISTANCEMODEL qalDistanceModel; - + +/* + * Gives information over the OpenAL + * implementation and it's state + */ +void QAL_SoundInfo() +{ + Com_Printf("OpenAL settings:\n"); + Com_Printf("AL_VENDOR: %s\n", qalGetString(AL_VENDOR)); + Com_Printf("AL_RENDERER: %s\n", qalGetString(AL_RENDERER)); + Com_Printf("AL_VERSION: %s\n", qalGetString(AL_VERSION)); + Com_Printf("AL_EXTENSIONS: %s\n", qalGetString(AL_EXTENSIONS)); + + if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) + { + const char *devs = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); + + Com_Printf("\nAvailable OpenAL devices:\n"); + + if (devs == NULL) + { + Com_Printf("- No devices found. Depending on your\n"); + Com_Printf(" platform this may be expected and\n"); + Com_Printf(" doesn't indicate a problem!\n"); + } + else + { + while (devs && *devs) + { + Com_Printf("- %s\n", devs); + devs += strlen(devs) + 1; + } + } + } + + if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) + { + const char *devs = alcGetString(NULL, ALC_DEVICE_SPECIFIER); + + Com_Printf("\nCurrent OpenAL device:\n"); + + if (devs == NULL) + { + Com_Printf("- No OpenAL device in use\n"); + } + else + { + Com_Printf("- %s\n", devs); + } + } +} + /* * Shuts OpenAL down, frees all context and * device handles and unloads the shared lib. @@ -422,6 +475,11 @@ QAL_Init() Com_Printf("ok\n"); + /* Print OpenAL informations */ + Com_Printf("\n"); + QAL_SoundInfo(); + Com_Printf("\n"); + return true; } diff --git a/src/client/sound/snd_al.c b/src/client/sound/snd_al.c index c61f69ff..f94b4bc3 100644 --- a/src/client/sound/snd_al.c +++ b/src/client/sound/snd_al.c @@ -49,14 +49,6 @@ static void S_AL_StreamUpdate( void ); static void S_AL_StreamDie( void ); // /Forward Declarations -void AL_SoundInfo( void ) { - Com_Printf( "AL_VENDOR: %s\n", qalGetString( AL_VENDOR ) ); - Com_Printf( "AL_RENDERER: %s\n", qalGetString( AL_RENDERER ) ); - Com_Printf( "AL_VERSION: %s\n", qalGetString( AL_VERSION ) ); - Com_Printf( "AL_EXTENSIONS: %s\n", qalGetString( AL_EXTENSIONS ) ); - Com_Printf( "Number of sources: %d\n", s_numchannels ); -} - static void AL_InitStreamSource() { qalSourcei (streamSource, AL_BUFFER, 0 ); qalSourcei (streamSource, AL_LOOPING, AL_FALSE ); @@ -108,10 +100,9 @@ qboolean AL_Init( void ) { s_numchannels = i; AL_InitStreamSource(); + + Com_Printf("Number of OpenAL sources: %d\n\n", s_numchannels); - Com_Printf("\nOpenAL setting:\n"); - AL_SoundInfo(); - Com_Printf("\n"); return true; fail: diff --git a/src/client/sound/snd_dma.c b/src/client/sound/snd_dma.c index 83b7e922..c52c5d7f 100644 --- a/src/client/sound/snd_dma.c +++ b/src/client/sound/snd_dma.c @@ -29,6 +29,7 @@ #include "../header/client.h" #include "header/local.h" #include "header/vorbis.h" +#include "header/qal_api.h" void S_Play ( void ); void S_SoundList ( void ); @@ -108,7 +109,8 @@ S_SoundInfo_f ( void ) } #if USE_OPENAL if(sound_started == SS_OAL) { - AL_SoundInfo(); + QAL_SoundInfo(); + Com_Printf("\nNumber of sources: %d\n", s_numchannels); } else #endif DMA_SoundInfo(); From f836cef4c43950b2429935b5c094c515e1695876 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Tue, 24 Apr 2012 14:20:01 +0000 Subject: [PATCH 20/29] Rename qal_api.c to unix/qal.c and qal_api.h to unix/header/qal.h. Both files are platform dependend and won't work on non unixoid platforms. --- Makefile | 2 +- src/client/sound/snd_al.c | 2 +- src/client/sound/snd_dma.c | 2 +- src/{client/sound/header/qal_api.h => unix/header/qal.h} | 3 +++ src/{client/sound/qal_api.c => unix/qal.c} | 8 ++++++-- 5 files changed, 12 insertions(+), 5 deletions(-) rename src/{client/sound/header/qal_api.h => unix/header/qal.h} (99%) rename src/{client/sound/qal_api.c => unix/qal.c} (99%) diff --git a/Makefile b/Makefile index d00e4853..59af1b91 100644 --- a/Makefile +++ b/Makefile @@ -252,7 +252,6 @@ CLIENT_OBJS_ := \ src/client/menu/menu.o \ src/client/menu/qmenu.o \ src/client/menu/videomenu.o \ - src/client/sound/qal_api.o \ src/client/sound/snd_al.o \ src/client/sound/snd_dma.o \ src/client/sound/snd_mem.o \ @@ -300,6 +299,7 @@ CLIENT_OBJS_ := \ src/unix/hunk.o \ src/unix/main.o \ src/unix/network.o \ + src/unix/qal.o \ src/unix/signalhandler.o \ src/unix/system.o \ src/unix/vid.o diff --git a/src/client/sound/snd_al.c b/src/client/sound/snd_al.c index f94b4bc3..63718b66 100644 --- a/src/client/sound/snd_al.c +++ b/src/client/sound/snd_al.c @@ -25,8 +25,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef USE_OPENAL #include "../header/client.h" +#include "../../unix/header/qal.h" #include "header/local.h" -#include "header/qal_api.h" #include "header/vorbis.h" // translates from AL coordinate system to quake diff --git a/src/client/sound/snd_dma.c b/src/client/sound/snd_dma.c index c52c5d7f..1ae0ec3d 100644 --- a/src/client/sound/snd_dma.c +++ b/src/client/sound/snd_dma.c @@ -27,9 +27,9 @@ */ #include "../header/client.h" +#include "../../unix/header/qal.h" #include "header/local.h" #include "header/vorbis.h" -#include "header/qal_api.h" void S_Play ( void ); void S_SoundList ( void ); diff --git a/src/client/sound/header/qal_api.h b/src/unix/header/qal.h similarity index 99% rename from src/client/sound/header/qal_api.h rename to src/unix/header/qal.h index bdee3ebc..b9d67ce8 100644 --- a/src/client/sound/header/qal_api.h +++ b/src/unix/header/qal.h @@ -26,6 +26,8 @@ * ======================================================================= */ +#ifdef USE_OPENAL + #ifndef _QAL_API_H_ #define _QAL_API_H_ @@ -126,4 +128,5 @@ qboolean QAL_Init(void); void QAL_Shutdown(void); #endif /* _QAL_API_H_ */ +#endif /* USE_OPENAL */ diff --git a/src/client/sound/qal_api.c b/src/unix/qal.c similarity index 99% rename from src/client/sound/qal_api.c rename to src/unix/qal.c index a06b102c..76289fbe 100644 --- a/src/client/sound/qal_api.c +++ b/src/unix/qal.c @@ -29,13 +29,15 @@ * ======================================================================= */ +#ifdef USE_OPENAL + #include #include #include #include -#include "../../common/header/common.h" -#include "header/qal_api.h" +#include "../common/header/common.h" +#include "header/qal.h" static ALCcontext *context; static ALCdevice *device; @@ -483,3 +485,5 @@ QAL_Init() return true; } +#endif /* USE_OPENAL */ + From 23ad8471b0f5c61f7e1d886688ed07ac95ef120c Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Tue, 24 Apr 2012 14:51:20 +0000 Subject: [PATCH 21/29] Update TODO --- TODO | 2 -- 1 file changed, 2 deletions(-) diff --git a/TODO b/TODO index 345ea4a7..994b79d7 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,4 @@ - Dateien neu ordnen (vielleicht besser nach dem Merge...) -- Das Makro-Gefrickel in qal_api.c ist ja wohl widerlichST. - Lass uns da lieber ein paar Codeblöcke haben, als DAS DA! - Doku anpassen - yq2-Lizenzheader und Inhaltsbeschreibungen - Den Kram hinter _DEBUG raus oder konsistent mit dem Rest From a38825425245fc6a2b527cb0a4b95ae0b2ba5df5 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Wed, 25 Apr 2012 10:09:16 +0000 Subject: [PATCH 22/29] Fix a missmerge --- src/client/sound/snd_dma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/client/sound/snd_dma.c b/src/client/sound/snd_dma.c index 8d8a512b..1e32289a 100644 --- a/src/client/sound/snd_dma.c +++ b/src/client/sound/snd_dma.c @@ -242,7 +242,6 @@ S_Shutdown ( void ) #ifdef OGG OGG_Shutdown(); #endif - SNDDMA_Shutdown(); #if USE_OPENAL if( sound_started == SS_OAL ) From 905b31a918e33f2731b1e7cefc491367dfb51601 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Wed, 25 Apr 2012 10:09:30 +0000 Subject: [PATCH 23/29] Integrate OpenAL into the options system --- Makefile | 9 +++++++++ src/unix/main.c | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/Makefile b/Makefile index 0d12f42b..6bd6491b 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,10 @@ WITH_CDA=yes # dependencies to libogg, libvorbis and libvorbisfile. WITH_OGG=yes +# Enables the optional OpenAL sound systems. Adds +# a dependencx to libopenal +WITH_OPENAL=yes + # Enables retexturing support. Adds a dependency to # libjpeg WITH_RETEXTURING=yes @@ -182,6 +186,11 @@ release/quake2 : CFLAGS += -DOGG release/quake2 : LDFLAGS += -lvorbis -lvorbisfile -logg endif +ifeq ($(WITH_OPENAL),yes) +release/quake2 : CFLAGS += -DUSE_OPENAL -DDEFAULT_OPENAL_DRIVER='"libopenal.so.1"' +release/quake2 : LDFLAGS += -lopenal +endif + ifeq ($(WITH_ZIP),yes) release/quake2 : CFLAGS += -DZIP release/quake2 : LDFLAGS += -lz diff --git a/src/unix/main.c b/src/unix/main.c index 291d0bc2..296aa753 100644 --- a/src/unix/main.c +++ b/src/unix/main.c @@ -66,6 +66,11 @@ main ( int argc, char **argv ) #else printf(" - OGG/Vorbis\n"); #endif +#ifdef USE_OPENAL + printf(" + OpenAL\n"); +#else + printf(" - OpenAL\n"); +#endif #ifdef ZIP printf(" + Zip file support\n"); #else From 774e7bf46f74c9a17a87c7569cef527204566b8a Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Fri, 27 Apr 2012 11:52:38 +0000 Subject: [PATCH 24/29] Document the OpenAL support --- README | 56 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/README b/README index 2d17c398..2d761130 100644 --- a/README +++ b/README @@ -38,10 +38,11 @@ Content of this file: 2.4 Console variables 3. Configuration - 3.1 Widescreen setup - 3.2 Video - 3.3 Input - 3.4 Sound + 3.1 Video + 3.2 Input + 3.3 Sound + 3.3.1 The classic sound system + 3.3.2 The OpenAL sound system 4. Bugreports @@ -338,14 +339,23 @@ There are some cvar to adjust: 3.3 Sound --------- -Quake II featured one of the best sound systems of it's time but sadly it was -totaly broken. Therefore id Software rewrote it once, later it was rewritten -again for the linux port. That fixed the most visible problems, but the code was -just crap and broke again as time passed and sound on PCs evolved. -For Yamagi Quake II 3.0 the sound system was overhauled, featuring a complete -code audit of the upper layers with many bugfixes and memory leak plugs. -The backend was rewritten from scratch. This should solve most if not all -problems. +Quake II featured one of the best sound systems of it's time (for example it had +support for realtime calculated stereo effects) but sadly it was totaly broken. +Therefore id Software rewrote it once, later it was rewritten again for the +linux port. That fixed the most visible problems, but the code was just crap and +broke again as time passed and sound on PCs evolved. For Yamagi Quake II 3.0 the +sound system was overhauled, featuring a complete code audit of the upper layers +with many bugfixes and memory leak plugs. The backend was rewritten from +scratch. This should solve most if not all problems. Yamagi Quake II 4.20 +featured an optional OpenAL sound system, enabling better stereo calculations +and even surround support. + +3.3.1 The classic sound system +------------------------------ +This is the original sound implementation, as used in the first release of Quake +II in 1997. It featured stereo calculations for most samples. It's disabled by +default and can be reenables by setting "s_openal" to "0", followed by +"snd_restart. Common problems are: - The earthquake sound sample is distorted This is not a fault of the sound code but of the sound sample itself. @@ -370,6 +380,28 @@ problems. card 0 } +3.3.2 The OpenAL sound system +----------------------------- +This is a sound system based upon the popular OpenAL audio library. It features +surround playback which gives a huge improvement in sound quality and gameplay +experience. It's enables by default, but can be disabled by setting "s_openal" +to "0", followed by a "snd_restart". To work correctly it's in the need of a +correctly configured OpenAL! OpenAL is configured in the file ~/.alsoftrc (for +the openal-soft implementation, other implementations may vary). The most +important options are: + +- channels = surround51 -> Enable 5.1 surround support. Other values are "mono", + "stereo", "quad", "surround61" and "surround71". + +- stereodup = true -> If set to "true" all raw stereo samples (in Quake II the + background music and video sounds) are duplicated behind the listener. + Otherwise they're played only through the front speaker. + +- resampler = cubic -> Use cubic resampling. While this requires more cpu power + than the default linear resamling it's highly recommended since Quake II has + several hard to resamples sound effects. Especially the earthquake sound can + distort if a low quality resampler is employed! + =============================================================================== 4. Bugreports From 363dc5d3114f772bfc8ab47baeff9a66495b0eed Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Fri, 27 Apr 2012 11:53:04 +0000 Subject: [PATCH 25/29] Update TODO --- TODO | 2 -- 1 file changed, 2 deletions(-) diff --git a/TODO b/TODO index 994b79d7..4e312223 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,3 @@ -- Dateien neu ordnen (vielleicht besser nach dem Merge...) -- Doku anpassen - yq2-Lizenzheader und Inhaltsbeschreibungen - Den Kram hinter _DEBUG raus oder konsistent mit dem Rest vom Source From 1a0b4ebad515a5a8c81906e6045de5ceed9b7a12 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Fri, 27 Apr 2012 12:00:22 +0000 Subject: [PATCH 26/29] Do not set / enable / show the s_openal CVAR if the binary is build without OpenAL support. OpenAL is enabled in the default Makefile and if it's disabled, it's shown at startup. --- src/client/sound/snd_dma.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/client/sound/snd_dma.c b/src/client/sound/snd_dma.c index 1e32289a..b5fb339f 100644 --- a/src/client/sound/snd_dma.c +++ b/src/client/sound/snd_dma.c @@ -150,12 +150,7 @@ S_Init ( void ) Cmd_AddCommand( "ogg_shutdown", OGG_Shutdown ); #endif -#if ! USE_OPENAL - cv = Cvar_Get( "s_openal", "0", CVAR_ARCHIVE); - if( cv->value ) { - Com_Printf("Warning: Ignoring s_openal, as this binary has no OpenAL support!"); - } -#else +#if USE_OPENAL cv = Cvar_Get( "s_openal", "1", CVAR_ARCHIVE); if( cv->value && AL_Init() ) { sound_started = SS_OAL; From 2b6389a4716d3ec396873e8d7a21de4a336935f7 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Fri, 27 Apr 2012 13:55:45 +0000 Subject: [PATCH 27/29] Filter sound samples (not the music) when under water --- src/client/sound/snd_al.c | 50 +++++++++++++++++++++++++++++++++++++++ src/common/pmove.c | 23 ++++++++++++++++++ src/unix/header/qal.h | 5 ++++ src/unix/qal.c | 12 ++++++++++ 4 files changed, 90 insertions(+) diff --git a/src/client/sound/snd_al.c b/src/client/sound/snd_al.c index 63718b66..031f2409 100644 --- a/src/client/sound/snd_al.c +++ b/src/client/sound/snd_al.c @@ -40,6 +40,7 @@ qboolean streamPlaying; int active_buffers; static ALuint streamSource; +static ALuint underwaterFilter; static ALuint s_srcnums[MAX_CHANNELS-1]; static int s_framecount; @@ -61,6 +62,31 @@ static void AL_InitStreamSource() { // srcList[cursrc].scaleGain = 0.0f; FIXME - something like that? } +static void AL_InitUnderwaterFilter() +{ + // Generate a filter + qalGenFilters(1, &underwaterFilter); + + if (qalGetError() != AL_NO_ERROR) + { + Com_Printf("Couldn't generate an OpenAL filter!\n"); + return; + } + + // Low pass filter for underwater effect + qalFilteri(underwaterFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS); + + if (qalGetError() != AL_NO_ERROR) + { + Com_Printf("Low pass filter is not supported!\n"); + return; + } + + // The effect + qalFilterf(underwaterFilter, AL_LOWPASS_GAIN, 1.5); + qalFilterf(underwaterFilter, AL_LOWPASS_GAINHF, 0.25); +} + qboolean AL_Init( void ) { int i; @@ -100,6 +126,7 @@ qboolean AL_Init( void ) { s_numchannels = i; AL_InitStreamSource(); + AL_InitUnderwaterFilter(); Com_Printf("Number of OpenAL sources: %d\n\n", s_numchannels); @@ -114,6 +141,7 @@ void AL_Shutdown( void ) { Com_Printf( "Shutting down OpenAL.\n" ); qalDeleteSources(1, &streamSource); + qalDeleteFilters(1, &underwaterFilter); if( s_numchannels ) { // delete source names @@ -391,6 +419,28 @@ void AL_Update( void ) { AL_IssuePlaysounds(); } + +void AL_Underwater() +{ + int i; + + // Apply to all sources + for (i = 0; i < MAX_CHANNELS - 1; i++) + { + qalSourcei(s_srcnums[i], AL_DIRECT_FILTER, underwaterFilter); + } +} + +void AL_Overwater() +{ + int i; + + // Apply to all sources + for (i = 0; i < MAX_CHANNELS - 1; i++) + { + qalSourcei(s_srcnums[i], AL_DIRECT_FILTER, 0); + } +} /* =========================================================================== diff --git a/src/common/pmove.c b/src/common/pmove.c index 6ff34cb8..eeeb5f60 100644 --- a/src/common/pmove.c +++ b/src/common/pmove.c @@ -27,6 +27,11 @@ #include "header/common.h" +#if !defined(DEDICATED_ONLY) && defined(USE_OPENAL) +void AL_Underwater(); +void AL_Overwater(); +#endif + #define STEPSIZE 18 /* all of the locals will be zeroed before each @@ -1108,6 +1113,10 @@ void PM_ClampAngles (void) */ void Pmove (pmove_t *pmove) { +#if !defined(DEDICATED_ONLY) && defined(USE_OPENAL) + static int underwater; +#endif + pm = pmove; /* clear results */ @@ -1235,5 +1244,19 @@ void Pmove (pmove_t *pmove) /* set groundentity, watertype, and waterlevel for final spot */ PM_CatagorizePosition (); +#if !defined(DEDICATED_ONLY) && defined(USE_OPENAL) + if ((pm->waterlevel == 3) && !underwater) + { + underwater = 1; + AL_Underwater(); + } + + if ((pm->waterlevel < 3 && underwater)) + { + underwater = 0; + AL_Overwater(); + } +#endif + PM_SnapPosition (); } diff --git a/src/unix/header/qal.h b/src/unix/header/qal.h index b9d67ce8..aad1c511 100644 --- a/src/unix/header/qal.h +++ b/src/unix/header/qal.h @@ -32,6 +32,7 @@ #define _QAL_API_H_ #include +#include /* Function pointers used to tie the qal API to the OpenAL API */ @@ -108,6 +109,10 @@ extern LPALDOPPLERFACTOR qalDopplerFactor; extern LPALDOPPLERVELOCITY qalDopplerVelocity; extern LPALSPEEDOFSOUND qalSpeedOfSound; extern LPALDISTANCEMODEL qalDistanceModel; +extern LPALGENFILTERS qalGenFilters; +extern LPALFILTERI qalFilteri; +extern LPALFILTERF qalFilterf; +extern LPALDELETEFILTERS qalDeleteFilters; /* * Gives information over the OpenAL diff --git a/src/unix/qal.c b/src/unix/qal.c index 76289fbe..f20648d7 100644 --- a/src/unix/qal.c +++ b/src/unix/qal.c @@ -142,6 +142,10 @@ LPALDOPPLERFACTOR qalDopplerFactor; LPALDOPPLERVELOCITY qalDopplerVelocity; LPALSPEEDOFSOUND qalSpeedOfSound; LPALDISTANCEMODEL qalDistanceModel; +LPALGENFILTERS qalGenFilters; +LPALFILTERI qalFilteri; +LPALFILTERF qalFilterf; +LPALDELETEFILTERS qalDeleteFilters; /* * Gives information over the OpenAL @@ -312,6 +316,10 @@ QAL_Shutdown() qalDopplerVelocity = NULL; qalSpeedOfSound = NULL; qalDistanceModel = NULL; + qalGenFilters = NULL; + qalFilteri = NULL; + qalFilterf = NULL; + qalDeleteFilters = NULL; /* Unload the shared lib */ dlclose(handle); @@ -436,6 +444,10 @@ QAL_Init() qalDopplerVelocity = dlsym(handle, "alDopplerVelocity"); qalSpeedOfSound = dlsym(handle, "alSpeedOfSound"); qalDistanceModel = dlsym(handle, "alDistanceModel"); + qalGenFilters = dlsym(handle, "alGenFilters"); + qalFilteri = dlsym(handle, "alFilteri"); + qalFilterf = dlsym(handle, "alFilterf"); + qalDeleteFilters = dlsym(handle, "alDeleteFilters"); /* Open the OpenAL device */ Com_Printf("...opening OpenAL device:"); From c62e5ac85b627cdb6423ff03105aecb44ee6176b Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Fri, 27 Apr 2012 14:06:08 +0000 Subject: [PATCH 28/29] - Implement AL_UnqueueRawSamples() and use it to stop the Vorbis playback imediatly - Increase Vorbis buffers to 64. 24 were to few --- src/client/sound/snd_al.c | 5 +++++ src/client/sound/snd_vorbis.c | 18 +++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/client/sound/snd_al.c b/src/client/sound/snd_al.c index 031f2409..0333e2a2 100644 --- a/src/client/sound/snd_al.c +++ b/src/client/sound/snd_al.c @@ -585,4 +585,9 @@ void AL_RawSamples( int samples, int rate, int width, int channels, byte *data, */ } +void AL_UnqueueRawSamples() +{ + S_AL_StreamDie(); +} + #endif // USE_OPENAL diff --git a/src/client/sound/snd_vorbis.c b/src/client/sound/snd_vorbis.c index 930eb667..d42cee0a 100644 --- a/src/client/sound/snd_vorbis.c +++ b/src/client/sound/snd_vorbis.c @@ -39,6 +39,10 @@ #include "header/local.h" #include "header/vorbis.h" +#ifdef USE_OPENAL +void AL_UnqueueRawSamples(); +#endif + qboolean ogg_first_init = true; /* First initialization flag. */ qboolean ogg_started = false; /* Initialization flag. */ int ogg_bigendian = 0; @@ -583,6 +587,10 @@ OGG_Stop ( void ) return; } +#ifdef USE_OPENAL + AL_UnqueueRawSamples(); +#endif + ov_clear( &ovFile ); ogg_status = STOP; ogg_info = NULL; @@ -617,16 +625,16 @@ OGG_Stream ( void ) We take the number of active buffers at startup (at this point most of the samples should be precached and loaded - into buffers) and add 24. Empircal + into buffers) and add 64. Empircal testing showed, that at most times - at least 12 buffers remain available - for OGG/Vorbis, enough for about 0.5 + at least 52 buffers remain available + for OGG/Vorbis, enough for about 3 seconds playback. The music won't stutter as long as the framerate - stayes over 3 FPS. */ + stayes over 1 FPS. */ if ( ogg_numbufs == 0 ) { - ogg_numbufs = active_buffers + 24; + ogg_numbufs = active_buffers + 64; } /* active_buffers are all active OpenAL buffers, From 31f9af817ff7ec9c7188528e1843f5a1757b49ae Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sat, 28 Apr 2012 15:44:14 +0000 Subject: [PATCH 29/29] Last fixes and cleanups for OpenAL support * New license header in snd_al.c * README fixes * Fix printing of used OpenAL device * Cleanup in snd_al.c --- README | 4 +- src/client/sound/snd_al.c | 133 +++++++++++-------------------------- src/client/sound/snd_dma.c | 2 +- src/unix/qal.c | 2 +- 4 files changed, 41 insertions(+), 100 deletions(-) diff --git a/README b/README index 2d761130..defcc321 100644 --- a/README +++ b/README @@ -388,14 +388,14 @@ experience. It's enables by default, but can be disabled by setting "s_openal" to "0", followed by a "snd_restart". To work correctly it's in the need of a correctly configured OpenAL! OpenAL is configured in the file ~/.alsoftrc (for the openal-soft implementation, other implementations may vary). The most -important options are: +important options (tested with OpenAL Soft 1.14) are: - channels = surround51 -> Enable 5.1 surround support. Other values are "mono", "stereo", "quad", "surround61" and "surround71". - stereodup = true -> If set to "true" all raw stereo samples (in Quake II the background music and video sounds) are duplicated behind the listener. - Otherwise they're played only through the front speaker. + Otherwise they're played only through the front speakers. - resampler = cubic -> Use cubic resampling. While this requires more cpu power than the default linear resamling it's highly recommended since Quake II has diff --git a/src/client/sound/snd_al.c b/src/client/sound/snd_al.c index 0333e2a2..073a5ab5 100644 --- a/src/client/sound/snd_al.c +++ b/src/client/sound/snd_al.c @@ -1,26 +1,33 @@ /* -This Source File - except for the last few functions - see the other copyright -notice further down the - was taken from the Q2Pro Port. - -Copyright (C) 2010 skuller.net - 2012 Some changes by the Yamagi Quake II developers - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ + * Copyright (C) 1997-2005 Id Software, Inc. + * (C) 2010 skuller.net + * (C) 2005 Stuart Dalton (badcdev@gmail.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * ======================================================================= + * + * Most of these functions are from the Q2Pro project, and some are from + * zeq2. We adapted them to work with Yamagi Quake II + * + * This is an OpenAL backend for the Quake II Soundsystem. + * + * ======================================================================= + */ #ifdef USE_OPENAL @@ -58,8 +65,6 @@ static void AL_InitStreamSource() { qalSource3f(streamSource, AL_DIRECTION, 0.0, 0.0, 0.0); qalSourcef (streamSource, AL_ROLLOFF_FACTOR, 0.0 ); qalSourcei (streamSource, AL_SOURCE_RELATIVE, AL_TRUE ); - - // srcList[cursrc].scaleGain = 0.0f; FIXME - something like that? } static void AL_InitUnderwaterFilter() @@ -160,7 +165,6 @@ sfxcache_t *AL_UploadSfx( sfx_t *s, wavinfo_t *s_info, byte *data ) { ALuint name; if( !size ) { - // s->error = Q_ERR_TOO_FEW; FIXME: do I want this information? return NULL; } @@ -169,12 +173,11 @@ sfxcache_t *AL_UploadSfx( sfx_t *s, wavinfo_t *s_info, byte *data ) { qalBufferData( name, format, data, size, s_info->rate ); active_buffers++; if( qalGetError() != AL_NO_ERROR ) { - // s->error = Q_ERR_LIBRARY_ERROR; FIXME: do I want this info? return NULL; } // allocate placeholder sfxcache - sc = s->cache = Z_TagMalloc(sizeof(*sc), 0); // FIXME: TAG_SOUND instead of 0 - this possibly leaks! + sc = s->cache = Z_TagMalloc(sizeof(*sc), 0); sc->length = s_info->samples * 1000 / s_info->rate; // in msec sc->loopstart = s_info->loopstart; sc->width = s_info->width; @@ -199,10 +202,9 @@ void AL_DeleteSfx( sfx_t *s ) { } void AL_StopChannel( channel_t *ch ) { -#ifdef _DEBUG - if (s_show->integer > 1) + + if (s_show->value > 1) Com_Printf("%s: %s\n", __func__, ch->sfx->name ); -#endif // stop it qalSourceStop( ch->srcnum ); @@ -229,15 +231,12 @@ static void AL_Spatialize( channel_t *ch ) { void AL_PlayChannel( channel_t *ch ) { sfxcache_t *sc = ch->sfx->cache; -#ifdef _DEBUG - if (s_show->integer > 1) + if (s_show->value > 1) Com_Printf("%s: %s\n", __func__, ch->sfx->name ); -#endif ch->srcnum = s_srcnums[ch - channels]; qalGetError(); qalSourcei( ch->srcnum, AL_BUFFER, sc->bufnum ); - //qalSourcei( ch->srcnum, AL_LOOPING, sc->loopstart == -1 ? AL_FALSE : AL_TRUE ); qalSourcei( ch->srcnum, AL_LOOPING, ch->autosound ? AL_TRUE : AL_FALSE ); qalSourcef( ch->srcnum, AL_GAIN, ch->master_vol ); qalSourcef( ch->srcnum, AL_REFERENCE_DISTANCE, SOUND_FULLVOLUME ); @@ -296,7 +295,7 @@ static void AL_AddLoopSounds( void ) { int num; entity_state_t *ent; - if( cls.state != ca_active || !s_ambient->value ) { // FIXME: sv_paused->value || + if( cls.state != ca_active || cl_paused->value || !s_ambient->value ) { return; } @@ -359,12 +358,6 @@ void AL_Update( void ) { channel_t *ch; vec_t orientation[6]; - /* FIXME - if( !s_active ) { - return; - } - */ - paintedtime = cl.time; // set listener parameters @@ -398,12 +391,9 @@ void AL_Update( void ) { } } -#ifdef _DEBUG - if (s_show->integer) { + if (s_show->value) { Com_Printf ("%.1f %s\n", ch->master_vol, ch->sfx->name); - // total++; } -#endif AL_Spatialize(ch); // respatialize channel } @@ -425,7 +415,7 @@ void AL_Underwater() int i; // Apply to all sources - for (i = 0; i < MAX_CHANNELS - 1; i++) + for (i = 0; i < s_numchannels; i++) { qalSourcei(s_srcnums[i], AL_DIRECT_FILTER, underwaterFilter); } @@ -436,48 +426,16 @@ void AL_Overwater() int i; // Apply to all sources - for (i = 0; i < MAX_CHANNELS - 1; i++) + for (i = 0; i < s_numchannels; i++) { qalSourcei(s_srcnums[i], AL_DIRECT_FILTER, 0); } } -/* -=========================================================================== -* The remaining functions in this file are from zeq2 who seem to have got -* them from ioquake3. Adapted for Yamagi Quake II (e.g. we only need one -* non-spatialized stream) -* -* They came with the following copyright notice (modified to make clear -* that only the rest of this file is affected): - -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com) - 2012 Some changes by the Yamagi Quake II developers - -The rest of this file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== - */ - static void S_AL_StreamDie( void ) { int numBuffers; - streamPlaying = false; qalSourceStop(streamSource); @@ -490,8 +448,6 @@ static void S_AL_StreamDie( void ) qalDeleteBuffers(1, &buffer); active_buffers--; } - - // S_AL_FreeStreamChannel(stream); } static void S_AL_StreamUpdate( void ) @@ -516,10 +472,6 @@ static void S_AL_StreamUpdate( void ) if(state == AL_STOPPED) { streamPlaying = false; - - // If there are no buffers queued up, release the streamSource - //if( !numBuffers ) - // S_AL_FreeStreamChannel( stream ); } if( !streamPlaying && numBuffers ) @@ -572,17 +524,6 @@ void AL_RawSamples( int samples, int rate, int width, int channels, byte *data, // emulate behavior of S_RawSamples for s_rawend s_rawend += samples; - /* - // get this buffers speed/frequency - ALint speed = 0; - qalGetBufferi(buffer, AL_FREQUENCY, &speed); - // FIXME: the buffers are leaking I think - float scale = (float) rate / speed; - - if( samples > 0 && scale >= 0.0f ) { - s_rawend += samples/scale; - } - */ } void AL_UnqueueRawSamples() diff --git a/src/client/sound/snd_dma.c b/src/client/sound/snd_dma.c index b5fb339f..4d17fb73 100644 --- a/src/client/sound/snd_dma.c +++ b/src/client/sound/snd_dma.c @@ -1005,7 +1005,7 @@ S_AddLoopSounds ( void ) return; } - if ( !cl.sound_prepped || !s_ambient->value ) // FIXME: || sv_paused->value ) + if ( !cl.sound_prepped || !s_ambient->value ) { return; } diff --git a/src/unix/qal.c b/src/unix/qal.c index f20648d7..24fc1308 100644 --- a/src/unix/qal.c +++ b/src/unix/qal.c @@ -183,7 +183,7 @@ void QAL_SoundInfo() if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) { - const char *devs = alcGetString(NULL, ALC_DEVICE_SPECIFIER); + const char *devs = alcGetString(device, ALC_DEVICE_SPECIFIER); Com_Printf("\nCurrent OpenAL device:\n");