* 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:
Tim Angus 2005-11-13 18:58:14 +00:00
parent 79ceef93cc
commit 84c4f21082
14 changed files with 3813 additions and 703 deletions

344
code/client/qal.c Normal file
View 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
View 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
View 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
View 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
View 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;
}

View file

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

View file

@ -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
View 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( );
}

View file

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

File diff suppressed because it is too large Load diff