mirror of
https://github.com/UberGames/ioef.git
synced 2024-11-27 14:32:55 +00:00
* OpenAL support, from BlackAura aka Stuart Dalton <badcdev@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
This commit is contained in:
parent
79ceef93cc
commit
84c4f21082
14 changed files with 3813 additions and 703 deletions
344
code/client/qal.c
Normal file
344
code/client/qal.c
Normal file
|
@ -0,0 +1,344 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2005 Stuart Dalton (badcdev@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
|
134
code/client/qal.h
Normal file
134
code/client/qal.h
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2005 Stuart Dalton (badcdev@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__
|
226
code/client/snd_codec.c
Normal file
226
code/client/snd_codec.c
Normal file
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2005 Stuart Dalton (badcdev@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);
|
||||
}
|
97
code/client/snd_codec.h
Normal file
97
code/client/snd_codec.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2005 Stuart Dalton (badcdev@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_
|
307
code/client/snd_codec_wav.c
Normal file
307
code/client/snd_codec_wav.c
Normal file
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2005 Stuart Dalton (badcdev@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@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;
|
||||
}
|
|
@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
*****************************************************************************/
|
||||
|
||||
#include "snd_local.h"
|
||||
#include "snd_codec.h"
|
||||
#include "client.h"
|
||||
|
||||
void S_Play_f(void);
|
||||
|
@ -37,13 +38,11 @@ void S_SoundList_f(void);
|
|||
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 @@ int s_numSfx = 0;
|
|||
#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 @@ portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
|
|||
// ====================================================================
|
||||
|
||||
|
||||
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 @@ void S_SoundInfo_f(void) {
|
|||
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 @@ void S_SoundInfo_f(void) {
|
|||
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,25 +185,6 @@ void S_ChannelSetup( void ) {
|
|||
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");
|
||||
}
|
||||
|
||||
|
||||
// =======================================================================
|
||||
|
@ -352,32 +301,11 @@ This is called when the hunk is cleared and the sounds
|
|||
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
|
||||
|
@ -385,7 +313,7 @@ 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 @@ sfxHandle_t S_RegisterSound( const char *name, qboolean compressed ) {
|
|||
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 @@ void S_SpatializeOrigin (vec3_t origin, int master_vol, int *left_vol, int *righ
|
|||
{
|
||||
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 @@ if pos is NULL, the sound will be dynamically sourced from the entity
|
|||
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 @@ void S_StartSound(vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfxH
|
|||
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 @@ void S_StartLocalSound( sfxHandle_t sfxHandle, int channelNum ) {
|
|||
return;
|
||||
}
|
||||
|
||||
S_StartSound (NULL, listener_number, channelNum, sfxHandle );
|
||||
S_Base_StartSound (NULL, listener_number, channelNum, sfxHandle );
|
||||
}
|
||||
|
||||
|
||||
|
@ -648,7 +594,7 @@ If we are about to perform file access, clear the buffer
|
|||
so sound doesn't stutter.
|
||||
==================
|
||||
*/
|
||||
void S_ClearSoundBuffer( void ) {
|
||||
void S_Base_ClearSoundBuffer( void ) {
|
||||
int clear;
|
||||
|
||||
if (!s_soundStarted)
|
||||
|
@ -683,15 +629,15 @@ void S_ClearSoundBuffer( void ) {
|
|||
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 @@ continuous looping sounds are added each frame
|
|||
==============================================================
|
||||
*/
|
||||
|
||||
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 @@ S_ClearLoopingSounds
|
|||
|
||||
==================
|
||||
*/
|
||||
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 @@ Called during entity generation for a frame
|
|||
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 @@ Called during entity generation for a frame
|
|||
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 @@ S_RawSamples
|
|||
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 @@ S_UpdateEntityPosition
|
|||
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 @@ S_Respatialize
|
|||
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 @@ S_Update
|
|||
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 @@ void S_GetSoundtime(void)
|
|||
{ // time to chop things off to avoid 32 bit limits
|
||||
buffers = 0;
|
||||
s_paintedtime = fullsamples;
|
||||
S_StopAllSounds ();
|
||||
S_Base_StopAllSounds ();
|
||||
}
|
||||
}
|
||||
oldsamplepos = samplepos;
|
||||
|
@ -1289,73 +1235,6 @@ void S_Update_(void) {
|
|||
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 @@ background music functions
|
|||
===============================================================================
|
||||
*/
|
||||
|
||||
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 @@ void S_StopBackgroundTrack( void ) {
|
|||
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 @@ void S_StartBackgroundTrack( const char *intro, const char *loop ){
|
|||
}
|
||||
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 @@ void S_UpdateBackgroundTrack( void ) {
|
|||
int r;
|
||||
static float musicVolume = 0.5f;
|
||||
|
||||
if ( !s_backgroundFile ) {
|
||||
if(!s_backgroundStream) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1549,50 +1336,47 @@ void S_UpdateBackgroundTrack( void ) {
|
|||
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;
|
||||
|
||||
// don't try and read past the end of the file
|
||||
if ( fileSamples > s_backgroundSamples ) {
|
||||
fileSamples = s_backgroundSamples;
|
||||
}
|
||||
fileSamples = bufferSamples * s_backgroundStream->info.rate / dma.speed;
|
||||
|
||||
// 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 @@ void S_FreeOldestSound( void ) {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -117,6 +117,31 @@ typedef struct {
|
|||
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 @@ extern dma_t dma;
|
|||
#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 short *sfxScratchBuffer;
|
|||
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 );
|
||||
|
|
433
code/client/snd_main.c
Normal file
433
code/client/snd_main.c
Normal file
|
@ -0,0 +1,433 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2005 Stuart Dalton (badcdev@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( );
|
||||
}
|
||||
|
|
@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
*****************************************************************************/
|
||||
|
||||
#include "snd_local.h"
|
||||
#include "snd_codec.h"
|
||||
|
||||
#define DEF_COMSOUNDMEGS "8"
|
||||
|
||||
|
@ -99,137 +100,6 @@ void SND_setup(void) {
|
|||
Com_Printf("Sound memory manager started\n");
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
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 @@ static int ResampleSfxRaw( short *sfx, int inrate, int inwidth, int samples, byt
|
|||
return outcount;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
|
@ -330,8 +199,8 @@ qboolean S_LoadSound( sfx_t *sfx )
|
|||
{
|
||||
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,17 +208,9 @@ qboolean S_LoadSound( sfx_t *sfx )
|
|||
}
|
||||
|
||||
// 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 @@ qboolean S_LoadSound( sfx_t *sfx )
|
|||
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 @@ qboolean S_LoadSound( sfx_t *sfx )
|
|||
}
|
||||
|
||||
Hunk_FreeTempMemory(samples);
|
||||
FS_FreeFile( data );
|
||||
Z_Free(data);
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
|
1567
code/client/snd_openal.c
Normal file
1567
code/client/snd_openal.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
|
|
|
@ -47,6 +47,10 @@ ifndef USE_SDL
|
|||
USE_SDL=1
|
||||
endif
|
||||
|
||||
ifndef USE_OPENAL
|
||||
USE_OPENAL=1
|
||||
endif
|
||||
|
||||
ifndef BUILD_CLIENT
|
||||
BUILD_CLIENT=1
|
||||
endif
|
||||
|
@ -115,6 +119,10 @@ ifeq ($(PLATFORM),linux)
|
|||
|
||||
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 @@ ifeq ($(PLATFORM),mingw32)
|
|||
|
||||
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 @@ Q3OBJ = \
|
|||
$(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_dma.o : $(CDIR)/snd_dma.c; $(DO_CC)
|
|||
$(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)
|
||||
|
|
|
@ -56,233 +56,285 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#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 (dmapos >= dmasize)
|
||||
dmapos = 0;
|
||||
}
|
||||
|
||||
static void print_audiospec(const char *str, const SDL_AudioSpec *spec)
|
||||
{
|
||||
Com_Printf("%s:\n", str);
|
||||
|
||||
// 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("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");
|
||||
}
|
||||
|
||||
qboolean SNDDMA_Init(void)
|
||||
{
|
||||
char drivername[128];
|
||||
SDL_AudioSpec desired;
|
||||
SDL_AudioSpec obtained;
|
||||
int tmp;
|
||||
|
||||
if (snd_inited)
|
||||
return 1;
|
||||
|
||||
Com_Printf("SDL Audio driver initializing...\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 (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 (!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_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));
|
||||
|
||||
tmp = ((int) sndbits->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);
|
||||
|
||||
// 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*)
|
||||
}
|
||||
|
||||
desired.channels = (int) sndchannels->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
|
||||
|
||||
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 = 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;
|
||||
|
||||
Com_Printf("WARNING: sdlmixsamps wasn't a power of two (%d),"
|
||||
" so we made it one (%d).\n", tmp, val);
|
||||
tmp = val;
|
||||
}
|
||||
|
||||
dmapos = 0;
|
||||
dma.samplebits = obtained.format & 0xFF; // first byte of format is bits.
|
||||
dma.channels = obtained.channels;
|
||||
dma.samples = tmp;
|
||||
dma.submission_chunk = 1;
|
||||
dma.speed = obtained.freq;
|
||||
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("SDL audio initialized.\n");
|
||||
snd_inited = 1;
|
||||
return qtrue;
|
||||
if (dmapos >= dmasize)
|
||||
dmapos = 0;
|
||||
}
|
||||
|
||||
int SNDDMA_GetDMAPos(void)
|
||||
static struct
|
||||
{
|
||||
return dmapos;
|
||||
}
|
||||
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" }
|
||||
};
|
||||
|
||||
void SNDDMA_Shutdown(void)
|
||||
static int formatToStringTableSize =
|
||||
sizeof( formatToStringTable ) / sizeof( formatToStringTable[ 0 ] );
|
||||
|
||||
/*
|
||||
===============
|
||||
print_audiospec
|
||||
===============
|
||||
*/
|
||||
static void print_audiospec(const char *str, const SDL_AudioSpec *spec)
|
||||
{
|
||||
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");
|
||||
int i;
|
||||
char *fmt = NULL;
|
||||
|
||||
Com_Printf("%s:\n", str);
|
||||
|
||||
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;
|
||||
int tmp;
|
||||
|
||||
if (snd_inited)
|
||||
return qtrue;
|
||||
|
||||
Com_Printf("Initializing SDL audio driver...\n");
|
||||
|
||||
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))
|
||||
{
|
||||
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);
|
||||
|
||||
memset(&desired, '\0', sizeof (desired));
|
||||
memset(&obtained, '\0', sizeof (obtained));
|
||||
|
||||
tmp = ((int) s_sdlBits->value);
|
||||
if ((tmp != 16) && (tmp != 8))
|
||||
tmp = 16;
|
||||
|
||||
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 (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) s_sdlChannels->value;
|
||||
desired.callback = sdl_audio_callback;
|
||||
|
||||
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);
|
||||
|
||||
// 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;
|
||||
|
||||
if (tmp & (tmp - 1)) // not a power of two? Seems to confuse something.
|
||||
{
|
||||
int val = 1;
|
||||
while (val < tmp)
|
||||
val <<= 1;
|
||||
|
||||
tmp = val;
|
||||
}
|
||||
|
||||
dmapos = 0;
|
||||
dma.samplebits = obtained.format & 0xFF; // first byte of format is bits.
|
||||
dma.channels = obtained.channels;
|
||||
dma.samples = tmp;
|
||||
dma.submission_chunk = 1;
|
||||
dma.speed = obtained.freq;
|
||||
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("SDL audio initialized.\n");
|
||||
snd_inited = qtrue;
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SNDDMA_GetDMAPos
|
||||
===============
|
||||
*/
|
||||
int SNDDMA_GetDMAPos(void)
|
||||
{
|
||||
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 = 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 @@ Send sound to device if buffer isn't really the dma buffer
|
|||
*/
|
||||
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 ...
|
||||
|
||||
|
|
|
@ -109,13 +109,16 @@ follows:
|
|||
|
||||
...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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
Loading…
Reference in a new issue