r343 - in trunk: . code/client code/macosx/Quake3.pbproj code/unix

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Sun Nov 13 13:58:15 EST 2005


Author: tma
Date: 2005-11-13 13:58:14 -0500 (Sun, 13 Nov 2005)
New Revision: 343

Added:
   trunk/code/client/qal.c
   trunk/code/client/qal.h
   trunk/code/client/snd_codec.c
   trunk/code/client/snd_codec.h
   trunk/code/client/snd_codec_wav.c
   trunk/code/client/snd_main.c
   trunk/code/client/snd_openal.c
Modified:
   trunk/code/client/snd_dma.c
   trunk/code/client/snd_local.h
   trunk/code/client/snd_mem.c
   trunk/code/macosx/Quake3.pbproj/project.pbxproj
   trunk/code/unix/Makefile
   trunk/code/unix/sdl_snd.c
   trunk/i_o-q3-readme
Log:
* OpenAL support, from BlackAura aka Stuart Dalton <badcdev at gmail.com>
  + An abstract codec system, simplifying support for new formats
  + Changes versus BlackAura's patch:
    o Consolidated the OpenAL parts into one file
    o Changed the function naming scheme to more closely resemble Q3
    o Changed the interface to fall back on the "base" sound system
      if loading OpenAL fails
  + This is enabled on Linux and MinGW for now, but should work on the
    other *nixs with appropriate additions to the Makefile
  + NOT enabled on OS X or MSVC Windows builds
  + Probably breaks the Windows build again
* Retabulated sdl_snd.c and made the messages less verbose since
  there do not seem to be many having problems with SDL sound now


Added: trunk/code/client/qal.c
===================================================================
--- trunk/code/client/qal.c	2005-11-13 18:33:28 UTC (rev 342)
+++ trunk/code/client/qal.c	2005-11-13 18:58:14 UTC (rev 343)
@@ -0,0 +1,344 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
+
+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
+===========================================================================
+*/
+
+// Dynamically loads OpenAL
+
+#if USE_OPENAL
+
+#include "qal.h"
+
+#if defined _WIN32
+#include <windows.h>
+#define OBJTYPE HMODULE
+#define OBJLOAD(x) LoadLibrary(x)
+#define SYMLOAD(x,y) GetProcAddress(x,y)
+#define OBJFREE(x) FreeLibrary(x)
+
+#elif defined __linux__ || defined __FreeBSD__
+#include <unistd.h>
+#include <sys/types.h>
+#include <dlfcn.h>
+#define OBJTYPE void *
+#define OBJLOAD(x) dlopen(x, RTLD_LAZY | RTLD_GLOBAL)
+#define SYMLOAD(x,y) dlsym(x,y)
+#define OBJFREE(x) dlclose(x)
+#else
+
+#error "Your platform has no lib loading code or it is disabled"
+#endif
+
+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;
+LPALGETLISTENERF qalGetListenerf;
+LPALGETLISTENER3F qalGetListener3f;
+LPALGETLISTENERFV qalGetListenerfv;
+LPALGETLISTENERI qalGetListeneri;
+LPALGENSOURCES qalGenSources;
+LPALDELETESOURCES qalDeleteSources;
+LPALISSOURCE qalIsSource;
+LPALSOURCEF qalSourcef;
+LPALSOURCE3F qalSource3f;
+LPALSOURCEFV qalSourcefv;
+LPALSOURCEI qalSourcei;
+LPALGETSOURCEF qalGetSourcef;
+LPALGETSOURCE3F qalGetSource3f;
+LPALGETSOURCEFV qalGetSourcefv;
+LPALGETSOURCEI qalGetSourcei;
+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;
+LPALGETBUFFERF qalGetBufferf;
+LPALGETBUFFERI qalGetBufferi;
+LPALDOPPLERFACTOR qalDopplerFactor;
+LPALDOPPLERVELOCITY qalDopplerVelocity;
+LPALDISTANCEMODEL qalDistanceModel;
+
+LPALCCREATECONTEXT qalcCreateContext;
+LPALCMAKECONTEXTCURRENT qalcMakeContextCurrent;
+LPALCPROCESSCONTEXT qalcProcessContext;
+LPALCSUSPENDCONTEXT qalcSuspendContext;
+LPALCDESTROYCONTEXT qalcDestroyContext;
+LPALCGETCURRENTCONTEXT qalcGetCurrentContext;
+LPALCGETCONTEXTSDEVICE qalcGetContextsDevice;
+LPALCOPENDEVICE qalcOpenDevice;
+LPALCCLOSEDEVICE qalcCloseDevice;
+LPALCGETERROR qalcGetError;
+LPALCISEXTENSIONPRESENT qalcIsExtensionPresent;
+LPALCGETPROCADDRESS qalcGetProcAddress;
+LPALCGETENUMVALUE qalcGetEnumValue;
+LPALCGETSTRING qalcGetString;
+LPALCGETINTEGERV qalcGetIntegerv;
+
+static OBJTYPE OpenALLib = NULL;
+
+static qboolean alinit_fail = qfalse;
+
+/*
+=================
+GPA
+=================
+*/
+static void *GPA(char *str)
+{
+	void *rv;
+
+	rv = SYMLOAD(OpenALLib, str);
+	if(!rv)
+	{
+		Com_Printf( " Can't load symbol %s\n", str);
+		alinit_fail = qtrue;
+		return NULL;
+	}
+	else
+	{
+		Com_DPrintf( " Loaded symbol %s (0x%08X)\n", str, rv);
+        return rv;
+	}
+}
+
+/*
+=================
+QAL_Init
+=================
+*/
+qboolean QAL_Init(const char *libname)
+{
+	if(OpenALLib)
+		return qtrue;
+
+	Com_Printf( "Loading \"%s\"...\n", libname);
+	if( (OpenALLib = OBJLOAD(libname)) == 0 )
+	{
+#ifdef _WIN32
+		return qfalse;
+#else
+		char fn[1024];
+		getcwd(fn, sizeof(fn));
+		strncat(fn, "/", sizeof(fn));
+		strncat(fn, libname, sizeof(fn));
+
+		if( (OpenALLib = OBJLOAD(fn)) == 0 )
+		{
+			return qfalse;
+		}
+#endif
+	}
+
+	alinit_fail = qfalse;
+
+	qalEnable = GPA("alEnable");
+	qalDisable = GPA("alDisable");
+	qalIsEnabled = GPA("alIsEnabled");
+	qalGetString = GPA("alGetString");
+	qalGetBooleanv = GPA("alGetBooleanv");
+	qalGetIntegerv = GPA("alGetIntegerv");
+	qalGetFloatv = GPA("alGetFloatv");
+	qalGetDoublev = GPA("alGetDoublev");
+	qalGetBoolean = GPA("alGetBoolean");
+	qalGetInteger = GPA("alGetInteger");
+	qalGetFloat = GPA("alGetFloat");
+	qalGetDouble = GPA("alGetDouble");
+	qalGetError = GPA("alGetError");
+	qalIsExtensionPresent = GPA("alIsExtensionPresent");
+	qalGetProcAddress = GPA("alGetProcAddress");
+	qalGetEnumValue = GPA("alGetEnumValue");
+	qalListenerf = GPA("alListenerf");
+	qalListener3f = GPA("alListener3f");
+	qalListenerfv = GPA("alListenerfv");
+	qalListeneri = GPA("alListeneri");
+	qalGetListenerf = GPA("alGetListenerf");
+	qalGetListener3f = GPA("alGetListener3f");
+	qalGetListenerfv = GPA("alGetListenerfv");
+	qalGetListeneri = GPA("alGetListeneri");
+	qalGenSources = GPA("alGenSources");
+	qalDeleteSources = GPA("alDeleteSources");
+	qalIsSource = GPA("alIsSource");
+	qalSourcef = GPA("alSourcef");
+	qalSource3f = GPA("alSource3f");
+	qalSourcefv = GPA("alSourcefv");
+	qalSourcei = GPA("alSourcei");
+	qalGetSourcef = GPA("alGetSourcef");
+	qalGetSource3f = GPA("alGetSource3f");
+	qalGetSourcefv = GPA("alGetSourcefv");
+	qalGetSourcei = GPA("alGetSourcei");
+	qalSourcePlayv = GPA("alSourcePlayv");
+	qalSourceStopv = GPA("alSourceStopv");
+	qalSourceRewindv = GPA("alSourceRewindv");
+	qalSourcePausev = GPA("alSourcePausev");
+	qalSourcePlay = GPA("alSourcePlay");
+	qalSourceStop = GPA("alSourceStop");
+	qalSourceRewind = GPA("alSourceRewind");
+	qalSourcePause = GPA("alSourcePause");
+	qalSourceQueueBuffers = GPA("alSourceQueueBuffers");
+	qalSourceUnqueueBuffers = GPA("alSourceUnqueueBuffers");
+	qalGenBuffers = GPA("alGenBuffers");
+	qalDeleteBuffers = GPA("alDeleteBuffers");
+	qalIsBuffer = GPA("alIsBuffer");
+	qalBufferData = GPA("alBufferData");
+	qalGetBufferf = GPA("alGetBufferf");
+	qalGetBufferi = GPA("alGetBufferi");
+	qalDopplerFactor = GPA("alDopplerFactor");
+	qalDopplerVelocity = GPA("alDopplerVelocity");
+	qalDistanceModel = GPA("alDistanceModel");
+
+	qalcCreateContext = GPA("alcCreateContext");
+	qalcMakeContextCurrent = GPA("alcMakeContextCurrent");
+	qalcProcessContext = GPA("alcProcessContext");
+	qalcSuspendContext = GPA("alcSuspendContext");
+	qalcDestroyContext = GPA("alcDestroyContext");
+	qalcGetCurrentContext = GPA("alcGetCurrentContext");
+	qalcGetContextsDevice = GPA("alcGetContextsDevice");
+	qalcOpenDevice = GPA("alcOpenDevice");
+	qalcCloseDevice = GPA("alcCloseDevice");
+	qalcGetError = GPA("alcGetError");
+	qalcIsExtensionPresent = GPA("alcIsExtensionPresent");
+	qalcGetProcAddress = GPA("alcGetProcAddress");
+	qalcGetEnumValue = GPA("alcGetEnumValue");
+	qalcGetString = GPA("alcGetString");
+	qalcGetIntegerv = GPA("alcGetIntegerv");
+
+	if(alinit_fail)
+	{
+		QAL_Shutdown();
+		Com_Printf( " One or more symbols not found\n");
+		return qfalse;
+	}
+
+	return qtrue;
+}
+
+/*
+=================
+QAL_Shutdown
+=================
+*/
+void QAL_Shutdown( void )
+{
+	if(OpenALLib)
+	{
+		OBJFREE(OpenALLib);
+		OpenALLib = NULL;
+	}
+
+	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;
+	qalGetListenerf = NULL;
+	qalGetListener3f = NULL;
+	qalGetListenerfv = NULL;
+	qalGetListeneri = NULL;
+	qalGenSources = NULL;
+	qalDeleteSources = NULL;
+	qalIsSource = NULL;
+	qalSourcef = NULL;
+	qalSource3f = NULL;
+	qalSourcefv = NULL;
+	qalSourcei = NULL;
+	qalGetSourcef = NULL;
+	qalGetSource3f = NULL;
+	qalGetSourcefv = NULL;
+	qalGetSourcei = 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;
+	qalGetBufferf = NULL;
+	qalGetBufferi = NULL;
+	qalDopplerFactor = NULL;
+	qalDopplerVelocity = NULL;
+	qalDistanceModel = NULL;
+
+	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;
+}
+
+#endif

Added: trunk/code/client/qal.h
===================================================================
--- trunk/code/client/qal.h	2005-11-13 18:33:28 UTC (rev 342)
+++ trunk/code/client/qal.h	2005-11-13 18:58:14 UTC (rev 343)
@@ -0,0 +1,134 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
+
+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
+===========================================================================
+*/
+
+
+#ifndef __QAL_H__
+#define __QAL_H__
+
+#include "../qcommon/q_shared.h"
+#include "../qcommon/qcommon.h"
+
+#define AL_NO_PROTOTYPES
+#define ALC_NO_PROTOTYPES
+#include <AL/al.h>
+#include <AL/alc.h>
+
+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 LPALBUFFERF qalBufferi;
+extern LPALBUFFER3F qalBuffer3i;
+extern LPALBUFFERFV 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;
+
+extern LPALCCREATECONTEXT qalcCreateContext;
+extern LPALCMAKECONTEXTCURRENT qalcMakeContextCurrent;
+extern LPALCPROCESSCONTEXT qalcProcessContext;
+extern LPALCSUSPENDCONTEXT qalcSuspendContext;
+extern LPALCDESTROYCONTEXT qalcDestroyContext;
+extern LPALCGETCURRENTCONTEXT qalcGetCurrentContext;
+extern LPALCGETCONTEXTSDEVICE qalcGetContextsDevice;
+extern LPALCOPENDEVICE qalcOpenDevice;
+extern LPALCCLOSEDEVICE qalcCloseDevice;
+extern LPALCGETERROR qalcGetError;
+extern LPALCISEXTENSIONPRESENT qalcIsExtensionPresent;
+extern LPALCGETPROCADDRESS qalcGetProcAddress;
+extern LPALCGETENUMVALUE qalcGetEnumValue;
+extern LPALCGETSTRING qalcGetString;
+extern LPALCGETINTEGERV qalcGetIntegerv;
+extern LPALCCAPTUREOPENDEVICE qalcCaptureOpenDevice;
+extern LPALCCAPTURECLOSEDEVICE qalcCaptureCloseDevice;
+extern LPALCCAPTURESTART qalcCaptureStart;
+extern LPALCCAPTURESTOP qalcCaptureStop;
+extern LPALCCAPTURESAMPLES qalcCaptureSamples;
+
+qboolean QAL_Init(const char *libname);
+void QAL_Shutdown( void );
+
+#endif	// __QAL_H__

Added: trunk/code/client/snd_codec.c
===================================================================
--- trunk/code/client/snd_codec.c	2005-11-13 18:33:28 UTC (rev 342)
+++ trunk/code/client/snd_codec.c	2005-11-13 18:58:14 UTC (rev 343)
@@ -0,0 +1,226 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
+
+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
+===========================================================================
+*/
+
+#include "client.h"
+#include "snd_codec.h"
+
+static snd_codec_t *codecs;
+
+/*
+=================
+S_FileExtension
+=================
+*/
+static char *S_FileExtension(const char *fni)
+{
+	char *fn = (char *)fni;
+	char *eptr = NULL;
+	while(*fn)
+	{
+		if(*fn == '.')
+			eptr = fn;
+		fn++;
+	}
+
+	return eptr;
+}
+
+/*
+=================
+S_FindCodecForFile
+
+Select an appropriate codec for a file based on its extension
+=================
+*/
+static snd_codec_t *S_FindCodecForFile(const char *filename)
+{
+	char *ext = S_FileExtension(filename);
+	snd_codec_t *codec = codecs;
+
+	if(!ext)
+	{
+		// No extension - auto-detect
+		while(codec)
+		{
+			char fn[MAX_QPATH];
+			Q_strncpyz(fn, filename, sizeof(fn) - 4);
+			COM_DefaultExtension(fn, sizeof(fn), codec->ext);
+
+			// Check it exists
+			if(FS_ReadFile(fn, NULL) != -1)
+				return codec;
+
+			// Nope. Next!
+			codec = codec->next;
+		}
+
+		// Nothin'
+		return NULL;
+	}
+
+	while(codec)
+	{
+		if(!Q_stricmp(ext, codec->ext))
+			return codec;
+		codec = codec->next;
+	}
+
+	return NULL;
+}
+
+/*
+=================
+S_CodecInit
+=================
+*/
+void S_CodecInit()
+{
+	codecs = NULL;
+	S_CodecRegister(&wav_codec);
+#ifdef USE_CODEC_VORBIS
+	S_CodecRegister(&ogg_codec);
+#endif
+}
+
+/*
+=================
+S_CodecShutdown
+=================
+*/
+void S_CodecShutdown()
+{
+	codecs = NULL;
+}
+
+/*
+=================
+S_CodecRegister
+=================
+*/
+void S_CodecRegister(snd_codec_t *codec)
+{
+	codec->next = codecs;
+	codecs = codec;
+}
+
+/*
+=================
+S_CodecLoad
+=================
+*/
+void *S_CodecLoad(const char *filename, snd_info_t *info)
+{
+	snd_codec_t *codec;
+	char fn[MAX_QPATH];
+
+	codec = S_FindCodecForFile(filename);
+	if(!codec)
+	{
+		Com_Printf("Unknown extension for %s\n", filename);
+		return NULL;
+	}
+
+	strncpy(fn, filename, sizeof(fn));
+	COM_DefaultExtension(fn, sizeof(fn), codec->ext);
+
+	return codec->load(fn, info);
+}
+
+/*
+=================
+S_CodecOpenStream
+=================
+*/
+snd_stream_t *S_CodecOpenStream(const char *filename)
+{
+	snd_codec_t *codec;
+	char fn[MAX_QPATH];
+
+	codec = S_FindCodecForFile(filename);
+	if(!codec)
+	{
+		Com_Printf("Unknown extension for %s\n", filename);
+		return NULL;
+	}
+
+	strncpy(fn, filename, sizeof(fn));
+	COM_DefaultExtension(fn, sizeof(fn), codec->ext);
+
+	return codec->open(fn);
+}
+
+void S_CodecCloseStream(snd_stream_t *stream)
+{
+	stream->codec->close(stream);
+}
+
+int S_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
+{
+	return stream->codec->read(stream, bytes, buffer);
+}
+
+//=======================================================================
+// Util functions (used by codecs)
+
+/*
+=================
+S_CodecUtilOpen
+=================
+*/
+snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec)
+{
+	snd_stream_t *stream;
+	fileHandle_t hnd;
+
+	// Try to open the file
+	FS_FOpenFileRead(filename, &hnd, qtrue);
+	if(!hnd)
+	{
+		Com_Printf("Can't read sound file %s\n", filename);
+		return NULL;
+	}
+
+	// Allocate a stream
+	stream = Z_Malloc(sizeof(snd_stream_t));
+	if(!stream)
+	{
+		FS_FCloseFile(hnd);
+		return NULL;
+	}
+
+	// Copy over, return
+	stream->codec = codec;
+	stream->file = hnd;
+	return stream;
+}
+
+/*
+=================
+S_CodecUtilClose
+=================
+*/
+void S_CodecUtilClose(snd_stream_t *stream)
+{
+	FS_FCloseFile(stream->file);
+	Z_Free(stream);
+}

