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");