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 ;)
This commit is contained in:
Daniel Gibson 2012-04-15 02:58:01 +00:00
parent 9ee0341d14
commit 7e0a44825e
10 changed files with 808 additions and 93 deletions

View file

@ -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

View file

@ -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 <AL/al.h>
#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 );

131
src/client/sound/qal_api.c Normal file
View file

@ -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 <AL/alc.h>
#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;
}

361
src/client/sound/snd_al.c Normal file
View file

@ -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

View file

@ -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

View file

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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

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