Added: trunk/code/client/snd_codec.h
===================================================================
--- trunk/code/client/snd_codec.h	2005-11-13 18:33:28 UTC (rev 342)
+++ trunk/code/client/snd_codec.h	2005-11-13 18:58:14 UTC (rev 343)
@@ -0,0 +1,97 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
+
+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
+===========================================================================
+*/
+
+#ifndef _SND_CODEC_H_
+#define _SND_CODEC_H_
+
+#include "../qcommon/q_shared.h"
+#include "../qcommon/qcommon.h"
+
+typedef struct snd_info_s
+{
+	int rate;
+	int width;
+	int channels;
+	int samples;
+	int size;
+	int dataofs;
+} snd_info_t;
+
+typedef struct snd_codec_s snd_codec_t;
+
+typedef struct snd_stream_s
+{
+	snd_codec_t *codec;
+	fileHandle_t file;
+	snd_info_t info;
+	int pos;
+	void *ptr;
+} snd_stream_t;
+
+// Codec functions
+typedef void *(*CODEC_LOAD)(const char *filename, snd_info_t *info);
+typedef snd_stream_t *(*CODEC_OPEN)(const char *filename);
+typedef int (*CODEC_READ)(snd_stream_t *stream, int bytes, void *buffer);
+typedef void (*CODEC_CLOSE)(snd_stream_t *stream);
+
+// Codec data structure
+struct snd_codec_s
+{
+	char *ext;
+	CODEC_LOAD load;
+	CODEC_OPEN open;
+	CODEC_READ read;
+	CODEC_CLOSE close;
+	snd_codec_t *next;
+};
+
+// Codec management
+void S_CodecInit( void );
+void S_CodecShutdown( void );
+void S_CodecRegister(snd_codec_t *codec);
+void *S_CodecLoad(const char *filename, snd_info_t *info);
+snd_stream_t *S_CodecOpenStream(const char *filename);
+void S_CodecCloseStream(snd_stream_t *stream);
+int S_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
+
+// Util functions (used by codecs)
+snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec);
+void S_CodecUtilClose(snd_stream_t *stream);
+
+// WAV Codec
+extern snd_codec_t wav_codec;
+void *S_WAV_CodecLoad(const char *filename, snd_info_t *info);
+snd_stream_t *S_WAV_CodecOpenStream(const char *filename);
+void S_WAV_CodecCloseStream(snd_stream_t *stream);
+int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
+
+// Ogg Vorbis codec
+#ifdef USE_CODEC_VORBIS
+extern snd_codec_t ogg_codec;
+void *S_OGG_CodecLoad(const char *filename, snd_info_t *info);
+snd_stream_t *S_OGG_CodecOpenStream(const char *filename);
+void S_OGG_CodecCloseStream(snd_stream_t *stream);
+int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
+#endif // USE_CODEC_VORBIS
+
+#endif // !_SND_CODEC_H_

Added: trunk/code/client/snd_codec_wav.c
===================================================================
--- trunk/code/client/snd_codec_wav.c	2005-11-13 18:33:28 UTC (rev 342)
+++ trunk/code/client/snd_codec_wav.c	2005-11-13 18:58:14 UTC (rev 343)
@@ -0,0 +1,307 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
+
+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
+===========================================================================
+*/
+
+#include "client.h"
+#include "snd_codec.h"
+
+/*
+=================
+FGetLittleLong
+=================
+*/
+static int FGetLittleLong( fileHandle_t f ) {
+	int		v;
+
+	FS_Read( &v, sizeof(v), f );
+
+	return LittleLong( v);
+}
+
+/*
+=================
+FGetLittleShort
+=================
+*/
+static int FGetLittleShort( fileHandle_t f ) {
+	short	v;
+
+	FS_Read( &v, sizeof(v), f );
+
+	return LittleShort( v);
+}
+
+/*
+=================
+S_ReadChunkInfo
+=================
+*/
+static int S_ReadChunkInfo(fileHandle_t f, char *name)
+{
+	int len, r;
+
+	name[4] = 0;
+
+	r = FS_Read(name, 4, f);
+	if(r != 4)
+		return 0;
+
+	len = FGetLittleLong(f);
+	if(len < 0 || len > 0xffffffff)
+		return 0;
+
+	//FIXME: 11/11/05 <tim at ngus.net>
+	// I'm not sure I understand why this needs to be padded.
+	// Surely this results in reading past the end of the data?
+	//len = (len + 1 ) & ~1;		// pad to word boundary
+
+	return len;
+}
+
+/*
+=================
+S_SkipChunk
+=================
+*/
+static void S_SkipChunk(fileHandle_t f, int length)
+{
+	byte buffer[32*1024];
+
+	while(length > 0)
+	{
+		int toread = length;
+		if(toread > sizeof(buffer))
+			toread = sizeof(buffer);
+		FS_Read(buffer, toread, f);
+		length -= toread;
+	}
+}
+
+/*
+=================
+S_FindWavChunk
+
+Returns the length of the data in the chunk, or 0 if not found
+=================
+*/
+static int S_FindWavChunk( fileHandle_t f, char *chunk ) {
+	char	name[5];
+	int		len;
+
+	// This is a bit dangerous...
+	while(1)
+	{
+		len = S_ReadChunkInfo(f, name);
+
+		// Read failure?
+		if(len == 0)
+			return 0;
+
+		// If this is the right chunk, return
+		if(!strcmp(name, chunk))
+			return len;
+
+		// Not the right chunk - skip it
+		S_SkipChunk(f, len);
+	}
+}
+
+/*
+=================
+S_ByteSwapRawSamples
+=================
+*/
+static void S_ByteSwapRawSamples( int samples, int width, int s_channels, const byte *data ) {
+	int		i;
+
+	if ( width != 2 ) {
+		return;
+	}
+	if ( LittleShort( 256 ) == 256 ) {
+		return;
+	}
+
+	if ( s_channels == 2 ) {
+		samples <<= 1;
+	}
+	for ( i = 0 ; i < samples ; i++ ) {
+		((short *)data)[i] = LittleShort( ((short *)data)[i] );
+	}
+}
+
+/*
+=================
+S_ReadWavHeader
+=================
+*/
+static qboolean S_ReadWavHeader(fileHandle_t file, snd_info_t *info)
+{
+	char dump[16];
+	int wav_format;
+	int fmtlen = 0;
+
+	// skip the riff wav header
+	FS_Read(dump, 12, file);
+
+	// Scan for the format chunk
+	if((fmtlen = S_FindWavChunk(file, "fmt ")) == 0)
+	{
+		Com_Printf("No fmt chunk\n");
+		return qfalse;
+	}
+
+	// Save the parameters
+	wav_format = FGetLittleShort(file);
+	info->channels = FGetLittleShort(file);
+	info->rate = FGetLittleLong(file);
+	FGetLittleLong(file);
+	FGetLittleShort(file);
+	info->width = FGetLittleShort(file) / 8;
+	info->dataofs = 0;
+
+	// Skip the rest of the format chunk if required
+	if(fmtlen > 16)
+	{
+		fmtlen -= 16;
+		S_SkipChunk(file, fmtlen);
+	}
+
+	// Scan for the data chunk
+	if( (info->size = S_FindWavChunk(file, "data")) == 0)
+	{
+		Com_Printf("No data chunk\n");
+		return qfalse;
+	}
+	info->samples = (info->size / info->width) / info->channels;
+
+	return qtrue;
+}
+
+// WAV codec
+snd_codec_t wav_codec =
+{
+	".wav",
+	S_WAV_CodecLoad,
+	S_WAV_CodecOpenStream,
+	S_WAV_CodecReadStream,
+	S_WAV_CodecCloseStream,
+	NULL
+};
+
+/*
+=================
+S_WAV_CodecLoad
+=================
+*/
+void *S_WAV_CodecLoad(const char *filename, snd_info_t *info)
+{
+	fileHandle_t file;
+	void *buffer;
+
+	// Try to open the file
+	FS_FOpenFileRead(filename, &file, qtrue);
+	if(!file)
+	{
+		Com_Printf("Can't read sound file %s\n", filename);
+		return NULL;
+	}
+
+	// Read the RIFF header
+	if(!S_ReadWavHeader(file, info))
+	{
+		FS_FCloseFile(file);
+		Com_Printf("Can't understand wav file %s\n", filename);
+		return NULL;
+	}
+
+	// Allocate some memory
+	buffer = Z_Malloc(info->size);
+	if(!buffer)
+	{
+		FS_FCloseFile(file);
+		Com_Printf("Out of memory reading %s\n", filename);
+		return NULL;
+	}
+
+	// Read, byteswap
+	FS_Read(buffer, info->size, file);
+	S_ByteSwapRawSamples(info->samples, info->width, info->channels, (byte *)buffer);
+
+	// Close and return
+	FS_FCloseFile(file);
+	return buffer;
+}
+
+/*
+=================
+S_WAV_CodecOpenStream
+=================
+*/
+snd_stream_t *S_WAV_CodecOpenStream(const char *filename)
+{
+	snd_stream_t *rv;
+
+	// Open
+	rv = S_CodecUtilOpen(filename, &wav_codec);
+	if(!rv)
+		return NULL;
+
+	// Read the RIFF header
+	if(!S_ReadWavHeader(rv->file, &rv->info))
+	{
+		S_CodecUtilClose(rv);
+		return NULL;
+	}
+
+	return rv;
+}
+
+/*
+=================
+S_WAV_CodecCloseStream
+=================
+*/
+void S_WAV_CodecCloseStream(snd_stream_t *stream)
+{
+	S_CodecUtilClose(stream);
+}
+
+/*
+=================
+S_WAV_CodecReadStream
+=================
+*/
+int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
+{
+	int remaining = stream->info.size - stream->pos;
+	int samples;
+
+	if(remaining <= 0)
+		return 0;
+	if(bytes > remaining)
+		bytes = remaining;
+	stream->pos += bytes;
+	samples = (bytes / stream->info.width) / stream->info.channels;
+	FS_Read(buffer, bytes, stream->file);
+	S_ByteSwapRawSamples(samples, stream->info.width, stream->info.channels, buffer);
+	return bytes;
+}

Modified: trunk/code/client/snd_dma.c
===================================================================
--- trunk/code/client/snd_dma.c	2005-11-13 18:33:28 UTC (rev 342)
+++ trunk/code/client/snd_dma.c	2005-11-13 18:58:14 UTC (rev 343)
@@ -30,6 +30,7 @@
  *****************************************************************************/
 
 #include "snd_local.h"
+#include "snd_codec.h"
 #include "client.h"
 
 void S_Play_f(void);
@@ -37,13 +38,11 @@
 void S_Music_f(void);
 
 void S_Update_( void );
-void S_StopAllSounds(void);
 void S_UpdateBackgroundTrack( void );
+void S_Base_StopAllSounds(void);
+void S_Base_StopBackgroundTrack( void );
 
-static fileHandle_t s_backgroundFile;
-static wavinfo_t	s_backgroundInfo;
-//int			s_nextWavChunk;
-static int			s_backgroundSamples;
+snd_stream_t	*s_backgroundStream = NULL;
 static char		s_backgroundLoop[MAX_QPATH];
 //static char		s_backgroundMusic[MAX_QPATH]; //TTimo: unused
 
@@ -82,15 +81,11 @@
 #define		LOOP_HASH		128
 static	sfx_t		*sfxHash[LOOP_HASH];
 
-cvar_t		*s_volume;
 cvar_t		*s_testsound;
 cvar_t		*s_khz;
 cvar_t		*s_show;
 cvar_t		*s_mixahead;
 cvar_t		*s_mixPreStep;
-cvar_t		*s_musicVolume;
-cvar_t		*s_separation;
-cvar_t		*s_doppler;
 
 static loopSound_t		loopSounds[MAX_GENTITIES];
 static	channel_t		*freelist = NULL;
@@ -104,7 +99,7 @@
 // ====================================================================
 
 
