From 7d96b51fbc8b0df8ebf348de2aa5f2058254ed93 Mon Sep 17 00:00:00 2001 From: Tim Angus Date: Mon, 9 Jan 2006 02:16:46 +0000 Subject: * Merged ioq3-468 --- src/client/cl_avi.c | 10 +- src/client/cl_main.c | 8 +- src/client/client.h | 2 +- src/client/snd_codec.c | 4 +- src/client/snd_codec.h | 1 + src/client/snd_codec_ogg.c | 465 +++++++++++++++++++++++++++++++++++++++++++++ src/client/snd_dma.c | 2 +- src/game/g_mover.c | 2 +- src/qcommon/vm_x86_64.c | 5 +- src/unix/Makefile | 40 +++- 10 files changed, 514 insertions(+), 25 deletions(-) create mode 100644 src/client/snd_codec_ogg.c (limited to 'src') diff --git a/src/client/cl_avi.c b/src/client/cl_avi.c index 4a372d8b..178260be 100644 --- a/src/client/cl_avi.c +++ b/src/client/cl_avi.c @@ -332,9 +332,9 @@ qboolean CL_OpenAVIForWriting( const char *fileName ) Com_Memset( &afd, 0, sizeof( aviFileData_t ) ); // Don't start if a framerate has not been chosen - if( cl_avidemo->integer <= 0 ) + if( cl_aviFrameRate->integer <= 0 ) { - Com_Printf( S_COLOR_RED "cl_avidemo must be >= 1\n" ); + Com_Printf( S_COLOR_RED "cl_aviFrameRate must be >= 1\n" ); return qfalse; } @@ -349,7 +349,7 @@ qboolean CL_OpenAVIForWriting( const char *fileName ) Q_strncpyz( afd.fileName, fileName, MAX_QPATH ); - afd.frameRate = cl_avidemo->integer; + afd.frameRate = cl_aviFrameRate->integer; afd.framePeriod = (int)( 1000000.0f / afd.frameRate ); afd.width = cls.glconfig.vidWidth; afd.height = cls.glconfig.vidHeight; @@ -375,7 +375,7 @@ qboolean CL_OpenAVIForWriting( const char *fileName ) while( ( afd.a.rate % suggestRate ) && suggestRate >= 1 ) suggestRate--; - Com_Printf( S_COLOR_YELLOW "WARNING: cl_avidemo is not a divisor " + Com_Printf( S_COLOR_YELLOW "WARNING: cl_aviFrameRate is not a divisor " "of the audio rate, suggest %d\n", suggestRate ); } @@ -484,7 +484,7 @@ void CL_WriteAVIAudioFrame( const byte *pcmBuffer, int size ) bytesInBuffer += size; // Only write if we have a frame's worth of audio - if( bytesInBuffer >= (int)ceil( afd.a.rate / cl_avidemo->value ) * + if( bytesInBuffer >= (int)ceil( afd.a.rate / cl_aviFrameRate->value ) * afd.a.sampleSize ) { int chunkOffset = afd.fileSize - afd.moviOffset - 8; diff --git a/src/client/cl_main.c b/src/client/cl_main.c index a00f901e..3f2e1152 100644 --- a/src/client/cl_main.c +++ b/src/client/cl_main.c @@ -45,7 +45,7 @@ cvar_t *cl_shownet; cvar_t *cl_showSend; cvar_t *cl_timedemo; cvar_t *cl_autoRecordDemo; -cvar_t *cl_avidemo; +cvar_t *cl_aviFrameRate; cvar_t *cl_aviMotionJpeg; cvar_t *cl_forceavidemo; @@ -1974,13 +1974,13 @@ void CL_Frame ( int msec ) { } // if recording an avi, lock to a fixed fps - if ( CL_VideoRecording( ) && cl_avidemo->integer && msec) { + if ( CL_VideoRecording( ) && cl_aviFrameRate->integer && msec) { // save the current screen if ( cls.state == CA_ACTIVE || cl_forceavidemo->integer) { CL_TakeVideoFrame( ); // fixed time for next frame' - msec = (int)ceil( (1000.0f / cl_avidemo->value) * com_timescale->value ); + msec = (int)ceil( (1000.0f / cl_aviFrameRate->value) * com_timescale->value ); if (msec == 0) { msec = 1; } @@ -2362,7 +2362,7 @@ void CL_Init( void ) { cl_timedemo = Cvar_Get ("timedemo", "0", 0); cl_autoRecordDemo = Cvar_Get ("cl_autoRecordDemo", "0", CVAR_ARCHIVE); - cl_avidemo = Cvar_Get ("cl_avidemo", "25", CVAR_ARCHIVE); + cl_aviFrameRate = Cvar_Get ("cl_aviFrameRate", "25", CVAR_ARCHIVE); cl_aviMotionJpeg = Cvar_Get ("cl_aviMotionJpeg", "1", CVAR_ARCHIVE); cl_forceavidemo = Cvar_Get ("cl_forceavidemo", "0", 0); diff --git a/src/client/client.h b/src/client/client.h index 1c4fa198..fb1ecea1 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -343,7 +343,7 @@ extern cvar_t *m_side; extern cvar_t *m_filter; extern cvar_t *cl_timedemo; -extern cvar_t *cl_avidemo; +extern cvar_t *cl_aviFrameRate; extern cvar_t *cl_aviMotionJpeg; extern cvar_t *cl_activeAction; diff --git a/src/client/snd_codec.c b/src/client/snd_codec.c index 338d0306..e1c6bb47 100644 --- a/src/client/snd_codec.c +++ b/src/client/snd_codec.c @@ -192,9 +192,10 @@ snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec) { snd_stream_t *stream; fileHandle_t hnd; + int length; // Try to open the file - FS_FOpenFileRead(filename, &hnd, qtrue); + length = FS_FOpenFileRead(filename, &hnd, qtrue); if(!hnd) { Com_Printf("Can't read sound file %s\n", filename); @@ -212,6 +213,7 @@ snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec) // Copy over, return stream->codec = codec; stream->file = hnd; + stream->length = length; return stream; } diff --git a/src/client/snd_codec.h b/src/client/snd_codec.h index 74ac77e9..582e65ef 100644 --- a/src/client/snd_codec.h +++ b/src/client/snd_codec.h @@ -45,6 +45,7 @@ typedef struct snd_stream_s snd_codec_t *codec; fileHandle_t file; snd_info_t info; + int length; int pos; void *ptr; } snd_stream_t; diff --git a/src/client/snd_codec_ogg.c b/src/client/snd_codec_ogg.c new file mode 100644 index 00000000..20462fcb --- /dev/null +++ b/src/client/snd_codec_ogg.c @@ -0,0 +1,465 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. +Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com) +Copyright (C) 2005-2006 Joerg Dietrich + +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 +=========================================================================== +*/ + +// OGG support is enabled by this define +#ifdef USE_CODEC_VORBIS + +// includes for the Q3 sound system +#include "client.h" +#include "snd_codec.h" + +// includes for the OGG codec +#include +#include + +// The OGG codec can return the samples in a number of different formats, +// we use the standard signed short format. +#define OGG_SAMPLEWIDTH 2 + +// Q3 OGG codec +snd_codec_t ogg_codec = +{ + ".ogg", + S_OGG_CodecLoad, + S_OGG_CodecOpenStream, + S_OGG_CodecReadStream, + S_OGG_CodecCloseStream, + NULL +}; + +// callbacks for vobisfile + +// fread() replacement +size_t S_OGG_Callback_read(void *ptr, size_t size, size_t nmemb, void *datasource) +{ + snd_stream_t *stream; + int byteSize = 0; + int bytesRead = 0; + size_t nMembRead = 0; + + // check if input is valid + if(!ptr) + { + errno = EFAULT; + return 0; + } + + if(!(size && nmemb)) + { + // It's not an error, caller just wants zero bytes! + errno = 0; + return 0; + } + + if(!datasource) + { + errno = EBADF; + return 0; + } + + // we use a snd_stream_t in the generic pointer to pass around + stream = (snd_stream_t *) datasource; + + // FS_Read does not support multi-byte elements + byteSize = nmemb * size; + + // read it with the Q3 function FS_Read() + bytesRead = FS_Read(ptr, byteSize, stream->file); + + // update the file position + stream->pos += bytesRead; + + // this function returns the number of elements read not the number of bytes + nMembRead = bytesRead / size; + + // even if the last member is only read partially + // it is counted as a whole in the return value + if(bytesRead % size) + { + nMembRead++; + } + + return nMembRead; +} + +// fseek() replacement +int S_OGG_Callback_seek(void *datasource, ogg_int64_t offset, int whence) +{ + snd_stream_t *stream; + int retVal = 0; + + // check if input is valid + if(!datasource) + { + errno = EBADF; + return -1; + } + + // snd_stream_t in the generic pointer + stream = (snd_stream_t *) datasource; + + // we must map the whence to its Q3 counterpart + switch(whence) + { + case SEEK_SET : + { + // set the file position in the actual file with the Q3 function + retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_SET); + + // something has gone wrong, so we return here + if(!(retVal == 0)) + { + return retVal; + } + + // keep track of file position + stream->pos = (int) offset; + break; + } + + case SEEK_CUR : + { + // set the file position in the actual file with the Q3 function + retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_CUR); + + // something has gone wrong, so we return here + if(!(retVal == 0)) + { + return retVal; + } + + // keep track of file position + stream->pos += (int) offset; + break; + } + + case SEEK_END : + { + // Quake 3 seems to have trouble with FS_SEEK_END + // so we use the file length and FS_SEEK_SET + + // set the file position in the actual file with the Q3 function + retVal = FS_Seek(stream->file, (long) stream->length + (long) offset, FS_SEEK_SET); + + // something has gone wrong, so we return here + if(!(retVal == 0)) + { + return retVal; + } + + // keep track of file position + stream->pos = stream->length + (int) offset; + break; + } + + default : + { + // unknown whence, so we return an error + errno = EINVAL; + return -1; + } + } + + // stream->pos shouldn't be smaller than zero or bigger than the filesize + stream->pos = (stream->pos < 0) ? 0 : stream->pos; + stream->pos = (stream->pos > stream->length) ? stream->length : stream->pos; + + return 0; +} + +// fclose() replacement +int S_OGG_Callback_close(void *datasource) +{ + // we do nothing here and close all things manually in S_OGG_CodecCloseStream() + return 0; +} + +// ftell() replacement +long S_OGG_Callback_tell(void *datasource) +{ + // check if input is valid + if(!datasource) + { + errno = EBADF; + return -1; + } + + // we keep track of the file position in stream->pos + return (long) (((snd_stream_t *) datasource) -> pos); +} + +// the callback structure +const ov_callbacks S_OGG_Callbacks = +{ + &S_OGG_Callback_read, + &S_OGG_Callback_seek, + &S_OGG_Callback_close, + &S_OGG_Callback_tell +}; + +/* +================= +S_OGG_CodecOpenStream +================= +*/ +snd_stream_t *S_OGG_CodecOpenStream(const char *filename) +{ + snd_stream_t *stream; + + // OGG codec control structure + OggVorbis_File *vf; + + // some variables used to get informations about the OGG + vorbis_info *OGGInfo; + ogg_int64_t numSamples; + + // check if input is valid + if(!filename) + { + return NULL; + } + + // Open the stream + stream = S_CodecUtilOpen(filename, &ogg_codec); + if(!stream) + { + return NULL; + } + + // alloctate the OggVorbis_File + vf = Z_Malloc(sizeof(OggVorbis_File)); + if(!vf) + { + S_CodecUtilClose(stream); + + return NULL; + } + + // open the codec with our callbacks and stream as the generic pointer + if(ov_open_callbacks(stream, vf, NULL, 0, S_OGG_Callbacks) != 0) + { + Z_Free(vf); + + S_CodecUtilClose(stream); + + return NULL; + } + + // the stream must be seekable + if(!ov_seekable(vf)) + { + ov_clear(vf); + + Z_Free(vf); + + S_CodecUtilClose(stream); + + return NULL; + } + + // we only support OGGs with one substream + if(ov_streams(vf) != 1) + { + ov_clear(vf); + + Z_Free(vf); + + S_CodecUtilClose(stream); + + return NULL; + } + + // get the info about channels and rate + OGGInfo = ov_info(vf, 0); + if(!OGGInfo) + { + ov_clear(vf); + + Z_Free(vf); + + S_CodecUtilClose(stream); + + return NULL; + } + + // get the number of sample-frames in the OGG + numSamples = ov_pcm_total(vf, 0); + + // fill in the info-structure in the stream + stream->info.rate = OGGInfo->rate; + stream->info.width = OGG_SAMPLEWIDTH; + stream->info.channels = OGGInfo->channels; + stream->info.samples = numSamples; + stream->info.size = stream->info.samples * stream->info.channels * stream->info.width; + stream->info.dataofs = 0; + + // We use stream->pos for the file pointer in the compressed ogg file + stream->pos = 0; + + // We use the generic pointer in stream for the OGG codec control structure + stream->ptr = vf; + + return stream; +} + +/* +================= +S_OGG_CodecCloseStream +================= +*/ +void S_OGG_CodecCloseStream(snd_stream_t *stream) +{ + // check if input is valid + if(!stream) + { + return; + } + + // let the OGG codec cleanup its stuff + ov_clear((OggVorbis_File *) stream->ptr); + + // free the OGG codec control struct + Z_Free(stream->ptr); + + // close the stream + S_CodecUtilClose(stream); +} + +/* +================= +S_OGG_CodecReadStream +================= +*/ +int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer) +{ + // buffer handling + int bytesRead, bytesLeft, c; + char *bufPtr; + + // Bitstream for the decoder + int BS = 0; + + // check if input is valid + if(!(stream && buffer)) + { + return 0; + } + + if(bytes <= 0) + { + return 0; + } + + bytesRead = 0; + bytesLeft = bytes; + bufPtr = buffer; + + // cycle until we have the requested or all available bytes read + while(-1) + { + // read some bytes from the OGG codec + c = ov_read((OggVorbis_File *) stream->ptr, bufPtr, bytesLeft, 0, OGG_SAMPLEWIDTH, 1, &BS); + + // no more bytes are left + if(c <= 0) + { + break; + } + + bytesRead += c; + bytesLeft -= c; + bufPtr += c; + + // we have enough bytes + if(bytesLeft <= 0) + { + break; + } + } + + return bytesRead; +} + +/* +===================================================================== +S_OGG_CodecLoad + +We handle S_OGG_CodecLoad as a special case of the streaming functions +where we read the whole stream at once. +====================================================================== +*/ +void *S_OGG_CodecLoad(const char *filename, snd_info_t *info) +{ + snd_stream_t *stream; + unsigned char *buffer; + int bytesRead; + + // check if input is valid + if(!(filename && info)) + { + return NULL; + } + + // open the file as a stream + stream = S_OGG_CodecOpenStream(filename); + if(!stream) + { + return NULL; + } + + // copy over the info + info->rate = stream->info.rate; + info->width = stream->info.width; + info->channels = stream->info.channels; + info->samples = stream->info.samples; + info->size = stream->info.size; + info->dataofs = stream->info.dataofs; + + // allocate a buffer + // this buffer must be free-ed by the caller of this function + buffer = Z_Malloc(info->size); + if(!buffer) + { + S_OGG_CodecCloseStream(stream); + + return NULL; + } + + // fill the buffer + bytesRead = S_OGG_CodecReadStream(stream, info->size, buffer); + + // we don't even have read a single byte + if(bytesRead <= 0) + { + S_OGG_CodecCloseStream(stream); + + return NULL; + } + + S_OGG_CodecCloseStream(stream); + + return buffer; +} + +#endif // USE_CODEC_VORBIS diff --git a/src/client/snd_dma.c b/src/client/snd_dma.c index d51a4b85..ee57f6f2 100644 --- a/src/client/snd_dma.c +++ b/src/client/snd_dma.c @@ -1142,7 +1142,7 @@ void S_GetSoundtime(void) if( CL_VideoRecording( ) ) { - s_soundtime += (int)ceil( dma.speed / cl_avidemo->value ); + s_soundtime += (int)ceil( dma.speed / cl_aviFrameRate->value ); return; } diff --git a/src/game/g_mover.c b/src/game/g_mover.c index 0c060c7b..8f7de418 100644 --- a/src/game/g_mover.c +++ b/src/game/g_mover.c @@ -1937,7 +1937,7 @@ void SP_func_button( gentity_t *ent ) float lip; char *s; - G_SpawnString( "sound1to2", "sound/movers/switches/butn2.wav", &s ); + G_SpawnString( "sound1to2", "sound/movers/switches/button1.wav", &s ); ent->sound1to2 = G_SoundIndex( s ); if( !ent->speed ) diff --git a/src/qcommon/vm_x86_64.c b/src/qcommon/vm_x86_64.c index e8545b9f..23f87c30 100644 --- a/src/qcommon/vm_x86_64.c +++ b/src/qcommon/vm_x86_64.c @@ -386,12 +386,11 @@ static int doas(char* in, char* out, unsigned char** compiledcode) if((*compiledcode = (unsigned char*)buf)) { -#ifdef VM_X86_64_STANDALONE // no idea why - if(mprotect(buf, allocsize, PROT_READ|PROT_EXEC) == -1) + // need to be able to exec code + if(mprotect(buf, allocsize, PROT_READ|PROT_WRITE|PROT_EXEC) == -1) { Com_Error(ERR_FATAL, "mprotect failed on %p+%x: %s\n", buf, allocsize, strerror(errno)); } -#endif return size; } diff --git a/src/unix/Makefile b/src/unix/Makefile index 4769b075..29301edb 100644 --- a/src/unix/Makefile +++ b/src/unix/Makefile @@ -92,6 +92,10 @@ ifndef USE_OPENAL_DLOPEN USE_OPENAL_DLOPEN=0 endif +ifndef USE_CODEC_VORBIS +USE_CODEC_VORBIS=0 +endif + ifndef USE_LOCAL_HEADERS USE_LOCAL_HEADERS=1 endif @@ -158,6 +162,10 @@ ifeq ($(PLATFORM),linux) endif endif + ifeq ($(USE_CODEC_VORBIS),1) + BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 + endif + ifeq ($(USE_SDL),1) BASE_CFLAGS += -DUSE_SDL_VIDEO=1 -DUSE_SDL_SOUND=1 $(shell sdl-config --cflags) GL_CFLAGS = @@ -216,6 +224,10 @@ ifeq ($(PLATFORM),linux) endif endif + ifeq ($(USE_CODEC_VORBIS),1) + CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg + endif + ifeq ($(ARCH),i386) # linux32 make ... BASE_CFLAGS += -m32 @@ -247,6 +259,10 @@ ifeq ($(PLATFORM),darwin) endif endif + ifeq ($(USE_CODEC_VORBIS),1) + BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 + endif + ifeq ($(USE_SDL),1) BASE_CFLAGS += -DUSE_SDL_VIDEO=1 -DUSE_SDL_SOUND=1 -D_THREAD_SAFE=1 -I../SDL12/include GL_CFLAGS = @@ -303,6 +319,10 @@ ifeq ($(PLATFORM),darwin) endif endif + ifeq ($(USE_CODEC_VORBIS),1) + CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg + endif + else # ifeq darwin @@ -323,6 +343,10 @@ ifeq ($(PLATFORM),mingw32) BASE_CFLAGS += -DUSE_OPENAL=1 -DUSE_OPENAL_DLOPEN=1 endif + ifeq ($(USE_CODEC_VORBIS),1) + BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 + endif + GL_CFLAGS = MINGW_CFLAGS = -DDONT_TYPEDEF_INT32 @@ -342,6 +366,10 @@ ifeq ($(PLATFORM),mingw32) LDFLAGS= -mwindows -lwsock32 -lgdi32 -lwinmm -lole32 CLIENT_LDFLAGS= + ifeq ($(USE_CODEC_VORBIS),1) + CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg + endif + ifeq ($(ARCH),x86) # build 32bit BASE_CFLAGS += -m32 @@ -701,6 +729,7 @@ Q3OBJ = \ $(B)/client/snd_main.o \ $(B)/client/snd_codec.o \ $(B)/client/snd_codec_wav.o \ + $(B)/client/snd_codec_ogg.o \ \ $(B)/client/qal.o \ $(B)/client/snd_openal.o \ @@ -828,13 +857,6 @@ ifeq ($(ARCH),x86) endif ifeq ($(ARCH),x86_64) Q3OBJ += $(B)/client/vm_x86_64.o - - #FIXME: why do these need to be here? - Q3OBJ += \ - $(B)/client/snd_mixa.o \ - $(B)/client/matha.o \ - $(B)/client/ftola.o \ - $(B)/client/snapvectora.o endif ifeq ($(ARCH),ppc) @@ -920,6 +942,7 @@ $(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/snd_codec_ogg.o : $(CDIR)/snd_codec_ogg.c; $(DO_CC) $(B)/client/qal.o : $(CDIR)/qal.c; $(DO_CC) $(B)/client/snd_openal.o : $(CDIR)/snd_openal.c; $(DO_CC) @@ -1454,8 +1477,7 @@ installer: build_release D_FILES=$(shell find . -name '*.d') $(B)/base/vm/vm.d: $(GOBJ) $(CGOBJ) $(UIOBJ) - -rm -f $@ - find $(B)/base -iname '*.d' | xargs sed -e 's/\.o/\.asm/g' > $@ + cat $(^:%.o=%.d) | sed -e 's/\.o/\.asm/g' > $@ qvmdeps: $(B)/base/vm/vm.d -- cgit