-void S_SoundInfo_f(void) {	
+void S_Base_SoundInfo(void) {	
 	Com_Printf("----- Sound Info -----\n" );
 	if (!s_soundStarted) {
 		Com_Printf ("sound system not started\n");
@@ -115,7 +110,7 @@
 		Com_Printf("%5d submission_chunk\n", dma.submission_chunk);
 		Com_Printf("%5d speed\n", dma.speed);
 		Com_Printf("0x%x dma buffer\n", dma.buffer);
-		if ( s_backgroundFile ) {
+		if ( s_backgroundStream ) {
 			Com_Printf("Background file: %s\n", s_backgroundLoop );
 		} else {
 			Com_Printf("No background file.\n" );
@@ -125,64 +120,37 @@
 	Com_Printf("----------------------\n" );
 }
 
-
-
 /*
-================
-S_Init
-================
+=================
+S_Base_SoundList
+=================
 */
-void S_Init( void ) {
-	cvar_t	*cv;
-	qboolean	r;
+void S_Base_SoundList( void ) {
+	int		i;
+	sfx_t	*sfx;
+	int		size, total;
+	char	type[4][16];
+	char	mem[2][16];
 
-	Com_Printf("\n------- sound initialization -------\n");
-
-	s_volume = Cvar_Get ("s_volume", "0.8", CVAR_ARCHIVE);
-	s_musicVolume = Cvar_Get ("s_musicvolume", "0.25", CVAR_ARCHIVE);
-	s_separation = Cvar_Get ("s_separation", "0.5", CVAR_ARCHIVE);
-	s_doppler = Cvar_Get ("s_doppler", "1", CVAR_ARCHIVE);
-	s_khz = Cvar_Get ("s_khz", "22", CVAR_ARCHIVE);
-	s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE);
-
-	s_mixPreStep = Cvar_Get ("s_mixPreStep", "0.05", CVAR_ARCHIVE);
-	s_show = Cvar_Get ("s_show", "0", CVAR_CHEAT);
-	s_testsound = Cvar_Get ("s_testsound", "0", CVAR_CHEAT);
-
-	cv = Cvar_Get ("s_initsound", "1", 0);
-	if ( !cv->integer ) {
-		Com_Printf ("not initializing.\n");
-		Com_Printf("------------------------------------\n");
-		return;
+	strcpy(type[0], "16bit");
+	strcpy(type[1], "adpcm");
+	strcpy(type[2], "daub4");
+	strcpy(type[3], "mulaw");
+	strcpy(mem[0], "paged out");
+	strcpy(mem[1], "resident ");
+	total = 0;
+	for (sfx=s_knownSfx, i=0 ; i<s_numSfx ; i++, sfx++) {
+		size = sfx->soundLength;
+		total += size;
+		Com_Printf("%6i[%s] : %s[%s]\n", size, type[sfx->soundCompressionMethod],
+				sfx->soundName, mem[sfx->inMemory] );
 	}
-
-	Cmd_AddCommand("play", S_Play_f);
-	Cmd_AddCommand("music", S_Music_f);
-	Cmd_AddCommand("s_list", S_SoundList_f);
-	Cmd_AddCommand("s_info", S_SoundInfo_f);
-	Cmd_AddCommand("s_stop", S_StopAllSounds);
-
-	r = SNDDMA_Init();
-	Com_Printf("------------------------------------\n");
-
-	if ( r ) {
-		s_soundStarted = 1;
-		s_soundMuted = 1;
-//		s_numSfx = 0;
-
-		Com_Memset(sfxHash, 0, sizeof(sfx_t *)*LOOP_HASH);
-
-		s_soundtime = 0;
-		s_paintedtime = 0;
-
-		S_StopAllSounds ();
-
-		S_SoundInfo_f();
-	}
-
+	Com_Printf ("Total resident: %i\n", total);
+	S_DisplayFreeMemory();
 }
 
 
+
 void S_ChannelFree(channel_t *v) {
 	v->thesfx = NULL;
 	*(channel_t **)v = freelist;
@@ -217,27 +185,8 @@
 	Com_DPrintf("Channel memory manager started\n");
 }
 
-// =======================================================================
-// Shutdown sound engine
-// =======================================================================
 
-void S_Shutdown( void ) {
-	if ( !s_soundStarted ) {
-		return;
-	}
 
-	SNDDMA_Shutdown();
-
-	s_soundStarted = 0;
-
-    Cmd_RemoveCommand("play");
-	Cmd_RemoveCommand("music");
-	Cmd_RemoveCommand("stopsound");
-	Cmd_RemoveCommand("soundlist");
-	Cmd_RemoveCommand("soundinfo");
-}
-
-
 // =======================================================================
 // Load a sound
 // =======================================================================
@@ -352,40 +301,19 @@
 are no longer valid.
 ===================
 */
-void S_DisableSounds( void ) {
-	S_StopAllSounds();
+void S_Base_DisableSounds( void ) {
+	S_Base_StopAllSounds();
 	s_soundMuted = qtrue;
 }
 
 /*
-=====================
-S_BeginRegistration
-
-=====================
-*/
-void S_BeginRegistration( void ) {
-	s_soundMuted = qfalse;		// we can play again
-
-	if (s_numSfx == 0) {
-		SND_setup();
-
-		s_numSfx = 0;
-		Com_Memset( s_knownSfx, 0, sizeof( s_knownSfx ) );
-		Com_Memset(sfxHash, 0, sizeof(sfx_t *)*LOOP_HASH);
-
-		S_RegisterSound("sound/feedback/hit.wav", qfalse);		// changed to a sound in baseq3
-	}
-}
-
-
-/*
 ==================
 S_RegisterSound
 
 Creates a default buzz sound if the file can't be loaded
 ==================
 */
-sfxHandle_t	S_RegisterSound( const char *name, qboolean compressed ) {
+sfxHandle_t	S_Base_RegisterSound( const char *name, qboolean compressed ) {
 	sfx_t	*sfx;
 
 	compressed = qfalse;
@@ -420,6 +348,26 @@
 	return sfx - s_knownSfx;
 }
 
+/*
+=====================
+S_BeginRegistration
+
+=====================
+*/
+void S_Base_BeginRegistration( void ) {
+	s_soundMuted = qfalse;		// we can play again
+
+	if (s_numSfx == 0) {
+		SND_setup();
+
+		s_numSfx = 0;
+		Com_Memset( s_knownSfx, 0, sizeof( s_knownSfx ) );
+		Com_Memset(sfxHash, 0, sizeof(sfx_t *)*LOOP_HASH);
+
+		S_Base_RegisterSound("sound/feedback/hit.wav", qfalse);		// changed to a sound in baseq3
+	}
+}
+
 void S_memoryLoad(sfx_t	*sfx) {
 	// load the sound file
 	if ( !S_LoadSound ( sfx ) ) {
@@ -470,8 +418,6 @@
 	{
 		rscale = 0.5 * (1.0 + dot);
 		lscale = 0.5 * (1.0 - dot);
-		//rscale = s_separation->value + ( 1.0 - s_separation->value ) * dot;
-		//lscale = s_separation->value - ( 1.0 - s_separation->value ) * dot;
 		if ( rscale < 0 ) {
 			rscale = 0;
 		}
@@ -505,7 +451,7 @@
 Entchannel 0 will never override a playing sound
 ====================
 */
-void S_StartSound(vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfxHandle ) {
+void S_Base_StartSound(vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfxHandle ) {
 	channel_t	*ch;
 	sfx_t		*sfx;
   int i, oldest, chosen, time;
@@ -626,7 +572,7 @@
 S_StartLocalSound
 ==================
 */
-void S_StartLocalSound( sfxHandle_t sfxHandle, int channelNum ) {
+void S_Base_StartLocalSound( sfxHandle_t sfxHandle, int channelNum ) {
 	if ( !s_soundStarted || s_soundMuted ) {
 		return;
 	}
@@ -636,7 +582,7 @@
 		return;
 	}
 
-	S_StartSound (NULL, listener_number, channelNum, sfxHandle );
+	S_Base_StartSound (NULL, listener_number, channelNum, sfxHandle );
 }
 
 
@@ -648,7 +594,7 @@
 so sound doesn't stutter.
 ==================
 */
-void S_ClearSoundBuffer( void ) {
+void S_Base_ClearSoundBuffer( void ) {
 	int		clear;
 		
 	if (!s_soundStarted)
@@ -683,15 +629,15 @@
 S_StopAllSounds
 ==================
 */
-void S_StopAllSounds(void) {
+void S_Base_StopAllSounds(void) {
 	if ( !s_soundStarted ) {
 		return;
 	}
 
 	// stop the background music
-	S_StopBackgroundTrack();
+	S_Base_StopBackgroundTrack();
 
-	S_ClearSoundBuffer ();
+	S_Base_ClearSoundBuffer ();
 }
 
 /*
@@ -702,7 +648,7 @@
 ==============================================================
 */
 
-void S_StopLoopingSound(int entityNum) {
+void S_Base_StopLoopingSound(int entityNum) {
 	loopSounds[entityNum].active = qfalse;
 //	loopSounds[entityNum].sfx = 0;
 	loopSounds[entityNum].kill = qfalse;
@@ -714,12 +660,12 @@
 
 ==================
 */
-void S_ClearLoopingSounds( qboolean killall ) {
+void S_Base_ClearLoopingSounds( qboolean killall ) {
 	int i;
 	for ( i = 0 ; i < MAX_GENTITIES ; i++) {
 		if (killall || loopSounds[i].kill == qtrue || (loopSounds[i].sfx && loopSounds[i].sfx->soundLength == 0)) {
 			loopSounds[i].kill = qfalse;
-			S_StopLoopingSound(i);
+			S_Base_StopLoopingSound(i);
 		}
 	}
 	numLoopChannels = 0;
@@ -733,7 +679,7 @@
 Include velocity in case I get around to doing doppler...
 ==================
 */
-void S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle ) {
+void S_Base_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle ) {
 	sfx_t *sfx;
 
 	if ( !s_soundStarted || s_soundMuted ) {
@@ -796,7 +742,7 @@
 Include velocity in case I get around to doing doppler...
 ==================
 */
-void S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle ) {
+void S_Base_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle ) {
 	sfx_t *sfx;
 
 	if ( !s_soundStarted || s_soundMuted ) {
@@ -947,7 +893,7 @@
 Music streaming
 ============
 */
-void S_RawSamples( int samples, int rate, int width, int s_channels, const byte *data, float volume ) {
+void S_Base_RawSamples( int samples, int rate, int width, int s_channels, const byte *data, float volume ) {
 	int		i;
 	int		src, dst;
 	float	scale;
@@ -1051,7 +997,7 @@
 let the sound system know where an entity currently is
 ======================
 */
-void S_UpdateEntityPosition( int entityNum, const vec3_t origin ) {
+void S_Base_UpdateEntityPosition( int entityNum, const vec3_t origin ) {
 	if ( entityNum < 0 || entityNum > MAX_GENTITIES ) {
 		Com_Error( ERR_DROP, "S_UpdateEntityPosition: bad entitynum %i", entityNum );
 	}
@@ -1066,7 +1012,7 @@
 Change the volumes of all the playing sounds for changes in their positions
 ============
 */
-void S_Respatialize( int entityNum, const vec3_t head, vec3_t axis[3], int inwater ) {
+void S_Base_Respatialize( int entityNum, const vec3_t head, vec3_t axis[3], int inwater ) {
 	int			i;
 	channel_t	*ch;
 	vec3_t		origin;
@@ -1151,7 +1097,7 @@
 Called once each time through the main loop
 ============
 */
-void S_Update( void ) {
+void S_Base_Update( void ) {
 	int			i;
 	int			total;
 	channel_t	*ch;
@@ -1204,7 +1150,7 @@
 		{	// time to chop things off to avoid 32 bit limits
 			buffers = 0;
 			s_paintedtime = fullsamples;
-			S_StopAllSounds ();
+			S_Base_StopAllSounds ();
 		}
 	}
 	oldsamplepos = samplepos;
@@ -1289,75 +1235,8 @@
 	lastTime = thisTime;
 }
 
-/*
-===============================================================================
 
-console functions
 
-===============================================================================
-*/
-
-void S_Play_f( void ) {
-	int 		i;
-	sfxHandle_t	h;
-	char		name[256];
-	
-	i = 1;
-	while ( i<Cmd_Argc() ) {
-		if ( !Q_strrchr(Cmd_Argv(i), '.') ) {
-			Com_sprintf( name, sizeof(name), "%s.wav", Cmd_Argv(1) );
-		} else {
-			Q_strncpyz( name, Cmd_Argv(i), sizeof(name) );
-		}
-		h = S_RegisterSound( name, qfalse );
-		if( h ) {
-			S_StartLocalSound( h, CHAN_LOCAL_SOUND );
-		}
-		i++;
-	}
-}
-
-void S_Music_f( void ) {
-	int		c;
-
-	c = Cmd_Argc();
-
-	if ( c == 2 ) {
-		S_StartBackgroundTrack( Cmd_Argv(1), Cmd_Argv(1) );
-		s_backgroundLoop[0] = 0;
-	} else if ( c == 3 ) {
-		S_StartBackgroundTrack( Cmd_Argv(1), Cmd_Argv(2) );
-	} else {
-		Com_Printf ("music <musicfile> [loopfile]\n");
-		return;
-	}
-
-}
-
-void S_SoundList_f( void ) {
-	int		i;
-	sfx_t	*sfx;
-	int		size, total;
-	char	type[4][16];
-	char	mem[2][16];
-
-	strcpy(type[0], "16bit");
-	strcpy(type[1], "adpcm");
-	strcpy(type[2], "daub4");
-	strcpy(type[3], "mulaw");
-	strcpy(mem[0], "paged out");
-	strcpy(mem[1], "resident ");
-	total = 0;
-	for (sfx=s_knownSfx, i=0 ; i<s_numSfx ; i++, sfx++) {
-		size = sfx->soundLength;
-		total += size;
-		Com_Printf("%6i[%s] : %s[%s]\n", size, type[sfx->soundCompressionMethod], sfx->soundName, mem[sfx->inMemory] );
-	}
-	Com_Printf ("Total resident: %i\n", total);
-	S_DisplayFreeMemory();
-}
-
-
 /*
 ===============================================================================
 
@@ -1366,61 +1245,16 @@
 ===============================================================================
 */
 
-int	FGetLittleLong( fileHandle_t f ) {
-	int		v;
-
-	FS_Read( &v, sizeof(v), f );
-
-	return LittleLong( v);
-}
-
-int	FGetLittleShort( fileHandle_t f ) {
-	short	v;
-
-	FS_Read( &v, sizeof(v), f );
-
-	return LittleShort( v);
-}
-
-// returns the length of the data in the chunk, or 0 if not found
-int S_FindWavChunk( fileHandle_t f, char *chunk ) {
-	char	name[5];
-	int		len;
-	int		r;
-
-	name[4] = 0;
-	len = 0;
-	r = FS_Read( name, 4, f );
-	if ( r != 4 ) {
-		return 0;
-	}
-	len = FGetLittleLong( f );
-	if ( len < 0 || len > 0xfffffff ) {
-		len = 0;
-		return 0;
-	}
-	len = (len + 1 ) & ~1;		// pad to word boundary
-//	s_nextWavChunk += len + 8;
-
-	if ( strcmp( name, chunk ) ) {
-		return 0;
-	}
-
-	return len;
-}
-
 /*
 ======================
 S_StopBackgroundTrack
 ======================
 */
-void S_StopBackgroundTrack( void ) {
-	if ( !s_backgroundFile ) {
+void S_Base_StopBackgroundTrack( void ) {
+	if(!s_backgroundStream)
 		return;
-	}
-	Sys_EndStreamedFile( s_backgroundFile );
-	FS_FCloseFile( s_backgroundFile );
-	s_backgroundFile = 0;
+	S_CodecCloseStream(s_backgroundStream);
+	s_backgroundStream = NULL;
 	s_rawend = 0;
 }
 
@@ -1429,11 +1263,7 @@
 S_StartBackgroundTrack
 ======================
 */
-void S_StartBackgroundTrack( const char *intro, const char *loop ){
-	int		len;
-	char	dump[16];
-	char	name[MAX_QPATH];
-
+void S_Base_StartBackgroundTrack( const char *intro, const char *loop ){
 	if ( !intro ) {
 		intro = "";
 	}
@@ -1442,77 +1272,34 @@
 	}
 	Com_DPrintf( "S_StartBackgroundTrack( %s, %s )\n", intro, loop );
 
-	Q_strncpyz( name, intro, sizeof( name ) - 4 );
-	COM_DefaultExtension( name, sizeof( name ), ".wav" );
-
 	if ( !intro[0] ) {
 		return;
 	}
 
-	Q_strncpyz( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) );
+	if( !loop ) {
+		s_backgroundLoop[0] = 0;
+	} else {
+		Q_strncpyz( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) );
+	}
 
 	// close the background track, but DON'T reset s_rawend
 	// if restarting the same back ground track
-	if ( s_backgroundFile ) {
-		Sys_EndStreamedFile( s_backgroundFile );
-		FS_FCloseFile( s_backgroundFile );
-		s_backgroundFile = 0;
+	if(s_backgroundStream)
+	{
+		S_CodecCloseStream(s_backgroundStream);
+		s_backgroundStream = NULL;
 	}
 
-	//
-	// open up a wav file and get all the info
-	//
-	FS_FOpenFileRead( name, &s_backgroundFile, qtrue );
-	if ( !s_backgroundFile ) {
-		Com_Printf( S_COLOR_YELLOW "WARNING: couldn't open music file %s\n", name );
+	// Open stream
+	s_backgroundStream = S_CodecOpenStream(intro);
+	if(!s_backgroundStream) {
+		Com_Printf( S_COLOR_YELLOW "WARNING: couldn't open music file %s\n", intro );
 		return;
 	}
 
-	// skip the riff wav header
-
-	FS_Read(dump, 12, s_backgroundFile);
-
-	if ( !S_FindWavChunk( s_backgroundFile, "fmt " ) ) {
-		Com_Printf( "No fmt chunk in %s\n", name );
-		FS_FCloseFile( s_backgroundFile );
-		s_backgroundFile = 0;
-		return;
+	if(s_backgroundStream->info.channels != 2 || s_backgroundStream->info.rate != 22050) {
+		Com_Printf(S_COLOR_YELLOW "WARNING: music file %s is not 22k stereo\n", intro );
 	}
-
-	// save name for soundinfo
-	s_backgroundInfo.format = FGetLittleShort( s_backgroundFile );
-	s_backgroundInfo.channels = FGetLittleShort( s_backgroundFile );
-	s_backgroundInfo.rate = FGetLittleLong( s_backgroundFile );
-	FGetLittleLong(  s_backgroundFile );
-	FGetLittleShort(  s_backgroundFile );
-	s_backgroundInfo.width = FGetLittleShort( s_backgroundFile ) / 8;
-
-	if ( s_backgroundInfo.format != WAV_FORMAT_PCM ) {
-		FS_FCloseFile( s_backgroundFile );
-		s_backgroundFile = 0;
-		Com_Printf("Not a microsoft PCM format wav: %s\n", name);
-		return;
-	}
-
-	if ( s_backgroundInfo.channels != 2 || s_backgroundInfo.rate != 22050 ) {
-		Com_Printf(S_COLOR_YELLOW "WARNING: music file %s is not 22k stereo\n", name );
-	}
-
-	if ( ( len = S_FindWavChunk( s_backgroundFile, "data" ) ) == 0 ) {
-		FS_FCloseFile( s_backgroundFile );
-		s_backgroundFile = 0;
-		Com_Printf("No data chunk in %s\n", name);
-		return;
-	}
-
-	s_backgroundInfo.samples = len / (s_backgroundInfo.width * s_backgroundInfo.channels);
-
-	s_backgroundSamples = s_backgroundInfo.samples;
-
-	//
-	// start the background streaming
-	//
-	Sys_BeginStreamedFile( s_backgroundFile, 0x10000 );
 }
 
 /*
@@ -1528,7 +1315,7 @@
 	int		r;
 	static	float	musicVolume = 0.5f;
 
-	if ( !s_backgroundFile ) {
+	if(!s_backgroundStream) {
 		return;
 	}
 
@@ -1549,50 +1336,47 @@
 		bufferSamples = MAX_RAW_SAMPLES - (s_rawend - s_soundtime);
 
 		// decide how much data needs to be read from the file
-		fileSamples = bufferSamples * s_backgroundInfo.rate / dma.speed;
+		fileSamples = bufferSamples * s_backgroundStream->info.rate / dma.speed;
 
-		// don't try and read past the end of the file
-		if ( fileSamples > s_backgroundSamples ) {
-			fileSamples = s_backgroundSamples;
-		}
-
 		// our max buffer size
-		fileBytes = fileSamples * (s_backgroundInfo.width * s_backgroundInfo.channels);
+		fileBytes = fileSamples * (s_backgroundStream->info.width * s_backgroundStream->info.channels);
 		if ( fileBytes > sizeof(raw) ) {
 			fileBytes = sizeof(raw);
-			fileSamples = fileBytes / (s_backgroundInfo.width * s_backgroundInfo.channels);
+			fileSamples = fileBytes / (s_backgroundStream->info.width * s_backgroundStream->info.channels);
 		}
 
-		r = Sys_StreamedRead( raw, 1, fileBytes, s_backgroundFile );
-		if ( r != fileBytes ) {
-			Com_Printf("StreamedRead failure on music track\n");
-			S_StopBackgroundTrack();
-			return;
+		// Read
+		r = S_CodecReadStream(s_backgroundStream, fileBytes, raw);
+		if(r < fileBytes)
+		{
+			fileBytes = r;
+			fileSamples = r / (s_backgroundStream->info.width * s_backgroundStream->info.channels);
 		}
 
-		// byte swap if needed
-		S_ByteSwapRawSamples( fileSamples, s_backgroundInfo.width, s_backgroundInfo.channels, raw );
-
-		// add to raw buffer
-		S_RawSamples( fileSamples, s_backgroundInfo.rate, 
-			s_backgroundInfo.width, s_backgroundInfo.channels, raw, musicVolume );
-
-		s_backgroundSamples -= fileSamples;
-		if ( !s_backgroundSamples ) {
+		if(r > 0)
+		{
+			// add to raw buffer
+			S_Base_RawSamples( fileSamples, s_backgroundStream->info.rate,
+				s_backgroundStream->info.width, s_backgroundStream->info.channels, raw, musicVolume );
+		}
+		else
+		{
 			// loop
-			if (s_backgroundLoop[0]) {
-				Sys_EndStreamedFile( s_backgroundFile );
-				FS_FCloseFile( s_backgroundFile );
-				s_backgroundFile = 0;
-				S_StartBackgroundTrack( s_backgroundLoop, s_backgroundLoop );
-				if ( !s_backgroundFile ) {
-					return;		// loop failed to restart
-				}
-			} else {
-				s_backgroundFile = 0;
+			if(s_backgroundLoop[0])
+			{
+				S_CodecCloseStream(s_backgroundStream);
+				s_backgroundStream = NULL;
+				S_Base_StartBackgroundTrack( s_backgroundLoop, s_backgroundLoop );
+				if(!s_backgroundStream)
+					return;
+			}
+			else
+			{
+				S_Base_StopBackgroundTrack();
 				return;
 			}
 		}
+
 	}
 }
 
@@ -1632,3 +1416,78 @@
 	sfx->inMemory = qfalse;
 	sfx->soundData = NULL;
 }
+
+// =======================================================================
+// Shutdown sound engine
+// =======================================================================
+
+void S_Base_Shutdown( void ) {
+	if ( !s_soundStarted ) {
+		return;
+	}
+
+	SNDDMA_Shutdown();
+
+	s_soundStarted = 0;
+
+	Cmd_RemoveCommand("s_info");
+}
+
+/*
+================
+S_Init
+================
+*/
+qboolean S_Base_Init( soundInterface_t *si ) {
+	qboolean	r;
+
+	if( !si ) {
+		return qfalse;
+	}
+
+	s_khz = Cvar_Get ("s_khz", "22", CVAR_ARCHIVE);
+	s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE);
+	s_mixPreStep = Cvar_Get ("s_mixPreStep", "0.05", CVAR_ARCHIVE);
+	s_show = Cvar_Get ("s_show", "0", CVAR_CHEAT);
+	s_testsound = Cvar_Get ("s_testsound", "0", CVAR_CHEAT);
+
+	r = SNDDMA_Init();
+
+	if ( r ) {
+		s_soundStarted = 1;
+		s_soundMuted = 1;
+//		s_numSfx = 0;
+
+		Com_Memset(sfxHash, 0, sizeof(sfx_t *)*LOOP_HASH);
+
+		s_soundtime = 0;
+		s_paintedtime = 0;
+
+		S_Base_StopAllSounds( );
+	} else {
+		return qfalse;
+	}
+
+	si->Shutdown = S_Base_Shutdown;
+	si->StartSound = S_Base_StartSound;
+	si->StartLocalSound = S_Base_StartLocalSound;
+	si->StartBackgroundTrack = S_Base_StartBackgroundTrack;
+	si->StopBackgroundTrack = S_Base_StopBackgroundTrack;
+	si->RawSamples = S_Base_RawSamples;
+	si->StopAllSounds = S_Base_StopAllSounds;
+	si->ClearLoopingSounds = S_Base_ClearLoopingSounds;
+	si->AddLoopingSound = S_Base_AddLoopingSound;
+	si->AddRealLoopingSound = S_Base_AddRealLoopingSound;
+	si->StopLoopingSound = S_Base_StopLoopingSound;
+	si->Respatialize = S_Base_Respatialize;
+	si->UpdateEntityPosition = S_Base_UpdateEntityPosition;
+	si->Update = S_Base_Update;
+	si->DisableSounds = S_Base_DisableSounds;
+	si->BeginRegistration = S_Base_BeginRegistration;
+	si->RegisterSound = S_Base_RegisterSound;
+	si->ClearSoundBuffer = S_Base_ClearSoundBuffer;
+	si->SoundInfo = S_Base_SoundInfo;
+	si->SoundList = S_Base_SoundList;
+
+	return qtrue;
+}

Modified: trunk/code/client/snd_local.h
===================================================================
--- trunk/code/client/snd_local.h	2005-11-13 18:33:28 UTC (rev 342)
+++ trunk/code/client/snd_local.h	2005-11-13 18:58:14 UTC (rev 343)
@@ -117,7 +117,32 @@
 	int			dataofs;		// chunk starts this many bytes from file start
 } wavinfo_t;
 
+// Interface between Q3 sound "api" and the sound backend
+typedef struct
+{
+	void (*Shutdown)(void);
+	void (*StartSound)( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx );
+	void (*StartLocalSound)( sfxHandle_t sfx, int channelNum );
+	void (*StartBackgroundTrack)( const char *intro, const char *loop );
+	void (*StopBackgroundTrack)( void );
+	void (*RawSamples)(int samples, int rate, int width, int channels, const byte *data, float volume);
+	void (*StopAllSounds)( void );
+	void (*ClearLoopingSounds)( qboolean killall );
+	void (*AddLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
+	void (*AddRealLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
+	void (*StopLoopingSound)(int entityNum );
+	void (*Respatialize)( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
+	void (*UpdateEntityPosition)( int entityNum, const vec3_t origin );
+	void (*Update)( void );
+	void (*DisableSounds)( void );
+	void (*BeginRegistration)( void );
+	sfxHandle_t (*RegisterSound)( const char *sample, qboolean compressed );
+	void (*ClearSoundBuffer)( void );
+	void (*SoundInfo)( void );
+	void (*SoundList)( void );
+} soundInterface_t;
 
+
 /*
 ====================================================================
 
@@ -157,14 +182,11 @@
 #define	MAX_RAW_SAMPLES	16384
 extern	portable_samplepair_t	s_rawsamples[MAX_RAW_SAMPLES];
 
-extern cvar_t	*s_volume;
-extern cvar_t	*s_nosound;
-extern cvar_t	*s_khz;
-extern cvar_t	*s_show;
-extern cvar_t	*s_mixahead;
+extern cvar_t *s_volume;
+extern cvar_t *s_musicVolume;
+extern cvar_t *s_doppler;
 
-extern cvar_t	*s_testsound;
-extern cvar_t	*s_separation;
+extern cvar_t *s_testsound;
 
 qboolean S_LoadSound( sfx_t *sfx );
 
@@ -204,3 +226,18 @@
 extern sfx_t *sfxScratchPointer;
 extern int	   sfxScratchIndex;
 
+qboolean S_Base_Init( soundInterface_t *si );
+
+// OpenAL stuff
+typedef enum
+{
+	SRCPRI_AMBIENT = 0,	// Ambient sound effects
+	SRCPRI_ENTITY,			// Entity sound effects
+	SRCPRI_ONESHOT,			// One-shot sounds
+	SRCPRI_LOCAL,				// Local sounds
+	SRCPRI_STREAM				// Streams (music, cutscenes)
+} alSrcPriority_t;
+
+typedef int srcHandle_t;
+
+qboolean S_AL_Init( soundInterface_t *si );

Added: trunk/code/client/snd_main.c
===================================================================
--- trunk/code/client/snd_main.c	2005-11-13 18:33:28 UTC (rev 342)
+++ trunk/code/client/snd_main.c	2005-11-13 18:58:14 UTC (rev 343)
@@ -0,0 +1,433 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
+
+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 Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+===========================================================================
+*/
+
+#include "client.h"
+#include "snd_codec.h"
+#include "snd_local.h"
+#include "snd_public.h"
+
+cvar_t *s_volume;
+cvar_t *s_musicVolume;
+cvar_t *s_doppler;
+
+static soundInterface_t si;
+
+/*
+=================
+S_ValidateInterface
+=================
+*/
+static qboolean S_ValidSoundInterface( soundInterface_t *si )
+{
+	if( !si->Shutdown ) return qfalse;
+	if( !si->StartSound ) return qfalse;
+	if( !si->StartLocalSound ) return qfalse;
+	if( !si->StartBackgroundTrack ) return qfalse;
+	if( !si->StopBackgroundTrack ) return qfalse;
+	if( !si->RawSamples ) return qfalse;
+	if( !si->StopAllSounds ) return qfalse;
+	if( !si->ClearLoopingSounds ) return qfalse;
+	if( !si->AddLoopingSound ) return qfalse;
+	if( !si->AddRealLoopingSound ) return qfalse;
+	if( !si->StopLoopingSound ) return qfalse;
+	if( !si->Respatialize ) return qfalse;
+	if( !si->UpdateEntityPosition ) return qfalse;
+	if( !si->Update ) return qfalse;
+	if( !si->DisableSounds ) return qfalse;
+	if( !si->BeginRegistration ) return qfalse;
+	if( !si->RegisterSound ) return qfalse;
+	if( !si->ClearSoundBuffer ) return qfalse;
+	if( !si->SoundInfo ) return qfalse;
+	if( !si->SoundList ) return qfalse;
+
+	return qtrue;
+}
+
+/*
+=================
+S_StartSound
+=================
+*/
+void S_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx )
+{
+	if( si.StartSound ) {
+		si.StartSound( origin, entnum, entchannel, sfx );
+	}
+}
+
+/*
+=================
+S_StartLocalSound
+=================
+*/
+void S_StartLocalSound( sfxHandle_t sfx, int channelNum )
+{
+	if( si.StartLocalSound ) {
+		si.StartLocalSound( sfx, channelNum );
+	}
+}
+
+/*
+=================
+S_StartBackgroundTrack
+=================
+*/
+void S_StartBackgroundTrack( const char *intro, const char *loop )
+{
+	if( si.StartBackgroundTrack ) {
+		si.StartBackgroundTrack( intro, loop );
+	}
+}
+
+/*
+=================
+S_StopBackgroundTrack
+=================
+*/
+void S_StopBackgroundTrack( void )
+{
+	if( si.StopBackgroundTrack ) {
+		si.StopBackgroundTrack( );
+	}
+}
+
+/*
+=================
+S_RawSamples
+=================
+*/
+void S_RawSamples (int samples, int rate, int width, int channels,
+		   const byte *data, float volume)
+{
+	if( si.RawSamples ) {
+		si.RawSamples( samples, rate, width, channels, data, volume );
+	}
+}
+
+/*
+=================
+S_StopAllSounds
+=================
+*/
+void S_StopAllSounds( void )
+{
+	if( si.StopAllSounds ) {
+		si.StopAllSounds( );
+	}
+}
+
+/*
+=================
+S_ClearLoopingSounds
+=================
+*/
+void S_ClearLoopingSounds( qboolean killall )
+{
+	if( si.ClearLoopingSounds ) {
+		si.ClearLoopingSounds( killall );
+	}
+}
+
+/*
+=================
+S_AddLoopingSound
+=================
+*/
+void S_AddLoopingSound( int entityNum, const vec3_t origin,
+		const vec3_t velocity, sfxHandle_t sfx )
+{
+	if( si.AddLoopingSound ) {
+		si.AddLoopingSound( entityNum, origin, velocity, sfx );
+	}
+}
+
+/*
+=================
+S_AddRealLoopingSound
+=================
+*/
+void S_AddRealLoopingSound( int entityNum, const vec3_t origin,
+		const vec3_t velocity, sfxHandle_t sfx )
+{
+	if( si.AddRealLoopingSound ) {
+		si.AddRealLoopingSound( entityNum, origin, velocity, sfx );
+	}
+}
+
+/*
+=================
+S_StopLoopingSound
+=================
+*/
+void S_StopLoopingSound( int entityNum )
+{
+	if( si.StopLoopingSound ) {
+		si.StopLoopingSound( entityNum );
+	}
+}
+
+/*
+=================
+S_Respatialize
+=================
+*/
+void S_Respatialize( int entityNum, const vec3_t origin,
+		vec3_t axis[3], int inwater )
+{
+	if( si.Respatialize ) {
+		si.Respatialize( entityNum, origin, axis, inwater );
+	}
+}
+
+/*
+=================
+S_UpdateEntityPosition
+=================
+*/
+void S_UpdateEntityPosition( int entityNum, const vec3_t origin )
+{
+	if( si.UpdateEntityPosition ) {
+		si.UpdateEntityPosition( entityNum, origin );
+	}
+}
+
+/*
+=================
+S_Update
+=================
+*/
+void S_Update( void )
+{
+	if( si.Update ) {
+		si.Update( );
+	}
+}
+
+/*
+=================
+S_DisableSounds
+=================
+*/
+void S_DisableSounds( void )
+{
+	if( si.DisableSounds ) {
+		si.DisableSounds( );
+	}
+}
+
+/*
+=================
+S_BeginRegistration
+=================
+*/
+void S_BeginRegistration( void )
+{
+	if( si.BeginRegistration ) {
+		si.BeginRegistration( );
+	}
+}
+
+/*
+=================
+S_RegisterSound
+=================
+*/
+sfxHandle_t	S_RegisterSound( const char *sample, qboolean compressed )
+{
+	if( si.RegisterSound ) {
+		return si.RegisterSound( sample, compressed );
+	} else {
+		return 0;
+	}
+}
+
+/*
+=================
+S_ClearSoundBuffer
+=================
+*/
+void S_ClearSoundBuffer( void )
+{
+	if( si.ClearSoundBuffer ) {
+		si.ClearSoundBuffer( );
+	}
+}
+
+/*
+=================
+S_SoundInfo
+=================
+*/
+void S_SoundInfo( void )
+{
+	if( si.SoundInfo ) {
+		si.SoundInfo( );
+	}
+}
+
+/*
+=================
+S_SoundList
+=================
+*/
+void S_SoundList( void )
+{
+	if( si.SoundList ) {
+		si.SoundList( );
+	}
+}
+
+//=============================================================================
+
+/*
+=================
+S_Play_f
+=================
+*/
+void S_Play_f( void ) {
+	int 		i;
+	sfxHandle_t	h;
+	char		name[256];
+
+	if( !si.RegisterSound || !si.StartLocalSound ) {
+		return;
+	}
+
+	i = 1;
+	while ( i<Cmd_Argc() ) {
+		if ( !Q_strrchr(Cmd_Argv(i), '.') ) {
+			Com_sprintf( name, sizeof(name), "%s.wav", Cmd_Argv(1) );
+		} else {
+			Q_strncpyz( name, Cmd_Argv(i), sizeof(name) );
+		}
+		h = si.RegisterSound( name, qfalse );
+		if( h ) {
+			si.StartLocalSound( h, CHAN_LOCAL_SOUND );
+		}
+		i++;
+	}
+}
+
+/*
+=================
+S_Music_f
+=================
+*/
+void S_Music_f( void ) {
+	int		c;
+
+	if( !si.StartBackgroundTrack ) {
+		return;
+	}
+
+	c = Cmd_Argc();
+
+	if ( c == 2 ) {
+		si.StartBackgroundTrack( Cmd_Argv(1), NULL );
+	} else if ( c == 3 ) {
+		si.StartBackgroundTrack( Cmd_Argv(1), Cmd_Argv(2) );
+	} else {
+		Com_Printf ("music <musicfile> [loopfile]\n");
+		return;
+	}
+
+}
+
+//=============================================================================
+
+/*
+=================
+S_Init
+=================
+*/
+void S_Init( void )
+{
+	cvar_t		*cv;
+	qboolean	started = qfalse;
+
+	Com_Printf( "------ Initializing Sound ------\n" );
+
+	s_volume = Cvar_Get( "s_volume", "0.8", CVAR_ARCHIVE );
+	s_musicVolume = Cvar_Get( "s_musicvolume", "0.25", CVAR_ARCHIVE );
+	s_doppler = Cvar_Get( "s_doppler", "1", CVAR_ARCHIVE );
+
+	cv = Cvar_Get( "s_initsound", "1", 0 );
+	if( !cv->integer ) {
+		Com_Printf( "Sound disabled.\n" );
+	} else {
+
+		S_CodecInit( );
+
+		Cmd_AddCommand( "play", S_Play_f );
+		Cmd_AddCommand( "music", S_Music_f );
+		Cmd_AddCommand( "s_list", S_SoundList );
+		Cmd_AddCommand( "s_stop", S_StopAllSounds );
+		Cmd_AddCommand( "s_info", S_SoundInfo );
+
+		cv = Cvar_Get( "s_useOpenAL", "1", CVAR_ARCHIVE );
+		if( cv->integer ) {
+			//OpenAL
+			started = S_AL_Init( &si );
+		}
+
+		if( !started ) {
+			started = S_Base_Init( &si );
+		}
+
+		if( started ) {
+			if( !S_ValidSoundInterface( &si ) ) {
+				Com_Error( ERR_FATAL, "Sound interface invalid." );
+			}
+
+			S_SoundInfo( );
+			Com_Printf( "Sound intialization successful.\n" );
+		} else {
+			Com_Printf( "Sound intialization failed.\n" );
+		}
+	}
+
+	Com_Printf( "--------------------------------\n");
+}
+
+/*
+=================
+S_Shutdown
+=================
+*/
+void S_Shutdown( void )
+{
+	if( si.Shutdown ) {
+		si.Shutdown( );
+	}
+
+	Com_Memset( &si, 0, sizeof( soundInterface_t ) );
+
+	Cmd_RemoveCommand( "play" );
+	Cmd_RemoveCommand( "music");
+	Cmd_RemoveCommand( "s_list" );
+	Cmd_RemoveCommand( "s_stop" );
+	Cmd_RemoveCommand( "s_info" );
+
+	S_CodecShutdown( );
+}
+

Modified: trunk/code/client/snd_mem.c
===================================================================
--- trunk/code/client/snd_mem.c	2005-11-13 18:33:28 UTC (rev 342)
+++ trunk/code/client/snd_mem.c	2005-11-13 18:58:14 UTC (rev 343)
@@ -30,6 +30,7 @@
  *****************************************************************************/
 
 #include "snd_local.h"
+#include "snd_codec.h"
 
 #define DEF_COMSOUNDMEGS "8"
 
@@ -100,137 +101,6 @@
 }
 
 /*
-===============================================================================
-
-WAV loading
-
-===============================================================================
-*/
-
-static	byte	*data_p;
-static	byte 	*iff_end;
-static	byte 	*last_chunk;
-static	byte 	*iff_data;
-static	int 	iff_chunk_len;
-
-static short GetLittleShort(void)
-{
-	short val = 0;
-	val = *data_p;
-	val = val + (*(data_p+1)<<8);
-	data_p += 2;
-	return val;
-}
-
-static int GetLittleLong(void)
-{
-	int val = 0;
-	val = *data_p;
-	val = val + (*(data_p+1)<<8);
-	val = val + (*(data_p+2)<<16);
-	val = val + (*(data_p+3)<<24);
-	data_p += 4;
-	return val;
-}
-
-static void FindNextChunk(char *name)
-{
-	while (1)
-	{
-		data_p=last_chunk;
-
-		if (data_p >= iff_end)
-		{	// didn't find the chunk
-			data_p = NULL;
-			return;
-		}
-		
-		data_p += 4;
-		iff_chunk_len = GetLittleLong();
-		if (iff_chunk_len < 0)
-		{
-			data_p = NULL;
-			return;
-		}
-		data_p -= 8;
-		last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
-		if (!strncmp((char *)data_p, name, 4))
-			return;
-	}
-}
-
-static void FindChunk(char *name)
-{
-	last_chunk = iff_data;
-	FindNextChunk (name);
-}
-
-/*
-============
-GetWavinfo
-============
-*/
-static wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
-{
-	wavinfo_t	info;
-
-	Com_Memset (&info, 0, sizeof(info));
-
-	if (!wav)
-		return info;
-		
-	iff_data = wav;
-	iff_end = wav + wavlength;
-
-// find "RIFF" chunk
-	FindChunk("RIFF");
-	if (!(data_p && !strncmp((char *)data_p+8, "WAVE", 4)))
-	{
-		Com_Printf("Missing RIFF/WAVE chunks\n");
-		return info;
-	}
-
-// get "fmt " chunk
-	iff_data = data_p + 12;
-// DumpChunks ();
-
-	FindChunk("fmt ");
-	if (!data_p)
-	{
-		Com_Printf("Missing fmt chunk\n");
-		return info;
-	}
-	data_p += 8;
-	info.format = GetLittleShort();
-	info.channels = GetLittleShort();
-	info.rate = GetLittleLong();
-	data_p += 4+2;
-	info.width = GetLittleShort() / 8;
-
-	if (info.format != 1)
-	{
-		Com_Printf("Microsoft PCM format only\n");
-		return info;
-	}
-
-
-// find data chunk
-	FindChunk("data");
-	if (!data_p)
-	{
-		Com_Printf("Missing data chunk\n");
-		return info;
-	}
-
-	data_p += 4;
-	info.samples = GetLittleLong () / info.width;
-	info.dataofs = data_p - wav;
-
-	return info;
-}
-
-
-/*
 ================
 ResampleSfx
 
@@ -315,7 +185,6 @@
 	return outcount;
 }
 
-
 //=============================================================================
 
 /*
@@ -330,8 +199,8 @@
 {
 	byte	*data;
 	short	*samples;
-	wavinfo_t	info;
-	int		size;
+	snd_info_t	info;
+//	int		size;
 
 	// player specific sounds are never directly loaded
 	if ( sfx->soundName[0] == '*') {
@@ -339,18 +208,10 @@
 	}
 
 	// load it in
-	size = FS_ReadFile( sfx->soundName, (void **)&data );
-	if ( !data ) {
+	data = S_CodecLoad(sfx->soundName, &info);
+	if(!data)
 		return qfalse;
-	}
 
-	info = GetWavinfo( sfx->soundName, data, size );
-	if ( info.channels != 1 ) {
-		Com_Printf ("%s is a stereo wav file\n", sfx->soundName);
-		FS_FreeFile (data);
-		return qfalse;
-	}
-
 	if ( info.width == 1 ) {
 		Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit wav file\n", sfx->soundName);
 	}
@@ -372,7 +233,7 @@
 	if( sfx->soundCompressed == qtrue) {
 		sfx->soundCompressionMethod = 1;
 		sfx->soundData = NULL;
-		sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
+		sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, data + info.dataofs );
 		S_AdpcmEncodeSound(sfx, samples);
 #if 0
 	} else if (info.samples>(SND_CHUNK_SIZE*16) && info.width >1) {
@@ -394,7 +255,7 @@
 	}
 	
 	Hunk_FreeTempMemory(samples);
-	FS_FreeFile( data );
+	Z_Free(data);
 
 	return qtrue;
 }

Added: trunk/code/client/snd_openal.c
===================================================================
--- trunk/code/client/snd_openal.c	2005-11-13 18:33:28 UTC (rev 342)
+++ trunk/code/client/snd_openal.c	2005-11-13 18:58:14 UTC (rev 343)
@@ -0,0 +1,1567 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2005 Stuart Dalton (badcdev at gmail.com)
+
+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
+===========================================================================
+*/
+
+#include "snd_local.h"
+#include "snd_codec.h"
+#include "client.h"
+
+#if USE_OPENAL
+
+#include "qal.h"
+
+// Console variables specific to OpenAL
+cvar_t *s_alPrecache;
+cvar_t *s_alGain;
+cvar_t *s_alSources;
+cvar_t *s_alDopplerFactor;
+cvar_t *s_alDopplerSpeed;
+cvar_t *s_alMinDistance;
+cvar_t *s_alRolloff;
+cvar_t *s_alDriver;
+
+/*
+=================
+S_AL_Format
+=================
+*/
+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;
+}
+
+/*
+=================
+S_AL_ErrorMsg
+=================
+*/
+char *S_AL_ErrorMsg(ALenum error)
+{
+	switch(error)
+	{
+		case AL_NO_ERROR:
+			return "No error";
+		case AL_INVALID_NAME:
+			return "Invalid name";
+		case AL_INVALID_ENUM:
+			return "Invalid enumerator";
+		case AL_INVALID_VALUE:
+			return "Invalid value";
+		case AL_INVALID_OPERATION:
+			return "Invalid operation";
+		case AL_OUT_OF_MEMORY:
+			return "Out of memory";
+		default:
+			return "Unknown error";
+	}
+}
+
+
+//===========================================================================
+
+
+typedef struct alSfx_s
+{
+	char						filename[MAX_QPATH];
+	ALuint					buffer;		// OpenAL buffer
+	qboolean				isDefault;	// Couldn't be loaded - use default FX
+	qboolean				inMemory;	// Sound is stored in memory
+	qboolean				isLocked;	// Sound is locked (can not be unloaded)
+	int							used;		// Time last used
+	struct alSfx_t	*next;		// Next entry in hash list
+} alSfx_t;
+
+static qboolean alBuffersInitialised = qfalse;
+
+// Sound effect storage, data structures
+#define MAX_SFX 4096
+static alSfx_t knownSfx[MAX_SFX];
+static int numSfx;
+
+static sfxHandle_t default_sfx;
+
+/*
+=================
+S_AL_BufferFindFree
+
+Find a free handle
+=================
+*/
+static sfxHandle_t S_AL_BufferFindFree( void )
+{
+	int i;
+
+	for(i = 0; i < MAX_SFX; i++)
+	{
+		// Got one
+		if(knownSfx[i].filename[0] == '\0')
+			return i;
+	}
+
+	// Shit...
+	Com_Error(ERR_FATAL, "S_AL_BufferFindFree: No free sound handles");
+	return -1;
+}
+
+/*
+=================
+S_AL_BufferFind
+
+Find a sound effect if loaded, set up a handle otherwise
+=================
+*/
+static sfxHandle_t S_AL_BufferFind(const char *filename)
+{
+	// Look it up in the hash table
+	sfxHandle_t sfx = -1;
+	int i;
+
+	for(i = 0; i < MAX_SFX; i++)
+	{
+		if(!Q_stricmp(knownSfx[i].filename, filename))
+		{
+			sfx = i;
+			break;
+		}
+	}
+
+	// Not found in hash table?
+	if(sfx == -1)
+	{
+		alSfx_t *ptr;
+
+		sfx = S_AL_BufferFindFree();
+
+		// Clear and copy the filename over
+		ptr = &knownSfx[sfx];
+		memset(ptr, 0, sizeof(*ptr));
+		strcpy(ptr->filename, filename);
+	}
+
+	// Return the handle
+	return sfx;
+}
+
+/*
+=================
+S_AL_BufferUseDefault
+=================
+*/
+static void S_AL_BufferUseDefault(sfxHandle_t sfx)
+{
+	if(sfx == default_sfx)
+		Com_Error(ERR_FATAL, "Can't load default sound effect %s\n", knownSfx[sfx].filename);
+
+	Com_Printf( "Warning: Using default sound for %s\n", knownSfx[sfx].filename);
+	knownSfx[sfx].isDefault = qtrue;
+	knownSfx[sfx].buffer = knownSfx[default_sfx].buffer;
+}
+
+/*
+=================
+S_AL_BufferEvict
+	
+Doesn't work yet, so if OpenAL reports that you're out of memory, you'll just
+get "Catastrophic sound memory exhaustion". Whoops.
+=================
+*/
+static qboolean S_AL_BufferEvict( void )
+{
+	return qfalse;
+}
+
+/*
+=================
+S_AL_BufferLoad
+=================
+*/
+static void S_AL_BufferLoad(sfxHandle_t sfx)
+{
+	ALenum error;
+
+	void *data;
+	snd_info_t info;
+	ALuint format;
+
+	// Nothing?
+	if(knownSfx[sfx].filename[0] == '\0')
+		return;
+
+	// Player SFX
+	if(knownSfx[sfx].filename[0] == '*')
+		return;
+
+	// Already done?
+	if((knownSfx[sfx].inMemory) || (knownSfx[sfx].isDefault))
+		return;
+
+	// Try to load
+	data = S_CodecLoad(knownSfx[sfx].filename, &info);
+	if(!data)
+	{
+		Com_Printf( "Can't load %s\n", knownSfx[sfx].filename);
+		S_AL_BufferUseDefault(sfx);
+		return;
+	}
+
+	format = S_AL_Format(info.width, info.channels);
+
+	// Create a buffer
+	qalGenBuffers(1, &knownSfx[sfx].buffer);
+	if((error = qalGetError()) != AL_NO_ERROR)
+	{
+		S_AL_BufferUseDefault(sfx);
+		Z_Free(data);
+		Com_Printf( "Can't create a sound buffer for %s - %s\n", knownSfx[sfx].filename, S_AL_ErrorMsg(error));
+		return;
+	}
+
+	// Fill the buffer
+	qalGetError();
+	qalBufferData(knownSfx[sfx].buffer, format, data, info.size, info.rate);
+	error = qalGetError();
+
+	// If we ran out of memory, start evicting the least recently used sounds
+	while(error == AL_OUT_OF_MEMORY)
+	{
+		qboolean rv = S_AL_BufferEvict();
+		if(!rv)
+		{
+			S_AL_BufferUseDefault(sfx);
+			Z_Free(data);
+			Com_Printf( "Out of memory loading %s\n", knownSfx[sfx].filename);
+			return;
+		}
+
+		// Try load it again
+		qalGetError();
+		qalBufferData(knownSfx[sfx].buffer, format, data, info.size, info.rate);
+		error = qalGetError();
+	}
+
+	// Some other error condition
+	if(error != AL_NO_ERROR)
+	{
+		S_AL_BufferUseDefault(sfx);
+		Z_Free(data);
+		Com_Printf( "Can't fill sound buffer for %s - %s", knownSfx[sfx].filename, S_AL_ErrorMsg(error));
+		return;
+	}
+
+	// Free the memory
+	Z_Free(data);
+
+	// Woo!
+	knownSfx[sfx].inMemory = qtrue;
+}
+
+/*
+=================
+S_AL_BufferUse
+=================
+*/
+void S_AL_BufferUse(sfxHandle_t sfx)
+{
+	if(knownSfx[sfx].filename[0] == '\0')
+		return;
+
+	if((!knownSfx[sfx].inMemory) && (!knownSfx[sfx].isDefault))
+		S_AL_BufferLoad(sfx);
+	knownSfx[sfx].used = Com_Milliseconds();
+}
+
+/*
+=================
+S_AL_BufferInit
+=================
+*/
+qboolean S_AL_BufferInit( void )
+{
+	if(alBuffersInitialised)
+		return qtrue;
+
+	// Clear the hash table, and SFX table
+	memset(knownSfx, 0, sizeof(knownSfx));
+	numSfx = 0;
+
+	// Load the default sound, and lock it
+	default_sfx = S_AL_BufferFind("sound/feedback/hit.wav");
+	S_AL_BufferUse(default_sfx);
+	knownSfx[default_sfx].isLocked = qtrue;
+
+	// All done
+	alBuffersInitialised = qtrue;
+	return qtrue;
+}
+
+/*
+=================
+S_AL_BufferUnload
+=================
+*/
+static void S_AL_BufferUnload(sfxHandle_t sfx)
+{
+	ALenum error;
+
+	if(knownSfx[sfx].filename[0] == '\0')
+		return;
+
+	if(!knownSfx[sfx].inMemory)
+		return;
+
+	// Delete it
+	qalDeleteBuffers(1, &knownSfx[sfx].buffer);
+	if((error = qalGetError()) != AL_NO_ERROR)
+		Com_Printf( "Can't delete sound buffer for %s", knownSfx[sfx].filename);
+
+	knownSfx[sfx].inMemory = qfalse;
+}
+
+/*
+=================
+S_AL_BufferShutdown
+=================
+*/
+void S_AL_BufferShutdown( void )
+{
+	int i;
+
+	if(!alBuffersInitialised)
+		return;
+
+	// Unlock the default sound effect
+	knownSfx[default_sfx].isLocked = qfalse;
+
+	// Free all used effects
+	for(i = 0; i < MAX_SFX; i++)
+		S_AL_BufferUnload(i);
+
+	// Clear the tables
+	memset(knownSfx, 0, sizeof(knownSfx));
+
+	// All undone
+	alBuffersInitialised = qfalse;
+}
+
+/*
+=================
+S_AL_RegisterSound
+=================
+*/
+sfxHandle_t S_AL_RegisterSound( const char *sample, qboolean compressed )
+{
+	sfxHandle_t sfx = S_AL_BufferFind(sample);
+
+	if((s_alPrecache->integer == 1) && (!knownSfx[sfx].inMemory) && (!knownSfx[sfx].isDefault))
+		S_AL_BufferLoad(sfx);
+	knownSfx[sfx].used = Com_Milliseconds();
+
+	return sfx;
+}
+
+/*
+=================
+S_AL_BufferGet
+
+Return's an sfx's buffer
+=================
+*/
+ALuint S_AL_BufferGet(sfxHandle_t sfx)
+{
+	return knownSfx[sfx].buffer;
+}
+
+
+//===========================================================================
+
+
+typedef struct src_s
+{
+	ALuint					source;			// OpenAL source object
+	sfxHandle_t 		sfx;				// Sound effect in use
+
+	int							lastUse;		// Last time used
+	alSrcPriority_t	priority;		// Priority
+	int							entity;			// Owning entity (-1 if none)
+	int							channel;		// Associated channel (-1 if none)
+
+	int							isActive;		// Is this source currently in use?
+	int							isLocked;		// This is locked (un-allocatable)
+	int							isLooping;	// Is this a looping effect (attached to an entity)
+	int							isTracking;	// Is this object tracking it's owner
+
+	qboolean				local;			// Is this local (relative to the cam)
+} src_t;
+
+#define MAX_SRC 128
+static src_t srcList[MAX_SRC];
+static int srcCount = 0;
+static qboolean alSourcesInitialised = qfalse;
+
+static int ambientCount = 0;
+
+typedef struct sentity_s
+{
+	vec3_t origin;		// Object position
+
+	int has_sfx;		// Associated sound source
+	int sfx;
+	int touched;		// Sound present this update?
+} sentity_t;
+
+static sentity_t entityList[MAX_GENTITIES];
+
+/*
+=================
+S_AL_SrcInit
+=================
+*/
+qboolean S_AL_SrcInit( void )
+{
+	int i;
+	int limit;
+	ALenum error;
+
+	// Clear the sources data structure
+	memset(srcList, 0, sizeof(srcList));
+	srcCount = 0;
+
+	// Cap s_sources to MAX_SRC
+	limit = s_alSources->integer;
+	if(limit > MAX_SRC)
+		limit = MAX_SRC;
+	else if(limit < 16)
+		limit = 16;
+
+	// Allocate as many sources as possible
+	for(i = 0; i < limit; i++)
+	{
+		qalGenSources(1, &srcList[i].source);
+		if((error = qalGetError()) != AL_NO_ERROR)
+			break;
+		srcCount++;
+	}
+
+	// All done. Print this for informational purposes
+	Com_Printf( "Allocated %d sources.\n", srcCount);
+	alSourcesInitialised = qtrue;
+	return qtrue;
+}
+
+/*
+=================
+S_AL_SrcShutdown
+=================
+*/
+void S_AL_SrcShutdown( void )
+{
+	int i;
+
+	if(!alSourcesInitialised)
+		return;
+
+	// Destroy all the sources
+	for(i = 0; i < srcCount; i++)
+	{
+		if(srcList[i].isLocked)
+			Com_DPrintf("Warning: Source %d is locked\n", i);
+
+		qalSourceStop(srcList[i].source);
+		qalDeleteSources(1, &srcList[i].source);
+	}
+
+	memset(srcList, 0, sizeof(srcList));
+
+	alSourcesInitialised = qfalse;
+}
+
+/*
+=================
+S_AL_SrcSetup
+=================
+*/
+static void S_AL_SrcSetup(srcHandle_t src, sfxHandle_t sfx, alSrcPriority_t priority,
+		int entity, int channel, qboolean local)
+{
+	ALuint buffer;
+	float null_vector[] = {0, 0, 0};
+
+	// Mark the SFX as used, and grab the raw AL buffer
+	S_AL_BufferUse(sfx);
+	buffer = S_AL_BufferGet(sfx);
+
+	// Set up src struct
+	srcList[src].lastUse = Sys_Milliseconds();
+	srcList[src].sfx = sfx;
+	srcList[src].priority = priority;
+	srcList[src].entity = entity;
+	srcList[src].channel = channel;
+	srcList[src].isActive = qtrue;
+	srcList[src].isLocked = qfalse;
+	srcList[src].isLooping = qfalse;
+	srcList[src].isTracking = qfalse;
+	srcList[src].local = local;
+
+	// Set up OpenAL source
+	qalSourcei(srcList[src].source, AL_BUFFER, buffer);
+	qalSourcef(srcList[src].source, AL_PITCH, 1.0f);
+	qalSourcef(srcList[src].source, AL_GAIN, s_alGain->value * s_volume->value);
+	qalSourcefv(srcList[src].source, AL_POSITION, null_vector);
+	qalSourcefv(srcList[src].source, AL_VELOCITY, null_vector);
+	qalSourcei(srcList[src].source, AL_LOOPING, AL_FALSE);
+	qalSourcef(srcList[src].source, AL_REFERENCE_DISTANCE, s_alMinDistance->value);
+
+	if(local)
+	{
+		qalSourcei(srcList[src].source, AL_SOURCE_RELATIVE, AL_TRUE);
+		qalSourcef(srcList[src].source, AL_ROLLOFF_FACTOR, 0);
+	}
+	else
+	{
+		qalSourcei(srcList[src].source, AL_SOURCE_RELATIVE, AL_FALSE);
+		qalSourcef(srcList[src].source, AL_ROLLOFF_FACTOR, s_alRolloff->value);
+	}
+}
+
+/*
+=================
+S_AL_SrcKill
+=================
+*/
+static void S_AL_SrcKill(srcHandle_t src)
+{
+	// I'm not touching it. Unlock it first.
+	if(srcList[src].isLocked)
+		return;
+
+	// Stop it if it's playing
+	if(srcList[src].isActive)
+		qalSourceStop(srcList[src].source);
+
+	// Remove the entity association
+	if((srcList[src].isLooping) && (srcList[src].entity != -1))
+	{
+		int ent = srcList[src].entity;
+		entityList[ent].has_sfx = 0;
+		entityList[ent].sfx = -1;
+		entityList[ent].touched = qfalse;
+	}
+
+	// Remove the buffer
+	qalSourcei(srcList[src].source, AL_BUFFER, 0);
+
+	srcList[src].sfx = 0;
+	srcList[src].lastUse = 0;
+	srcList[src].priority = 0;
+	srcList[src].entity = -1;
+	srcList[src].channel = -1;
+	srcList[src].isActive = qfalse;
+	srcList[src].isLocked = qfalse;
+	srcList[src].isLooping = qfalse;
+	srcList[src].isTracking = qfalse;
+}
+
+/*
+=================
+S_AL_SrcAlloc
+=================
+*/
+srcHandle_t S_AL_SrcAlloc( alSrcPriority_t priority, int entnum, int channel )
+{
+	int i;
+	int empty = -1;
+	int weakest = -1;
+	int weakest_time = Sys_Milliseconds();
+	int weakest_pri = 999;
+
+	for(i = 0; i < srcCount; i++)
+	{
+		// If it's locked, we aren't even going to look at it
+		if(srcList[i].isLocked)
+			continue;
+
+		// Is it empty or not?
+		if((!srcList[i].isActive) && (empty == -1))
+			empty = i;
+		else if(srcList[i].priority < priority)
+		{
+			// If it's older or has lower priority, flag it as weak
+			if((srcList[i].priority < weakest_pri) ||
+				(srcList[i].lastUse < weakest_time))
+			{
+				weakest_pri = srcList[i].priority;
+				weakest_time = srcList[i].lastUse;
+				weakest = i;
+			}
+		}
+
+		// Is it an exact match, and not on channel 0?
+		if((srcList[i].entity == entnum) && (srcList[i].channel == channel) && (channel != 0))
+		{
+			S_AL_SrcKill(i);
+			return i;
+		}
+	}
+
+	// Do we have an empty one?
+	if(empty != -1)
+		return empty;
+
+	// No. How about an overridable one?
+	if(weakest != -1)
+	{
+		S_AL_SrcKill(weakest);
+		return weakest;
+	}
+
+	// Nothing. Return failure (cries...)
+	return -1;
+}
+
+/*
+=================
+S_AL_SrcFind
+
+Finds an active source with matching entity and channel numbers
+Returns -1 if there isn't one
+=================
+*/
+srcHandle_t S_AL_SrcFind(int entnum, int channel)
+{
+	int i;
+	for(i = 0; i < srcCount; i++)
+	{
+		if(!srcList[i].isActive)
+			continue;
+		if((srcList[i].entity == entnum) && (srcList[i].channel == channel))
+			return i;
+	}
+	return -1;
+}
+
+/*
+=================
+S_AL_SrcLock
+
+Locked sources will not be automatically reallocated or managed
+=================
+*/
+void S_AL_SrcLock(srcHandle_t src)
+{
+	srcList[src].isLocked = qtrue;
+}
+
+/*
+=================
+S_AL_SrcUnlock
+
+Once unlocked, the source may be reallocated again
+=================
+*/
+void S_AL_SrcUnlock(srcHandle_t src)
+{
+	srcList[src].isLocked = qfalse;
+}
+
+/*
+=================
+S_AL_UpdateEntityPosition
+=================
+*/
+void S_AL_UpdateEntityPosition( int entityNum, const vec3_t origin )
+{
+	if ( entityNum < 0 || entityNum > MAX_GENTITIES )
+		Com_Error( ERR_DROP, "S_UpdateEntityPosition: bad entitynum %i", entityNum );
+	VectorCopy( origin, entityList[entityNum].origin );
+}
+
+/*
+=================
+S_AL_StartLocalSound
+
+Play a local (non-spatialized) sound effect
+=================
+*/
+void S_AL_StartLocalSound(sfxHandle_t sfx, int channel)
+{
+	// Try to grab a source
+	srcHandle_t src = S_AL_SrcAlloc(SRCPRI_LOCAL, -1, channel);
+	if(src == -1)
+		return;
+
+	// Set up the effect
+	S_AL_SrcSetup(src, sfx, SRCPRI_LOCAL, -1, channel, qtrue);
+
+	// Start it playing
+	qalSourcePlay(srcList[src].source);
+}
+
+#define POSITION_SCALE 1.0f
+
+/*
+=================
+S_AL_StartSound
+
+Play a one-shot sound effect
+=================
+*/
+void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx )
+{
+	vec3_t sorigin;
+
+	// Try to grab a source
+	srcHandle_t src = S_AL_SrcAlloc(SRCPRI_ONESHOT, entnum, entchannel);
+	if(src == -1)
+		return;
+
+	// Set up the effect
+	S_AL_SrcSetup(src, sfx, SRCPRI_ONESHOT, entnum, entchannel, qfalse);
+
+	if(origin == NULL)
+	{
+		srcList[src].isTracking = qtrue;
+		VectorScale(entityList[entnum].origin, POSITION_SCALE, sorigin);
+	}
+	else
+		VectorScale(origin, POSITION_SCALE, sorigin);
+	qalSourcefv(srcList[src].source, AL_POSITION, sorigin);
+
+	// Start it playing
+	qalSourcePlay(srcList[src].source);
+}
+
+/*
+=================
+S_AL_ClearLoopingSounds
+=================
+*/
+void S_AL_ClearLoopingSounds( qboolean killall )
+{
+	int i;
+	for(i = 0; i < srcCount; i++)
+	{
+		if((srcList[i].isLooping) && (srcList[i].entity != -1))
+			entityList[srcList[i].entity].touched = qfalse;
+	}
+}
+
+/*
+=================
+S_AL_SrcLoop
+=================
+*/
+static void S_AL_SrcLoop( alSrcPriority_t priority, sfxHandle_t sfx,
+		const vec3_t origin, const vec3_t velocity, int entnum)
+{
+	int src;
+	qboolean need_to_play = qfalse;
+	vec3_t sorigin;
+
+	// Do we need to start a new sound playing?
+	if(!entityList[entnum].has_sfx)
+	{
+		// Try to get a channel
+		ambientCount++;
+		src = S_AL_SrcAlloc(priority, entnum, -1);
+		if(src == -1)
+			return;
+		need_to_play = qtrue;
+	}
+	else if(srcList[entityList[entnum].sfx].sfx != sfx)
+	{
+		// Need to restart. Just re-use this channel
+		src = entityList[entnum].sfx;
+		S_AL_SrcKill(src);
+		need_to_play = qtrue;
+	}
+	else
+		src = entityList[entnum].sfx;
+
+	if(need_to_play)
+	{
+		// Set up the effect
+		S_AL_SrcSetup(src, sfx, priority, entnum, -1, qfalse);
+		qalSourcei(srcList[src].source, AL_LOOPING, AL_TRUE);
+		srcList[src].isLooping = qtrue;
+
+		// Set up the entity
+		entityList[entnum].has_sfx = qtrue;
+		entityList[entnum].sfx = src;
+		need_to_play = qtrue;
+	}
+
+	// Set up the position and velocity
+	VectorScale(entityList[entnum].origin, POSITION_SCALE, sorigin);
+	qalSourcefv(srcList[src].source, AL_POSITION, sorigin);
+	qalSourcefv(srcList[src].source, AL_VELOCITY, velocity);
+
+	// Flag it
+	entityList[entnum].touched = qtrue;
+
+	// Play if need be
+	if(need_to_play)
+		qalSourcePlay(srcList[src].source);
+}
+
+/*
+=================
+S_AL_AddLoopingSound
+=================
+*/
+void S_AL_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx )
+{
+	S_AL_SrcLoop(SRCPRI_AMBIENT, sfx, origin, velocity, entityNum);
+}
+
+/*
+=================
+S_AL_AddRealLoopingSound
+=================
+*/
+void S_AL_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx )
+{
+	S_AL_SrcLoop(SRCPRI_ENTITY, sfx, origin, velocity, entityNum);
+}
+
+/*
+=================
+S_AL_StopLoopingSound
+=================
+*/
+void S_AL_StopLoopingSound(int entityNum )
+{
+	if(entityList[entityNum].has_sfx)
+		S_AL_SrcKill(entityList[entityNum].sfx);
+}
+
+/*
+=================
+S_AL_SrcUpdate
+
+Update state (move things around, manage sources, and so on)
+=================
+*/
+void S_AL_SrcUpdate( void )
+{
+	int i;
+	int ent;
+	ALint state;
+
+	for(i = 0; i < srcCount; i++)
+	{
+		if(srcList[i].isLocked)
+			continue;
+
+		if(!srcList[i].isActive)
+			continue;
+
+		// Check if it's done, and flag it
+		qalGetSourcei(srcList[i].source, AL_SOURCE_STATE, &state);
+		if(state == AL_STOPPED)
+		{
+			S_AL_SrcKill(i);
+			continue;
+		}
+
+		// Update source parameters
+		if((s_alGain->modified)||(s_volume->modified))
+			qalSourcef(srcList[i].source, AL_GAIN, s_alGain->value * s_volume->value);
+		if((s_alRolloff->modified)&&(!srcList[i].local))
+			qalSourcef(srcList[i].source, AL_ROLLOFF_FACTOR, s_alRolloff->value);
+		if(s_alMinDistance->modified)
+			qalSourcef(srcList[i].source, AL_REFERENCE_DISTANCE, s_alMinDistance->value);
+
+		ent = srcList[i].entity;
+
+		// If a looping effect hasn't been touched this frame, kill it
+		if(srcList[i].isLooping)
+		{
+			if(!entityList[ent].touched)
+			{
+				ambientCount--;
+				S_AL_SrcKill(i);
+			}
+			continue;
+		}
+
+		// See if it needs to be moved
+		if(srcList[i].isTracking)
+		{
+			vec3_t sorigin;
+			VectorScale(entityList[ent].origin, POSITION_SCALE, sorigin);
+			qalSourcefv(srcList[i].source, AL_POSITION, entityList[ent].origin);
+		}
+	}
+}
+
+/*
+=================
+S_AL_SrcShutup
+=================
+*/
+void S_AL_SrcShutup( void )
+{
+	int i;
+	for(i = 0; i < srcCount; i++)
+		S_AL_SrcKill(i);
+}
+
+/*
+=================
+S_AL_SrcGet
+=================
+*/
+ALuint S_AL_SrcGet(srcHandle_t src)
+{
+	return srcList[src].source;
+}
+
+
+//===========================================================================
+
+
+static srcHandle_t streamSourceHandle = -1;
+static qboolean streamPlaying = qfalse;
+static ALuint streamSource;
+
+/*
+=================
+S_AL_AllocateStreamChannel
+=================
+*/
+static void S_AL_AllocateStreamChannel( void )
+{
+	// Allocate a streamSource at high priority
+	streamSourceHandle = S_AL_SrcAlloc(SRCPRI_STREAM, -2, 0);
+	if(streamSourceHandle == -1)
+		return;
+
+	// Lock the streamSource so nobody else can use it, and get the raw streamSource
+	S_AL_SrcLock(streamSourceHandle);
+	streamSource = S_AL_SrcGet(streamSourceHandle);
+
+	// Set some streamSource parameters
+	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      );
+}
+
+/*
+=================
+S_AL_FreeStreamChannel
+=================
+*/
+static void S_AL_FreeStreamChannel( void )
+{
+	// Release the output streamSource
+	S_AL_SrcUnlock(streamSourceHandle);
+	streamSource = 0;
+	streamSourceHandle = -1;
+}
+
+/*
+=================
+S_AL_RawSamples
+=================
+*/
+void S_AL_RawSamples(int samples, int rate, int width, int channels, const byte *data, float volume)
+{
+	ALuint buffer;
+	ALuint format = AL_FORMAT_STEREO16;
+	ALint state;
+
+	// Work out AL 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;
+	}
+
+	// Create the streamSource if necessary
+	if(streamSourceHandle == -1)
+	{
+		S_AL_AllocateStreamChannel();
+	
+		// Failed?
+		if(streamSourceHandle == -1)
+		{
+			Com_Printf( "Can't allocate streaming streamSource\n");
+			return;
+		}
+	}
+
+	// Create a buffer, and stuff the data into it
+	qalGenBuffers(1, &buffer);
+	qalBufferData(buffer, format, data, (samples * width * channels), rate);
+
+	// Shove the data onto the streamSource
+	qalSourceQueueBuffers(streamSource, 1, &buffer);
+
+	// Start the streamSource playing if necessary
+	qalGetSourcei(streamSource, AL_SOURCE_STATE, &state);
+
+	// Volume
+	qalSourcef (streamSource, AL_GAIN, volume * s_volume->value * s_alGain->value);
+
+	if(!streamPlaying)
+	{
+		qalSourcePlay(streamSource);
+		streamPlaying = qtrue;
+	}
+}
+
+/*
+=================
+S_AL_StreamUpdate
+=================
+*/
+void S_AL_StreamUpdate( void )
+{
+	int processed;
+	ALint state;
+
+	if(streamSourceHandle == -1)
+		return;
+
+	// Un-queue any buffers, and delete them
+	qalGetSourcei(streamSource, AL_BUFFERS_PROCESSED, &processed);
+	if(processed)
+	{
+		while(processed--)
+		{
+			ALuint buffer;
+			qalSourceUnqueueBuffers(streamSource, 1, &buffer);
+			qalDeleteBuffers(1, &buffer);
+		}
+	}
+
+	// If it's stopped, release the streamSource
+	qalGetSourcei(streamSource, AL_SOURCE_STATE, &state);
+	if(state == AL_STOPPED)
+	{
+		streamPlaying = qfalse;
+		qalSourceStop(streamSource);
+		S_AL_FreeStreamChannel();
+	}
+}
+
+/*
+=================
+S_AL_StreamDie
+=================
+*/
+void S_AL_StreamDie( void )
+{
+	if(streamSourceHandle == -1)
+		return;
+
+	streamPlaying = qfalse;
+	qalSourceStop(streamSource);
+	S_AL_FreeStreamChannel();
+}
+
+
+//===========================================================================
+
+
+#define NUM_MUSIC_BUFFERS	4
+#define	MUSIC_BUFFER_SIZE 4096
+
+static qboolean musicPlaying = qfalse;
+static srcHandle_t musicSourceHandle = -1;
+static ALuint musicSource;
+static ALuint musicBuffers[NUM_MUSIC_BUFFERS];
+
+static snd_stream_t *mus_stream;
+static char s_backgroundLoop[MAX_QPATH];
+
+static byte decode_buffer[MUSIC_BUFFER_SIZE];
+
+/*
+=================
+S_AL_MusicSourceGet
+=================
+*/
+static void S_AL_MusicSourceGet( void )
+{
+	// Allocate a musicSource at high priority
+	musicSourceHandle = S_AL_SrcAlloc(SRCPRI_STREAM, -2, 0);
+	if(musicSourceHandle == -1)
+		return;
+
+	// Lock the musicSource so nobody else can use it, and get the raw musicSource
+	S_AL_SrcLock(musicSourceHandle);
+	musicSource = S_AL_SrcGet(musicSourceHandle);
+
+	// Set some musicSource parameters
+	qalSource3f(musicSource, AL_POSITION,        0.0, 0.0, 0.0);
+	qalSource3f(musicSource, AL_VELOCITY,        0.0, 0.0, 0.0);
+	qalSource3f(musicSource, AL_DIRECTION,       0.0, 0.0, 0.0);
+	qalSourcef (musicSource, AL_ROLLOFF_FACTOR,  0.0          );
+	qalSourcei (musicSource, AL_SOURCE_RELATIVE, AL_TRUE      );
+}
+
+/*
+=================
+S_AL_MusicSourceFree
+=================
+*/
+static void S_AL_MusicSourceFree( void )
+{
+	// Release the output musicSource
+	S_AL_SrcUnlock(musicSourceHandle);
+	musicSource = 0;
+	musicSourceHandle = -1;
+}
+
+/*
+=================
+S_AL_StopBackgroundTrack
+=================
+*/
+void S_AL_StopBackgroundTrack( void )
+{
+	if(!musicPlaying)
+		return;
+
+	// Stop playing
+	qalSourceStop(musicSource);
+
+	// De-queue the musicBuffers
+	qalSourceUnqueueBuffers(musicSource, NUM_MUSIC_BUFFERS, musicBuffers);
+
+	// Destroy the musicBuffers
+	qalDeleteBuffers(NUM_MUSIC_BUFFERS, musicBuffers);
+
+	// Free the musicSource
+	S_AL_MusicSourceFree();
+
+	// Unload the stream
+	if(mus_stream)
+		S_CodecCloseStream(mus_stream);
+	mus_stream = NULL;
+
+	musicPlaying = qfalse;
+}
+
+/*
+=================
+S_AL_MusicProcess
+=================
+*/
+void S_AL_MusicProcess(ALuint b)
+{
+	int l;
+	ALuint format;
+
+	l = S_CodecReadStream(mus_stream, MUSIC_BUFFER_SIZE, decode_buffer);
+
+	if(l == 0)
+	{
+		S_CodecCloseStream(mus_stream);
+		mus_stream = S_CodecOpenStream(s_backgroundLoop);
+		if(!mus_stream)
+		{
+			S_AL_StopBackgroundTrack();
+			return;
+		}
+
+		l = S_CodecReadStream(mus_stream, MUSIC_BUFFER_SIZE, decode_buffer);
+	}
+
+	format = S_AL_Format(mus_stream->info.width, mus_stream->info.channels);
+	qalBufferData(b, format, decode_buffer, l, mus_stream->info.rate);
+}
+
+/*
+=================
+S_AL_StartBackgroundTrack
+=================
+*/
+void S_AL_StartBackgroundTrack( const char *intro, const char *loop )
+{
+	int i;
+
+	// Stop any existing music that might be playing
+	S_AL_StopBackgroundTrack();
+
+	if ( !intro || !intro[0] ) {
+		intro = loop;
+	}
+	if ( !loop || !loop[0] ) {
+		loop = intro;
+	}
+
+	if((!intro || !intro[0]) && (!intro || !intro[0]))
+		return;
+
+	// Copy the loop over
+	strncpy( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) );
+
+	// Open the intro
+	mus_stream = S_CodecOpenStream(intro);
+
+	if(!mus_stream)
+		return;
+
+	// Allocate a musicSource
+	S_AL_MusicSourceGet();
+	if(musicSourceHandle == -1)
+		return;
+
+	// Generate the musicBuffers
+	qalGenBuffers(NUM_MUSIC_BUFFERS, musicBuffers);
+	
+	// Queue the musicBuffers up
+	for(i = 0; i < NUM_MUSIC_BUFFERS; i++)
+		S_AL_MusicProcess(musicBuffers[i]);
+	qalSourceQueueBuffers(musicSource, NUM_MUSIC_BUFFERS, musicBuffers);
+	
+	// Start playing
+	qalSourcePlay(musicSource);
+
+	musicPlaying = qtrue;
+}
+
+/*
+=================
+S_AL_MusicUpdate
+=================
+*/
+void S_AL_MusicUpdate( void )
+{
+	int processed;
+	ALint state;
+
+	if(!musicPlaying)
+		return;
+
+	qalGetSourcei(musicSource, AL_BUFFERS_PROCESSED, &processed);
+	if(processed)
+	{
+		while(processed--)
+		{
+			ALuint b;
+			qalSourceUnqueueBuffers(musicSource, 1, &b);
+			S_AL_MusicProcess(b);
+			qalSourceQueueBuffers(musicSource, 1, &b);
+		}
+	}
+
+	// If it's not still playing, give it a kick
+	qalGetSourcei(musicSource, AL_SOURCE_STATE, &state);
+	if(state == AL_STOPPED)
+	{
+		Com_DPrintf( "Restarted OpenAL music musicSource\n");
+		qalSourcePlay(musicSource);
+	}
+
+	// Set the gain property
+	qalSourcef(musicSource, AL_GAIN, s_alGain->value * s_musicVolume->value);
+}
+
+
+//===========================================================================
+
+
+// Local state variables
+static ALCdevice *alDevice;
+static ALCcontext *alContext;
+
+#ifdef _WIN32
+#define ALDRIVER_DEFAULT "OpenAL32.dll"
+#else
+#define ALDRIVER_DEFAULT "libopenal.so"
+#endif
+
+/*
+=================
+S_AL_StopAllSounds
+=================
+*/
+void S_AL_StopAllSounds( void )
+{
+	S_AL_SrcShutup();
+	S_AL_StopBackgroundTrack();
+}
+
+/*
+=================
+S_AL_Respatialize
+=================
+*/
+void S_AL_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater )
+{
+	// Axis[0] = Forward
+	// Axis[2] = Up
+	float velocity[] = {0.0f, 0.0f, 0.0f};
+	float orientation[] = {axis[0][0], axis[0][1], axis[0][2],
+		axis[2][0], axis[2][1], axis[2][2]};
+		vec3_t sorigin;
+
+	// Set OpenAL listener paramaters
+	VectorScale(origin, POSITION_SCALE, sorigin);
+	qalListenerfv(AL_POSITION, origin);
+	qalListenerfv(AL_VELOCITY, velocity);
+	qalListenerfv(AL_ORIENTATION, orientation);
+}
+
+/*
+=================
+S_AL_Update
+=================
+*/
+void S_AL_Update( void )
+{
+	// Update SFX channels
+	S_AL_SrcUpdate();
+
+	// Update streams
+	S_AL_StreamUpdate();
+	S_AL_MusicUpdate();
+
+	// Doppler
+	if(s_doppler->modified)
+	{
+		s_alDopplerFactor->modified = qtrue;
+		s_doppler->modified = qfalse;
+	}
+
+	// Doppler parameters
+	if(s_alDopplerFactor->modified)
+	{
+		if(s_doppler->integer)
+			qalDopplerFactor(s_alDopplerFactor->value);
+		else
+			qalDopplerFactor(0.0f);
+		s_alDopplerFactor->modified = qfalse;
+	}
+	if(s_alDopplerSpeed->modified)
+	{
+		qalDopplerVelocity(s_alDopplerSpeed->value);
+		s_alDopplerSpeed->modified = qfalse;
+	}
+
+	// Clear the modified flags on the other cvars
+	s_alGain->modified = qfalse;
+	s_volume->modified = qfalse;
+	s_musicVolume->modified = qfalse;
+	s_alMinDistance->modified = qfalse;
+	s_alRolloff->modified = qfalse;
+}
+
+/*
+=================
+S_AL_DisableSounds
+=================
+*/
+void S_AL_DisableSounds( void )
+{
+	S_AL_StopAllSounds();
+}
+
+/*
+=================
+S_AL_BeginRegistration
+=================
+*/
+void S_AL_BeginRegistration( void )
+{
+}
+
+/*
+=================
+S_AL_ClearSoundBuffer
+=================
+*/
+void S_AL_ClearSoundBuffer( void )
+{
+}
+
+/*
+=================
+S_AL_SoundList
+=================
+*/
+void S_AL_SoundList( void )
+{
+}
+
+/*
+=================
+S_AL_SoundInfo
+=================
+*/
+void S_AL_SoundInfo( void )
+{
+	Com_Printf( "OpenAL info:\n" );
+	Com_Printf( "  Vendor:     %s\n", qalGetString( AL_VENDOR ) );
+	Com_Printf( "  Version:    %s\n", qalGetString( AL_VERSION ) );
+	Com_Printf( "  Renderer:   %s\n", qalGetString( AL_RENDERER ) );
+	Com_Printf( "  Extensions: %s\n", qalGetString( AL_EXTENSIONS ) );
+
+}
+
+/*
+=================
+S_AL_Shutdown
+=================
+*/
+void S_AL_Shutdown( void )
+{
+	// Shut down everything
+	S_AL_StreamDie( );
+	S_AL_StopBackgroundTrack( );
+	S_AL_SrcShutdown( );
+	S_AL_BufferShutdown( );
+
+	// Check for Linux shutdown race condition
+	// FIXME: this will probably not be necessary once OpenAL CVS
+	//        from 11/11/05 is released and prevelant
+	if( Q_stricmp( qalGetString( AL_VENDOR ), "J. Valenzuela" ) ) {
+		qalcMakeContextCurrent( NULL );
+	}
+
+	qalcDestroyContext(alContext);
+	qalcCloseDevice(alDevice);
+
+	QAL_Shutdown();
+}
+
+#endif
+
+/*
+=================
+S_AL_Init
+=================
+*/
+qboolean S_AL_Init( soundInterface_t *si )
+{
+#if USE_OPENAL
+	if( !si ) {
+		return qfalse;
+	}
+
+	// New console variables
+	s_alPrecache = Cvar_Get( "s_alPrecache", "0", CVAR_ARCHIVE );
+	s_alGain = Cvar_Get( "s_alGain", "0.4", CVAR_ARCHIVE );
+	s_alSources = Cvar_Get( "s_alSources", "64", CVAR_ARCHIVE );
+	s_alDopplerFactor = Cvar_Get( "s_alDopplerFactor", "1.0", CVAR_ARCHIVE );
+	s_alDopplerSpeed = Cvar_Get( "s_alDopplerSpeed", "2200", CVAR_ARCHIVE );
+	s_alMinDistance = Cvar_Get( "s_alMinDistance", "80", CVAR_ARCHIVE );
+	s_alRolloff = Cvar_Get( "s_alRolloff", "0.25", CVAR_ARCHIVE );
+
+	s_alDriver = Cvar_Get( "s_alDriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE );
+
+	// Load QAL
+	if( !QAL_Init( s_alDriver->string ) )
+	{
+		Com_Printf(  "Failed to load library: \"%s\".\n", s_alDriver->string );
+		return qfalse;
+	}
+
+	// Open default device
+	alDevice = qalcOpenDevice( NULL );
+	if( !alDevice )
+	{
+		QAL_Shutdown( );
+		Com_Printf(  "Failed to open OpenAL device.\n" );
+		return qfalse;
+	}
+
+	// Create OpenAL context
+	alContext = qalcCreateContext( alDevice, NULL );
+	if( !alContext )
+	{
+		QAL_Shutdown( );
+		qalcCloseDevice( alDevice );
+		Com_Printf(  "Failed to create OpenAL context.\n" );
+		return qfalse;
+	}
+	qalcMakeContextCurrent( alContext );
+
+	// Initialize sources, buffers, music
+	S_AL_BufferInit( );
+	S_AL_SrcInit( );
+
+	// Set up OpenAL parameters (doppler, etc)
+	qalDopplerFactor( s_alDopplerFactor->value );
+	qalDopplerVelocity( s_alDopplerSpeed->value );
+
+	si->Shutdown = S_AL_Shutdown;
+	si->StartSound = S_AL_StartSound;
+	si->StartLocalSound = S_AL_StartLocalSound;
+	si->StartBackgroundTrack = S_AL_StartBackgroundTrack;
+	si->StopBackgroundTrack = S_AL_StopBackgroundTrack;
+	si->RawSamples = S_AL_RawSamples;
+	si->StopAllSounds = S_AL_StopAllSounds;
+	si->ClearLoopingSounds = S_AL_ClearLoopingSounds;
+	si->AddLoopingSound = S_AL_AddLoopingSound;
+	si->AddRealLoopingSound = S_AL_AddRealLoopingSound;
+	si->StopLoopingSound = S_AL_StopLoopingSound;
+	si->Respatialize = S_AL_Respatialize;
+	si->UpdateEntityPosition = S_AL_UpdateEntityPosition;
+	si->Update = S_AL_Update;
+	si->DisableSounds = S_AL_DisableSounds;
+	si->BeginRegistration = S_AL_BeginRegistration;
+	si->RegisterSound = S_AL_RegisterSound;
+	si->ClearSoundBuffer = S_AL_ClearSoundBuffer;
+	si->SoundInfo = S_AL_SoundInfo;
+	si->SoundList = S_AL_SoundList;
+
+	return qtrue;
+#else
+	return qfalse;
+#endif
+}
+

Modified: trunk/code/macosx/Quake3.pbproj/project.pbxproj
===================================================================
--- trunk/code/macosx/Quake3.pbproj/project.pbxproj	2005-11-13 18:33:28 UTC (rev 342)
+++ trunk/code/macosx/Quake3.pbproj/project.pbxproj	2005-11-13 18:58:14 UTC (rev 343)
@@ -999,6 +999,13 @@
 		};
 		012AD9A500868211C697A10E = {
 			children = (
+				92847F3509279B370056BC59,
+				92847F3609279B370056BC59,
+				92847F3709279B370056BC59,
+				92847F3809279B370056BC59,
+				92847F3909279B370056BC59,
+				92847F3A09279B370056BC59,
+				92847F3B09279B370056BC59,
 				9260378009101A6C0018EAE6,
 				012AD9A600868211C697A10E,
 				012AD9A700868211C697A10E,
@@ -6764,6 +6771,8 @@
 				9260377A09101A3B0018EAE6,
 				9260378109101A6C0018EAE6,
 				9292851809192BA800286DE9,
+				92847F3D09279B370056BC59,
+				92847F4009279B370056BC59,
 			);
 			isa = PBXHeadersBuildPhase;
 			runOnlyForDeploymentPostprocessing = 0;
@@ -6919,6 +6928,11 @@
 				4F23A81D08F4FA8F00CB90D3,
 				92603767091019D30018EAE6,
 				92603768091019D30018EAE6,
+				92847F3C09279B370056BC59,
+				92847F3E09279B370056BC59,
+				92847F3F09279B370056BC59,
+				92847F4109279B370056BC59,
+				92847F4209279B370056BC59,
 			);
 			isa = PBXSourcesBuildPhase;
 			runOnlyForDeploymentPostprocessing = 0;
@@ -7775,6 +7789,8 @@
 				9260377B09101A3B0018EAE6,
 				9260378209101A6C0018EAE6,
 				9292851909192BA800286DE9,
+				92847F4409279B370056BC59,
+				92847F4709279B370056BC59,
 			);
 			isa = PBXHeadersBuildPhase;
 			runOnlyForDeploymentPostprocessing = 0;
@@ -8260,6 +8276,11 @@
 				4F23A81508F4FA8F00CB90D3,
 				9260376B091019D30018EAE6,
 				9260376C091019D30018EAE6,
+				92847F4309279B370056BC59,
+				92847F4509279B370056BC59,
+				92847F4609279B370056BC59,
+				92847F4809279B370056BC59,
+				92847F4909279B370056BC59,
 			);
 			isa = PBXSourcesBuildPhase;
 			runOnlyForDeploymentPostprocessing = 0;
@@ -10932,6 +10953,146 @@
 			settings = {
 			};
 		};
+		92847F3509279B370056BC59 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.c.c;
+			path = qal.c;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		92847F3609279B370056BC59 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.c.h;
+			path = qal.h;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		92847F3709279B370056BC59 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.c.c;
+			path = snd_codec_wav.c;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		92847F3809279B370056BC59 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.c.c;
+			path = snd_codec.c;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		92847F3909279B370056BC59 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.c.h;
+			path = snd_codec.h;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		92847F3A09279B370056BC59 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.c.c;
+			path = snd_main.c;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		92847F3B09279B370056BC59 = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			lastKnownFileType = sourcecode.c.c;
+			path = snd_openal.c;
+			refType = 4;
+			sourceTree = "<group>";
+		};
+		92847F3C09279B370056BC59 = {
+			fileRef = 92847F3509279B370056BC59;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		92847F3D09279B370056BC59 = {
+			fileRef = 92847F3609279B370056BC59;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		92847F3E09279B370056BC59 = {
+			fileRef = 92847F3709279B370056BC59;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		92847F3F09279B370056BC59 = {
+			fileRef = 92847F3809279B370056BC59;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		92847F4009279B370056BC59 = {
+			fileRef = 92847F3909279B370056BC59;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		92847F4109279B370056BC59 = {
+			fileRef = 92847F3A09279B370056BC59;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		92847F4209279B370056BC59 = {
+			fileRef = 92847F3B09279B370056BC59;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		92847F4309279B370056BC59 = {
+			fileRef = 92847F3509279B370056BC59;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		92847F4409279B370056BC59 = {
+			fileRef = 92847F3609279B370056BC59;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		92847F4509279B370056BC59 = {
+			fileRef = 92847F3709279B370056BC59;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		92847F4609279B370056BC59 = {
+			fileRef = 92847F3809279B370056BC59;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		92847F4709279B370056BC59 = {
+			fileRef = 92847F3909279B370056BC59;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		92847F4809279B370056BC59 = {
+			fileRef = 92847F3A09279B370056BC59;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		92847F4909279B370056BC59 = {
+			fileRef = 92847F3B09279B370056BC59;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
 		9292851709192BA800286DE9 = {
 			fileEncoding = 30;
 			isa = PBXFileReference;

Modified: trunk/code/unix/Makefile
===================================================================
--- trunk/code/unix/Makefile	2005-11-13 18:33:28 UTC (rev 342)
+++ trunk/code/unix/Makefile	2005-11-13 18:58:14 UTC (rev 343)
@@ -47,6 +47,10 @@
 USE_SDL=1
 endif
 
+ifndef USE_OPENAL
+USE_OPENAL=1
+endif
+
 ifndef BUILD_CLIENT
 BUILD_CLIENT=1
 endif
@@ -115,6 +119,10 @@
 
   BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes
 
+  ifeq ($(USE_OPENAL),1)
+    BASE_CFLAGS += -DUSE_OPENAL=1
+  endif
+
   ifeq ($(USE_SDL),1)
     BASE_CFLAGS += -DUSE_SDL_VIDEO=1 -DUSE_SDL_SOUND=1 $(shell sdl-config --cflags)
     GL_CFLAGS =
@@ -214,6 +222,10 @@
 
   BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes
 
+  ifeq ($(USE_OPENAL),1)
+    BASE_CFLAGS += -DUSE_OPENAL=1
+  endif
+
   DX_CFLAGS = -I$(DXSDK_DIR)/Include
 
   GL_CFLAGS =
@@ -620,6 +632,13 @@
   $(B)/client/snd_mix.o \
   $(B)/client/snd_wavelet.o \
   \
+  $(B)/client/snd_main.o \
+  $(B)/client/snd_codec.o \
+  $(B)/client/snd_codec_wav.o \
+  \
+  $(B)/client/qal.o \
+  $(B)/client/snd_openal.o \
+  \
   $(B)/client/sv_bot.o \
   $(B)/client/sv_ccmds.o \
   $(B)/client/sv_client.o \
@@ -891,6 +910,14 @@
 $(B)/client/snd_mem.o : $(CDIR)/snd_mem.c; $(DO_CC)
 $(B)/client/snd_mix.o : $(CDIR)/snd_mix.c; $(DO_CC)
 $(B)/client/snd_wavelet.o : $(CDIR)/snd_wavelet.c; $(DO_CC)
+
+$(B)/client/snd_main.o : $(CDIR)/snd_main.c; $(DO_CC)
+$(B)/client/snd_codec.o : $(CDIR)/snd_codec.c; $(DO_CC)
+$(B)/client/snd_codec_wav.o : $(CDIR)/snd_codec_wav.c; $(DO_CC)
+
+$(B)/client/qal.o : $(CDIR)/qal.c; $(DO_CC)
+$(B)/client/snd_openal.o : $(CDIR)/snd_openal.c; $(DO_CC)
+
 $(B)/client/sv_bot.o : $(SDIR)/sv_bot.c; $(DO_CC)
 $(B)/client/sv_client.o : $(SDIR)/sv_client.c; $(DO_CC)
 $(B)/client/sv_ccmds.o : $(SDIR)/sv_ccmds.c; $(DO_CC)

Modified: trunk/code/unix/sdl_snd.c
===================================================================
--- trunk/code/unix/sdl_snd.c	2005-11-13 18:33:28 UTC (rev 342)
+++ trunk/code/unix/sdl_snd.c	2005-11-13 18:58:14 UTC (rev 343)
@@ -56,233 +56,285 @@
 #include "../qcommon/q_shared.h"
 #include "../client/snd_local.h"
 
-int snd_inited=0;
+qboolean snd_inited = qfalse;
 
-cvar_t *sndbits;
-cvar_t *sndspeed;
-cvar_t *sndchannels;
-cvar_t *snddevice;
-cvar_t *sdldevsamps;
-cvar_t *sdlmixsamps;
+cvar_t *s_sdlBits;
+cvar_t *s_sdlSpeed;
+cvar_t *s_sdlChannels;
+cvar_t *s_sdlDevSamps;
+cvar_t *s_sdlMixSamps;
 
 static qboolean use_custom_memset = qfalse;
-// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371 
+
+/*
+===============
+Snd_Memset
+
+https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
+
+<TTimo> some shitty mess with DMA buffers
+<TTimo> the mmap'ing permissions were write only
+<TTimo> and glibc optimized for mmx would do memcpy with a prefetch and a read
+<TTimo> causing segfaults
+<TTimo> some other systems would not let you mmap the DMA with read permissions
+<TTimo> so I think I ended up attempting opening with read/write, then try write only
+<TTimo> and use my own copy instead of the glibc crap
+===============
+*/
 void Snd_Memset (void* dest, const int val, const size_t count)
 {
-  int *pDest;
-  int i, iterate;
+	int *pDest;
+	int i, iterate;
 
-  if (!use_custom_memset)
-  {
-    Com_Memset(dest,val,count);
-    return;
-  }
-  iterate = count / sizeof(int);
-  pDest = (int*)dest;
-  for(i=0; i<iterate; i++)
-  {
-    pDest[i] = val;
-  }
+	if (!use_custom_memset)
+	{
+		Com_Memset(dest,val,count);
+		return;
+	}
+	iterate = count / sizeof(int);
+	pDest = (int*)dest;
+	for(i=0; i<iterate; i++)
+	{
+		pDest[i] = val;
+	}
 }
 
 /* The audio callback. All the magic happens here. */
 static int dmapos = 0;
 static int dmasize = 0;
+
+/*
+===============
+sdl_audio_callback
+===============
+*/
 static void sdl_audio_callback(void *userdata, Uint8 *stream, int len)
 {
-    int pos = (dmapos * (dma.samplebits/8));
-    if (pos >= dmasize)
-        dmapos = pos = 0;
+	int pos = (dmapos * (dma.samplebits/8));
+	if (pos >= dmasize)
+		dmapos = pos = 0;
 
-    if (!snd_inited)  /* shouldn't happen, but just in case... */
-    {
-        memset(stream, '\0', len);
-        return;
-    }
-    else
-    {
-        int tobufend = dmasize - pos;  /* bytes to buffer's end. */
-        int len1 = len;
-        int len2 = 0;
+	if (!snd_inited)  /* shouldn't happen, but just in case... */
+	{
+		memset(stream, '\0', len);
+		return;
+	}
+	else
+	{
+		int tobufend = dmasize - pos;  /* bytes to buffer's end. */
+		int len1 = len;
+		int len2 = 0;
 
-        if (len1 > tobufend)
-        {
-            len1 = tobufend;
-            len2 = len - len1;
-        }
-        memcpy(stream, dma.buffer + pos, len1);
-        if (len2 <= 0)
-            dmapos += (len1 / (dma.samplebits/8));
-        else  /* wraparound? */
-        {
-            memcpy(stream+len1, dma.buffer, len2);
-            dmapos = (len2 / (dma.samplebits/8));
-        }
-    }
+		if (len1 > tobufend)
+		{
+			len1 = tobufend;
+			len2 = len - len1;
+		}
+		memcpy(stream, dma.buffer + pos, len1);
+		if (len2 <= 0)
+			dmapos += (len1 / (dma.samplebits/8));
+		else  /* wraparound? */
+		{
+			memcpy(stream+len1, dma.buffer, len2);
+			dmapos = (len2 / (dma.samplebits/8));
+		}
+	}
 
-    if (dmapos >= dmasize)
-        dmapos = 0;
+	if (dmapos >= dmasize)
+		dmapos = 0;
 }
 
+static struct
+{
+	Uint16	enumFormat;
+	char		*stringFormat;
+} formatToStringTable[ ] =
+{
+	{ AUDIO_U8,     "AUDIO_U8" },
+	{ AUDIO_S8,     "AUDIO_S8" },
+	{ AUDIO_U16LSB, "AUDIO_U16LSB" },
+	{ AUDIO_S16LSB, "AUDIO_S16LSB" },
+	{ AUDIO_U16MSB, "AUDIO_U16MSB" },
+	{ AUDIO_S16MSB, "AUDIO_S16MSB" }
+};
+
+static int formatToStringTableSize =
+  sizeof( formatToStringTable ) / sizeof( formatToStringTable[ 0 ] );
+
+/*
+===============
+print_audiospec
+===============
+*/
 static void print_audiospec(const char *str, const SDL_AudioSpec *spec)
 {
-    Com_Printf("%s:\n", str);
+	int		i;
+	char	*fmt = NULL;
 
-    // I'm sorry this is nasty.
-    #define PRINT_AUDIO_FMT(x) \
-        if (spec->format == x) Com_Printf("Format: %s\n", #x); else
-    PRINT_AUDIO_FMT(AUDIO_U8)
-    PRINT_AUDIO_FMT(AUDIO_S8)
-    PRINT_AUDIO_FMT(AUDIO_U16LSB)
-    PRINT_AUDIO_FMT(AUDIO_S16LSB)
-    PRINT_AUDIO_FMT(AUDIO_U16MSB)
-    PRINT_AUDIO_FMT(AUDIO_S16MSB)
-    Com_Printf("Format: UNKNOWN\n");
-    #undef PRINT_AUDIO_FMT
+	Com_Printf("%s:\n", str);
 
-    Com_Printf("Freq: %d\n", (int) spec->freq);
-    Com_Printf("Samples: %d\n", (int) spec->samples);
-    Com_Printf("Channels: %d\n", (int) spec->channels);
-    Com_Printf("\n");
+	for( i = 0; i < formatToStringTableSize; i++ ) {
+		if( spec->format == formatToStringTable[ i ].enumFormat ) {
+			fmt = formatToStringTable[ i ].stringFormat;
+		}
+	}
+
+	if( fmt ) {
+		Com_Printf( "  Format:   %s\n", fmt );
+	} else {
+		Com_Printf( "  Format:   " S_COLOR_RED "UNKNOWN\n", fmt );
+	}
+
+	Com_Printf( "  Freq:     %d\n", (int) spec->freq );
+	Com_Printf( "  Samples:  %d\n", (int) spec->samples );
+	Com_Printf( "  Channels: %d\n", (int) spec->channels );
 }
 
+/*
+===============
+SNDDMA_Init
+===============
+*/
 qboolean SNDDMA_Init(void)
 {
-    char drivername[128];
-    SDL_AudioSpec desired;
-    SDL_AudioSpec obtained;
+	char drivername[128];
+	SDL_AudioSpec desired;
+	SDL_AudioSpec obtained;
 	int tmp;
 
 	if (snd_inited)
-		return 1;
+		return qtrue;
 
-    Com_Printf("SDL Audio driver initializing...\n");
+	Com_Printf("Initializing SDL audio driver...\n");
 
-	if (!snddevice) {
-		sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE);
-		sndspeed = Cvar_Get("sndspeed", "0", CVAR_ARCHIVE);
-		sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
-		snddevice = Cvar_Get("snddevice", "/dev/dsp", CVAR_ARCHIVE);
-		sdldevsamps = Cvar_Get("sdldevsamps", "0", CVAR_ARCHIVE);
-		sdlmixsamps = Cvar_Get("sdlmixsamps", "0", CVAR_ARCHIVE);
+	if (!s_sdlBits) {
+		s_sdlBits = Cvar_Get("s_sdlBits", "16", CVAR_ARCHIVE);
+		s_sdlSpeed = Cvar_Get("s_sdlSpeed", "0", CVAR_ARCHIVE);
+		s_sdlChannels = Cvar_Get("s_sdlChannels", "2", CVAR_ARCHIVE);
+		s_sdlDevSamps = Cvar_Get("s_sdlDevSamps", "0", CVAR_ARCHIVE);
+		s_sdlMixSamps = Cvar_Get("s_sdlMixSamps", "0", CVAR_ARCHIVE);
 	}
 
-    if (!SDL_WasInit(SDL_INIT_AUDIO))
-    {
-        Com_Printf("Calling SDL_Init(SDL_INIT_AUDIO)...\n");
-        if (SDL_Init(SDL_INIT_AUDIO) == -1)
-        {
-		    Com_Printf("SDL_Init(SDL_INIT_AUDIO) failed: %s\n", SDL_GetError());
-            return qfalse;
-        }
-        Com_Printf("SDL_Init(SDL_INIT_AUDIO) passed.\n");
-    }
+	if (!SDL_WasInit(SDL_INIT_AUDIO))
+	{
+		if (SDL_Init(SDL_INIT_AUDIO) == -1)
+		{
+			Com_Printf("SDL_Init(SDL_INIT_AUDIO) failed: %s\n", SDL_GetError());
+			return qfalse;
+		}
+	}
 
-    if (SDL_AudioDriverName(drivername, sizeof (drivername)) == NULL)
-        strcpy(drivername, "(UNKNOWN)");
-    Com_Printf("SDL audio driver is \"%s\"\n", drivername);
+	if (SDL_AudioDriverName(drivername, sizeof (drivername)) == NULL)
+		strcpy(drivername, "(UNKNOWN)");
+	Com_Printf("SDL audio driver is \"%s\".\n", drivername);
 
-    memset(&desired, '\0', sizeof (desired));
-    memset(&obtained, '\0', sizeof (obtained));
+	memset(&desired, '\0', sizeof (desired));
+	memset(&obtained, '\0', sizeof (obtained));
 
-    tmp = ((int) sndbits->value);
-    if ((tmp != 16) && (tmp != 8))
-        tmp = 16;
+	tmp = ((int) s_sdlBits->value);
+	if ((tmp != 16) && (tmp != 8))
+		tmp = 16;
 
-    desired.freq = (int) sndspeed->value;
-    if(!desired.freq) desired.freq = 22050;
-    desired.format = ((tmp == 16) ? AUDIO_S16SYS : AUDIO_U8);
+	desired.freq = (int) s_sdlSpeed->value;
+	if(!desired.freq) desired.freq = 22050;
+	desired.format = ((tmp == 16) ? AUDIO_S16SYS : AUDIO_U8);
 
-    // I dunno if this is the best idea, but I'll give it a try...
-    //  should probably check a cvar for this...
-    if (sdldevsamps->value)
-        desired.samples = sdldevsamps->value;
-    else
-    {
-        // just pick a sane default.
-        if (desired.freq <= 11025)
-            desired.samples = 256;
-        else if (desired.freq <= 22050)
-            desired.samples = 512;
-        else if (desired.freq <= 44100)
-            desired.samples = 1024;
-        else
-            desired.samples = 2048;  // (*shrug*)
-    }
+	// I dunno if this is the best idea, but I'll give it a try...
+	//  should probably check a cvar for this...
+	if (s_sdlDevSamps->value)
+		desired.samples = s_sdlDevSamps->value;
+	else
+	{
+		// just pick a sane default.
+		if (desired.freq <= 11025)
+			desired.samples = 256;
+		else if (desired.freq <= 22050)
+			desired.samples = 512;
+		else if (desired.freq <= 44100)
+			desired.samples = 1024;
+		else
+			desired.samples = 2048;  // (*shrug*)
+	}
 
-    desired.channels = (int) sndchannels->value;
-    desired.callback = sdl_audio_callback;
+	desired.channels = (int) s_sdlChannels->value;
+	desired.callback = sdl_audio_callback;
 
-    print_audiospec("Format we requested from SDL audio device", &desired);
+	if (SDL_OpenAudio(&desired, &obtained) == -1)
+	{
+		Com_Printf("SDL_OpenAudio() failed: %s\n", SDL_GetError());
+		SDL_QuitSubSystem(SDL_INIT_AUDIO);
+		return qfalse;
+	} // if
 
-    if (SDL_OpenAudio(&desired, &obtained) == -1)
-    {
-        Com_Printf("SDL_OpenAudio() failed: %s\n", SDL_GetError());
-        SDL_QuitSubSystem(SDL_INIT_AUDIO);
-        return qfalse;
-    } // if
+	print_audiospec("SDL_AudioSpec", &obtained);
 
-    print_audiospec("Format we actually got", &obtained);
+	// dma.samples needs to be big, or id's mixer will just refuse to
+	//  work at all; we need to keep it significantly bigger than the
+	//  amount of SDL callback samples, and just copy a little each time
+	//  the callback runs.
+	// 32768 is what the OSS driver filled in here on my system. I don't
+	//  know if it's a good value overall, but at least we know it's
+	//  reasonable...this is why I let the user override.
+	tmp = s_sdlMixSamps->value;
+	if (!tmp)
+		tmp = (obtained.samples * obtained.channels) * 10;
 
-    // dma.samples needs to be big, or id's mixer will just refuse to
-    //  work at all; we need to keep it significantly bigger than the
-    //  amount of SDL callback samples, and just copy a little each time
-    //  the callback runs.
-    // 32768 is what the OSS driver filled in here on my system. I don't
-    //  know if it's a good value overall, but at least we know it's
-    //  reasonable...this is why I let the user override.
-    tmp = sdlmixsamps->value;
-    if (!tmp)
-        tmp = (obtained.samples * obtained.channels) * 10;
+	if (tmp & (tmp - 1))  // not a power of two? Seems to confuse something.
+	{
+		int val = 1;
+		while (val < tmp)
+			val <<= 1;
 
-    if (tmp & (tmp - 1))  // not a power of two? Seems to confuse something.
-    {
-        int val = 1;
-        while (val < tmp)
-            val <<= 1;
+		tmp = val;
+	}
 
-        Com_Printf("WARNING: sdlmixsamps wasn't a power of two (%d),"
-                   " so we made it one (%d).\n", tmp, val);
-        tmp = val;
-    }
-
-    dmapos = 0;
+	dmapos = 0;
 	dma.samplebits = obtained.format & 0xFF;  // first byte of format is bits.
-    dma.channels = obtained.channels;
-    dma.samples = tmp;
+	dma.channels = obtained.channels;
+	dma.samples = tmp;
 	dma.submission_chunk = 1;
 	dma.speed = obtained.freq;
-    dmasize = (dma.samples * (dma.samplebits/8));
+	dmasize = (dma.samples * (dma.samplebits/8));
 	dma.buffer = calloc(1, dmasize);
 
-    Com_Printf("Starting SDL audio callback...\n");
-    SDL_PauseAudio(0);  // start callback.
+	Com_Printf("Starting SDL audio callback...\n");
+	SDL_PauseAudio(0);  // start callback.
 
-    Com_Printf("SDL audio initialized.\n");
-	snd_inited = 1;
+	Com_Printf("SDL audio initialized.\n");
+	snd_inited = qtrue;
 	return qtrue;
 }
 
+/*
+===============
+SNDDMA_GetDMAPos
+===============
+*/
 int SNDDMA_GetDMAPos(void)
 {
-    return dmapos;
+	return dmapos;
 }
 
+/*
+===============
+SNDDMA_Shutdown
+===============
+*/
 void SNDDMA_Shutdown(void)
 {
-    Com_Printf("Closing SDL audio device...\n");
-    SDL_PauseAudio(1);
-    SDL_CloseAudio();
-    SDL_QuitSubSystem(SDL_INIT_AUDIO);
-    free(dma.buffer);
-    dma.buffer = NULL;
-    dmapos = dmasize = 0;
-    snd_inited = 0;
-    Com_Printf("SDL audio device shut down.\n");
+	Com_Printf("Closing SDL audio device...\n");
+	SDL_PauseAudio(1);
+	SDL_CloseAudio();
+	SDL_QuitSubSystem(SDL_INIT_AUDIO);
+	free(dma.buffer);
+	dma.buffer = NULL;
+	dmapos = dmasize = 0;
+	snd_inited = qfalse;
+	Com_Printf("SDL audio device shut down.\n");
 }
 
 /*
-==============
+===============
 SNDDMA_Submit
 
 Send sound to device if buffer isn't really the dma buffer
@@ -290,15 +342,17 @@
 */
 void SNDDMA_Submit(void)
 {
-    SDL_UnlockAudio();
+	SDL_UnlockAudio();
 }
 
+/*
+===============
+SNDDMA_BeginPainting
+===============
+*/
 void SNDDMA_BeginPainting (void)
 {
-    SDL_LockAudio();
+	SDL_LockAudio();
 }
 
 #endif  // USE_SDL_SOUND
-
-// end of linux_snd_sdl.c ...
-

Modified: trunk/i_o-q3-readme
===================================================================
--- trunk/i_o-q3-readme	2005-11-13 18:33:28 UTC (rev 342)
+++ trunk/i_o-q3-readme	2005-11-13 18:58:14 UTC (rev 343)
@@ -109,13 +109,16 @@
 
    ...and comment out/remove the duplicated code marked by '>'.
 
-4. If you didn't install the DirectX SDK in C:\DXSDK\, edit DXSDK_DIR in
-   code/unix/Makefile to reflect the new location.
-5. Perform the usual precompilation sacrificial ritual.
-6. Open an MSys terminal, and follow the instructions for compiling on Linux.
-7. Steal underpants
-8. ????
-9. Profit!
+4. If you didn't install the DirectX SDK in C:\DXSDK\, add DXSDK_DIR to
+   code/unix/Makefile.local to reflect the new location.
+5. If you want OpenAL support, aquire some OpenAL headers and put them in
+   /include/AL/ beneath your MinGW dir. If not, add "USE_OPENAL=0" to
+   code/unix/Makefile.local.
+6. Perform the usual precompilation sacrificial ritual.
+7. Open an MSys terminal, and follow the instructions for compiling on Linux.
+8. Steal underpants
+9. ?????
+10. Profit!
 
 Creating mods compatible with Q3 1.32b
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~




More information about the quake3-commits mailing list