From ffa3bf4413b9400a05768b73296ed179f343d9b5 Mon Sep 17 00:00:00 2001 From: Ozkan Sezer Date: Wed, 25 Sep 2013 11:01:12 +0000 Subject: [PATCH] Merge several FS_* and snd_codec* layer updates from uhexen2 tree: tidy-ups in FS* stdio replacement functions. add new FS_filelength. snd codec layer updates: changed codec_open() to operate only on a stream pointer and moved all file open/close stuff to snd_codec.c. codec_open now only returns true or false upon success or failure instead of a stream pointer. added new snd_codec.c toplevel helper S_CodecForwardStream(), which allows one codec to hand over its stream from its codec_open() to another codec. Support for tracker (mod) music, including support for Unreal umx containers. (might be useful if we ever make a Nehahra version of the engine some day. edit the makefiles to enable when compiling.) git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@867 af15c1b1-3010-417e-b628-4374ebc0bcbd --- Quake/Makefile | 20 ++- Quake/Makefile.darwin | 24 ++- Quake/Makefile.w32 | 24 ++- Quake/Makefile.w64 | 24 ++- Quake/bgmusic.c | 5 + Quake/common.c | 53 +++--- Quake/common.h | 1 + Quake/snd_codec.c | 69 ++++++-- Quake/snd_codec.h | 2 + Quake/snd_codeci.h | 5 +- Quake/snd_flac.c | 23 +-- Quake/snd_mikmod.c | 199 ++++++++++++++++++++++ Quake/snd_mikmod.h | 13 ++ Quake/snd_modplug.c | 121 +++++++++++++ Quake/snd_modplug.h | 12 ++ Quake/snd_mp3.c | 21 +-- Quake/snd_mpg123.c | 18 +- Quake/snd_opus.c | 22 +-- Quake/snd_umx.c | 387 ++++++++++++++++++++++++++++++++++++++++++ Quake/snd_umx.h | 12 ++ Quake/snd_vorbis.c | 22 +-- Quake/snd_wave.c | 24 +-- 22 files changed, 971 insertions(+), 130 deletions(-) create mode 100644 Quake/snd_mikmod.c create mode 100644 Quake/snd_mikmod.h create mode 100644 Quake/snd_modplug.c create mode 100644 Quake/snd_modplug.h create mode 100644 Quake/snd_umx.c create mode 100644 Quake/snd_umx.h diff --git a/Quake/Makefile b/Quake/Makefile index 4ff4099d..a34d27e0 100644 --- a/Quake/Makefile +++ b/Quake/Makefile @@ -14,6 +14,10 @@ USE_CODEC_FLAC=0 USE_CODEC_MP3=1 USE_CODEC_VORBIS=1 USE_CODEC_OPUS=0 +# either mikmod (preferred) or modplug, not both +USE_CODEC_MIKMOD=0 +USE_CODEC_MODPLUG=0 +USE_CODEC_UMX=0 # which library to use for mp3 decoding: mad or mpg123 MP3LIB=mad @@ -157,6 +161,17 @@ ifeq ($(USE_CODEC_MP3),1) CFLAGS+= -DUSE_CODEC_MP3 CODECLIBS+= $(lib_mp3dec) endif +ifeq ($(USE_CODEC_MIKMOD),1) +CFLAGS+= -DUSE_CODEC_MIKMOD +CODECLIBS+= -lmikmod +endif +ifeq ($(USE_CODEC_MODPLUG),1) +CFLAGS+= -DUSE_CODEC_MODPLUG +CODECLIBS+= -lmodplug +endif +ifeq ($(USE_CODEC_UMX),1) +CFLAGS+= -DUSE_CODEC_UMX +endif COMMON_LIBS:= -lm -lGL @@ -187,7 +202,10 @@ MUSIC_OBJS:= bgmusic.o \ snd_wave.o \ snd_vorbis.o \ snd_opus.o \ - $(mp3_obj) + $(mp3_obj) \ + snd_mikmod.o \ + snd_modplug.o \ + snd_umx.o COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS) SYSOBJ_SND := snd_sdl.o SYSOBJ_CDA := cd_sdl.o diff --git a/Quake/Makefile.darwin b/Quake/Makefile.darwin index c66c85a5..6e2ef86d 100644 --- a/Quake/Makefile.darwin +++ b/Quake/Makefile.darwin @@ -15,6 +15,10 @@ USE_CODEC_FLAC=1 USE_CODEC_MP3=1 USE_CODEC_VORBIS=1 USE_CODEC_OPUS=1 +# either mikmod (preferred) or modplug, not both +USE_CODEC_MIKMOD=0 +USE_CODEC_MODPLUG=0 +USE_CODEC_UMX=0 # which library to use for mp3 decoding: mad or mpg123 MP3LIB=mad @@ -149,6 +153,21 @@ CODEC_INC = -I../MacOSX/codecs/include CODEC_LINK= -L../MacOSX/codecs/lib CODECLIBS+= $(lib_mp3dec) endif +ifeq ($(USE_CODEC_MIKMOD),1) +CFLAGS+= -DUSE_CODEC_MIKMOD +CODEC_INC = -I../MacOSX/codecs/include +CODEC_LINK= -L../MacOSX/codecs/lib +CODECLIBS+= -lmikmod +endif +ifeq ($(USE_CODEC_MODPLUG),1) +CFLAGS+= -DUSE_CODEC_MODPLUG +CODEC_INC = -I../MacOSX/codecs/include +CODEC_LINK= -L../MacOSX/codecs/lib +CODECLIBS+= -lmodplug +endif +ifeq ($(USE_CODEC_UMX),1) +CFLAGS+= -DUSE_CODEC_UMX +endif CFLAGS+= $(CODEC_INC) COMMON_LIBS:= -Wl,-framework,IOKit -Wl,-framework,OpenGL @@ -184,7 +203,10 @@ MUSIC_OBJS:= bgmusic.o \ snd_wave.o \ snd_vorbis.o \ snd_opus.o \ - $(mp3_obj) + $(mp3_obj) \ + snd_mikmod.o \ + snd_modplug.o \ + snd_umx.o COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS) SYSOBJ_SND := snd_sdl.o SYSOBJ_CDA := cd_sdl.o diff --git a/Quake/Makefile.w32 b/Quake/Makefile.w32 index 521ddaaf..3e302ad2 100644 --- a/Quake/Makefile.w32 +++ b/Quake/Makefile.w32 @@ -15,6 +15,10 @@ USE_CODEC_FLAC=0 USE_CODEC_MP3=1 USE_CODEC_VORBIS=1 USE_CODEC_OPUS=0 +# either mikmod (preferred) or modplug, not both +USE_CODEC_MIKMOD=0 +USE_CODEC_MODPLUG=0 +USE_CODEC_UMX=0 # which library to use for mp3 decoding: mad or mpg123 MP3LIB=mad @@ -155,6 +159,21 @@ CODEC_INC = -I../Windows/codecs/include CODEC_LINK= -L../Windows/codecs/x86 CODECLIBS+= $(lib_mp3dec) endif +ifeq ($(USE_CODEC_MIKMOD),1) +CFLAGS+= -DUSE_CODEC_MIKMOD +CODEC_INC = -I../Windows/codecs/include +CODEC_LINK= -L../Windows/codecs/x86 +CODECLIBS+= -lmikmod +endif +ifeq ($(USE_CODEC_MODPLUG),1) +CFLAGS+= -DUSE_CODEC_MODPLUG +CODEC_INC = -I../Windows/codecs/include +CODEC_LINK= -L../Windows/codecs/x86 +CODECLIBS+= -lmodplug +endif +ifeq ($(USE_CODEC_UMX),1) +CFLAGS+= -DUSE_CODEC_UMX +endif CFLAGS+= $(CODEC_INC) COMMON_LIBS:= -lm -lopengl32 @@ -188,7 +207,10 @@ MUSIC_OBJS:= bgmusic.o \ snd_wave.o \ snd_vorbis.o \ snd_opus.o \ - $(mp3_obj) + $(mp3_obj) \ + snd_mikmod.o \ + snd_modplug.o \ + snd_umx.o COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS) SYSOBJ_SND := snd_sdl.o SYSOBJ_CDA := cd_sdl.o diff --git a/Quake/Makefile.w64 b/Quake/Makefile.w64 index 6f822c86..a937eb71 100644 --- a/Quake/Makefile.w64 +++ b/Quake/Makefile.w64 @@ -15,6 +15,10 @@ USE_CODEC_FLAC=0 USE_CODEC_MP3=1 USE_CODEC_VORBIS=1 USE_CODEC_OPUS=0 +# either mikmod (preferred) or modplug, not both +USE_CODEC_MIKMOD=0 +USE_CODEC_MODPLUG=0 +USE_CODEC_UMX=0 # which library to use for mp3 decoding: mad or mpg123 MP3LIB=mad @@ -155,6 +159,21 @@ CODEC_INC = -I../Windows/codecs/include CODEC_LINK= -L../Windows/codecs/x64 CODECLIBS+= $(lib_mp3dec) endif +ifeq ($(USE_CODEC_MIKMOD),1) +CFLAGS+= -DUSE_CODEC_MIKMOD +CODEC_INC = -I../Windows/codecs/include +CODEC_LINK= -L../Windows/codecs/x64 +CODECLIBS+= -lmikmod +endif +ifeq ($(USE_CODEC_MODPLUG),1) +CFLAGS+= -DUSE_CODEC_MODPLUG +CODEC_INC = -I../Windows/codecs/include +CODEC_LINK= -L../Windows/codecs/x64 +CODECLIBS+= -lmodplug +endif +ifeq ($(USE_CODEC_UMX),1) +CFLAGS+= -DUSE_CODEC_UMX +endif CFLAGS+= $(CODEC_INC) COMMON_LIBS:= -lm -lopengl32 @@ -188,7 +207,10 @@ MUSIC_OBJS:= bgmusic.o \ snd_wave.o \ snd_vorbis.o \ snd_opus.o \ - $(mp3_obj) + $(mp3_obj) \ + snd_mikmod.o \ + snd_modplug.o \ + snd_umx.o COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS) SYSOBJ_SND := snd_sdl.o SYSOBJ_CDA := cd_sdl.o diff --git a/Quake/bgmusic.c b/Quake/bgmusic.c index 7763afb8..c259d1cf 100644 --- a/Quake/bgmusic.c +++ b/Quake/bgmusic.c @@ -58,6 +58,11 @@ static music_handler_t wanted_handlers[] = { CODECTYPE_MP3, BGM_STREAMER, -1, "mp3", MUSIC_DIRNAME, NULL }, { CODECTYPE_FLAC, BGM_STREAMER, -1, "flac", MUSIC_DIRNAME, NULL }, { CODECTYPE_WAV, BGM_STREAMER, -1, "wav", MUSIC_DIRNAME, NULL }, + { CODECTYPE_MOD, BGM_STREAMER, -1, "it", MUSIC_DIRNAME, NULL }, + { CODECTYPE_MOD, BGM_STREAMER, -1, "s3m", MUSIC_DIRNAME, NULL }, + { CODECTYPE_MOD, BGM_STREAMER, -1, "xm", MUSIC_DIRNAME, NULL }, + { CODECTYPE_MOD, BGM_STREAMER, -1, "mod", MUSIC_DIRNAME, NULL }, + { CODECTYPE_UMX, BGM_STREAMER, -1, "umx", MUSIC_DIRNAME, NULL }, { CODECTYPE_NONE, BGM_NONE, -1, NULL, NULL, NULL } }; diff --git a/Quake/common.c b/Quake/common.c index 8410bcfb..ecb91663 100644 --- a/Quake/common.c +++ b/Quake/common.c @@ -2008,24 +2008,19 @@ size_t FS_fread(void *ptr, size_t size, size_t nmemb, fshandle_t *fh) long bytes_read; size_t nmemb_read; - if (!ptr) - { + if (!fh) { + errno = EBADF; + return 0; + } + if (!ptr) { errno = EFAULT; return 0; } - - if (!(size && nmemb)) /* not an error, just zero bytes wanted */ - { + if (!size || !nmemb) { /* no error, just zero bytes wanted */ errno = 0; return 0; } - if (!fh) - { - errno = EBADF; - return 0; - } - byte_size = nmemb * size; if (byte_size > fh->length - fh->pos) /* just read to end */ byte_size = fh->length - fh->pos; @@ -2049,8 +2044,7 @@ int FS_fseek(fshandle_t *fh, long offset, int whence) * the quake/hexen2 file system is 32 bits, anyway. */ int ret; - if (!fh) - { + if (!fh) { errno = EBADF; return -1; } @@ -2072,8 +2066,7 @@ int FS_fseek(fshandle_t *fh, long offset, int whence) return -1; } - if (offset < 0) - { + if (offset < 0) { errno = EINVAL; return -1; } @@ -2091,32 +2084,25 @@ int FS_fseek(fshandle_t *fh, long offset, int whence) int FS_fclose(fshandle_t *fh) { - if (!fh) - { + if (!fh) { errno = EBADF; return -1; } - return fclose(fh->file); } long FS_ftell(fshandle_t *fh) { - if (!fh) - { + if (!fh) { errno = EBADF; return -1; } - - /* send the relative file position */ return fh->pos; } void FS_rewind(fshandle_t *fh) { - if (!fh) - return; - + if (!fh) return; clearerr(fh->file); fseek(fh->file, fh->start, SEEK_SET); fh->pos = 0; @@ -2124,6 +2110,10 @@ void FS_rewind(fshandle_t *fh) int FS_feof(fshandle_t *fh) { + if (!fh) { + errno = EBADF; + return -1; + } if (fh->pos >= fh->length) return -1; return 0; @@ -2131,6 +2121,10 @@ int FS_feof(fshandle_t *fh) int FS_ferror(fshandle_t *fh) { + if (!fh) { + errno = EBADF; + return -1; + } return ferror(fh->file); } @@ -2150,3 +2144,12 @@ char *FS_fgets(char *s, int size, fshandle_t *fh) return ret; } +long FS_filelength (fshandle_t *fh) +{ + if (!fh) { + errno = EBADF; + return -1; + } + return fh->length; +} + diff --git a/Quake/common.h b/Quake/common.h index 89553ace..0ee2f41c 100644 --- a/Quake/common.h +++ b/Quake/common.h @@ -249,6 +249,7 @@ int FS_feof(fshandle_t *fh); int FS_ferror(fshandle_t *fh); int FS_fclose(fshandle_t *fh); char *FS_fgets(char *s, int size, fshandle_t *fh); +long FS_filelength (fshandle_t *fh); extern struct cvar_s registered; diff --git a/Quake/snd_codec.c b/Quake/snd_codec.c index abfe63cf..ea4262b2 100644 --- a/Quake/snd_codec.c +++ b/Quake/snd_codec.c @@ -28,6 +28,9 @@ #include "snd_codeci.h" /* headers for individual codecs */ +#include "snd_mikmod.h" +#include "snd_modplug.h" +#include "snd_umx.h" #include "snd_wave.h" #include "snd_flac.h" #include "snd_mp3.h" @@ -60,6 +63,15 @@ void S_CodecInit (void) /* Register in the inverse order * of codec choice preference: */ +#ifdef USE_CODEC_UMX + S_CodecRegister(&umx_codec); +#endif +#ifdef USE_CODEC_MODPLUG + S_CodecRegister(&modplug_codec); +#endif +#ifdef USE_CODEC_MIKMOD + S_CodecRegister(&mikmod_codec); +#endif #ifdef USE_CODEC_WAVE S_CodecRegister(&wav_codec); #endif @@ -75,6 +87,7 @@ void S_CodecInit (void) #ifdef USE_CODEC_OPUS S_CodecRegister(&opus_codec); #endif + codec = codecs; while (codec) { @@ -127,9 +140,12 @@ snd_stream_t *S_CodecOpenStreamType (const char *filename, unsigned int type) Con_Printf("Unknown type for %s\n", filename); return NULL; } - stream = codec->codec_open(filename); - if (stream) - stream->status = STREAM_PLAY; + stream = S_CodecUtilOpen(filename, codec); + if (stream) { + if (codec->codec_open(stream)) + stream->status = STREAM_PLAY; + else S_CodecUtilClose(&stream); + } return stream; } @@ -158,9 +174,12 @@ snd_stream_t *S_CodecOpenStreamExt (const char *filename) Con_Printf("Unknown extension for %s\n", filename); return NULL; } - stream = codec->codec_open(filename); - if (stream) - stream->status = STREAM_PLAY; + stream = S_CodecUtilOpen(filename, codec); + if (stream) { + if (codec->codec_open(stream)) + stream->status = STREAM_PLAY; + else S_CodecUtilClose(&stream); + } return stream; } @@ -179,11 +198,13 @@ snd_stream_t *S_CodecOpenStreamAny (const char *filename) while (codec) { q_snprintf(tmp, sizeof(tmp), "%s.%s", filename, codec->ext); - stream = codec->codec_open(tmp); - if (stream) - { - stream->status = STREAM_PLAY; - return stream; + stream = S_CodecUtilOpen(tmp, codec); + if (stream) { + if (codec->codec_open(stream)) { + stream->status = STREAM_PLAY; + return stream; + } + S_CodecUtilClose(&stream); } codec = codec->next; } @@ -204,13 +225,31 @@ snd_stream_t *S_CodecOpenStreamAny (const char *filename) Con_Printf("Unknown extension for %s\n", filename); return NULL; } - stream = codec->codec_open(filename); - if (stream) - stream->status = STREAM_PLAY; + stream = S_CodecUtilOpen(filename, codec); + if (stream) { + if (codec->codec_open(stream)) + stream->status = STREAM_PLAY; + else S_CodecUtilClose(&stream); + } return stream; } } +qboolean S_CodecForwardStream (snd_stream_t *stream, unsigned int type) +{ + snd_codec_t *codec = codecs; + + while (codec) + { + if (type == codec->type) + break; + codec = codec->next; + } + if (!codec) return false; + stream->codec = codec; + return codec->codec_open(stream); +} + void S_CodecCloseStream (snd_stream_t *stream) { stream->status = STREAM_NONE; @@ -253,6 +292,8 @@ snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec) stream->fh.pos = 0; stream->fh.length = length; stream->fh.pak = stream->pak = pak; + q_strlcpy(stream->name, filename, MAX_QPATH); + return stream; } diff --git a/Quake/snd_codec.h b/Quake/snd_codec.h index c38d7bf3..657b0b2a 100644 --- a/Quake/snd_codec.h +++ b/Quake/snd_codec.h @@ -50,6 +50,7 @@ typedef struct snd_stream_s { fshandle_t fh; qboolean pak; + char name[MAX_QPATH]; /* name of the source file */ snd_info_t info; stream_status_t status; snd_codec_t *codec; /* codec handling this stream */ @@ -90,6 +91,7 @@ void S_CodecUtilClose(snd_stream_t **stream); #define CODECTYPE_MP3 (1U << 4) #define CODECTYPE_VORBIS (1U << 5) #define CODECTYPE_OPUS (1U << 6) +#define CODECTYPE_UMX (1U << 7) #define CODECTYPE_WAVE CODECTYPE_WAV #define CODECTYPE_MIDI CODECTYPE_MID diff --git a/Quake/snd_codeci.h b/Quake/snd_codeci.h index 32bf666a..feedb61c 100644 --- a/Quake/snd_codeci.h +++ b/Quake/snd_codeci.h @@ -29,7 +29,7 @@ /* Codec internals */ typedef qboolean (*CODEC_INIT)(void); typedef void (*CODEC_SHUTDOWN)(void); -typedef snd_stream_t *(*CODEC_OPEN)(const char *filename); +typedef qboolean (*CODEC_OPEN)(snd_stream_t *stream); typedef int (*CODEC_READ)(snd_stream_t *stream, int bytes, void *buffer); typedef int (*CODEC_REWIND)(snd_stream_t *stream); typedef void (*CODEC_CLOSE)(snd_stream_t *stream); @@ -48,5 +48,8 @@ struct snd_codec_s snd_codec_t *next; }; +qboolean S_CodecForwardStream (snd_stream_t *stream, unsigned int type); + /* Forward a stream to another codec of 'type' type. */ + #endif /* _SND_CODECI_H_ */ diff --git a/Quake/snd_flac.c b/Quake/snd_flac.c index d81f3d36..8101c5e8 100644 --- a/Quake/snd_flac.c +++ b/Quake/snd_flac.c @@ -126,7 +126,7 @@ flac_length_func (const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) { flacfile_t *ff = (flacfile_t *) client_data; - *stream_length = (FLAC__uint64) ff->file->length; + *stream_length = (FLAC__uint64) FS_filelength (ff->file); return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; } @@ -235,16 +235,11 @@ static void S_FLAC_CodecShutdown (void) { } -static snd_stream_t *S_FLAC_CodecOpenStream (const char *filename) +static qboolean S_FLAC_CodecOpenStream (snd_stream_t *stream) { - snd_stream_t *stream; flacfile_t *ff; int rc; - stream = S_CodecUtilOpen(filename, &flac_codec); - if (!stream) - return NULL; - ff = (flacfile_t *) Z_Malloc(sizeof(flacfile_t)); ff->decoder = FLAC__stream_decoder_new (); @@ -293,28 +288,29 @@ static snd_stream_t *S_FLAC_CodecOpenStream (const char *filename) { rc = FLAC__stream_decoder_get_state(ff->decoder); Con_Printf("%s not a valid flac file? (decoder state %i)\n", - filename, rc); + stream->name, rc); goto _fail; } if (ff->info->dataofs < 0) { - Con_Printf("%s has no STREAMINFO\n", filename); + Con_Printf("%s has no STREAMINFO\n", stream->name); goto _fail; } if (ff->info->bits != 8 && ff->info->bits != 16) { - Con_Printf("%s is not 8 or 16 bit\n", filename); + Con_Printf("%s is not 8 or 16 bit\n", stream->name); goto _fail; } if (ff->info->channels != 1 && ff->info->channels != 2) { Con_Printf("Unsupported number of channels %d in %s\n", - ff->info->channels, filename); + ff->info->channels, stream->name); goto _fail; } - return stream; + return true; + _fail: if (ff->decoder) { @@ -322,8 +318,7 @@ _fail: FLAC__stream_decoder_delete (ff->decoder); } Z_Free(ff); - S_CodecUtilClose(&stream); - return NULL; + return false; } static int S_FLAC_CodecReadStream (snd_stream_t *stream, int len, void *buffer) diff --git a/Quake/snd_mikmod.c b/Quake/snd_mikmod.c new file mode 100644 index 00000000..55c9605f --- /dev/null +++ b/Quake/snd_mikmod.c @@ -0,0 +1,199 @@ +/* + * tracker music (module file) decoding support using libmikmod + * + * Copyright (C) 2013 O.Sezer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "quakedef.h" + +#if defined(USE_CODEC_MIKMOD) +#include "snd_codec.h" +#include "snd_codeci.h" +#include "snd_mikmod.h" +#include + +#ifndef DMODE_SIMDMIXER +#define DMODE_SIMDMIXER 0x0800 /* enable SIMD mixing */ +#endif + +typedef struct _mik_priv { +/* struct MREADER in libmikmod <= 3.2.0-beta2 + * doesn't have iobase members. adding them here + * so that if we compile against 3.2.0-beta2, we + * can still run OK against 3.2.0b3 and newer. */ + struct MREADER reader; + long iobase, prev_iobase; + fshandle_t *fh; + MODULE *module; +} mik_priv_t; + +static BOOL MIK_Seek (MREADER *r, long ofs, int whence) +{ + return FS_fseek (((mik_priv_t *)r)->fh, ofs, whence); +} + +static long MIK_Tell (MREADER *r) +{ + return FS_ftell (((mik_priv_t *)r)->fh); +} + +static BOOL MIK_Read (MREADER *r, void *ptr, size_t siz) +{ + return !!FS_fread(ptr, siz, 1, ((mik_priv_t *)r)->fh); +} + +static int MIK_Get (MREADER *r) +{ + unsigned char c; + if (FS_feof(((mik_priv_t *)r)->fh)) + return EOF; + if (FS_fread(&c, 1, 1, ((mik_priv_t *)r)->fh)) + return (int)c; + return EOF; +} + +static BOOL MIK_Eof (MREADER *r) +{ + return FS_feof(((mik_priv_t *)r)->fh); +} + +static qboolean S_MIKMOD_CodecInitialize (void) +{ + if (mikmod_codec.initialized) + return true; + + /* set mode flags to only we like: */ + md_mode = 0; + if ((shm->samplebits / 8) == 2) + md_mode |= DMODE_16BITS; + if (shm->channels == 2) + md_mode |= DMODE_STEREO; + md_mode |= DMODE_SOFT_MUSIC; /* this is a software-only mixer */ + md_mode |= DMODE_HQMIXER; /* high-quality mixer is OK */ + + /* md_mixfreq is UWORD, so something like 96000 isn't OK */ + md_mixfreq = (shm->speed < 65536)? shm->speed : 48000; + + /* keeping md_device as 0 which is default (auto-detect: we + * only register drv_nos, and it will be the only one found.) + * md_pansep (stereo channels separation) default 128 is OK. + * no reverbation (md_reverb 0 (up to 15)) is OK. + * md_musicvolume and md_sndfxvolume defaults are 128: OK. + * just tone down overall volume md_volume from 128 to 96: */ + md_volume = 96; + + MikMod_RegisterDriver(&drv_nos); + MikMod_RegisterAllLoaders(); + if (MikMod_Init(NULL)) + { + Con_DPrintf("Could not initialize MikMod: %s\n", MikMod_strerror(MikMod_errno)); + return false; + } + + /* this can't get set with drv_nos, but whatever, be safe: */ + md_mode &= ~DMODE_SIMDMIXER; /* SIMD mixer is buggy when combined with HQMIXER */ + + mikmod_codec.initialized = true; + return true; +} + +static void S_MIKMOD_CodecShutdown (void) +{ + if (mikmod_codec.initialized) + { + mikmod_codec.initialized = false; + MikMod_Exit(); + } +} + +static qboolean S_MIKMOD_CodecOpenStream (snd_stream_t *stream) +{ + mik_priv_t *priv; + + stream->priv = Z_Malloc(sizeof(mik_priv_t)); + priv = (mik_priv_t *) stream->priv; + priv->reader.Seek = MIK_Seek; + priv->reader.Tell = MIK_Tell; + priv->reader.Read = MIK_Read; + priv->reader.Get = MIK_Get; + priv->reader.Eof = MIK_Eof; + priv->fh = &stream->fh; + + priv->module = Player_LoadGeneric((MREADER *)stream->priv, 64, 0); + if (!priv->module) + { + Con_DPrintf("Could not load module: %s\n", MikMod_strerror(MikMod_errno)); + Z_Free(stream->priv); + return false; + } + + /* keep default values of fadeout (0: don't fade out volume during when last + * position of the module is being played), extspd (1: do process Protracker + * extended speed effect), panflag (1: do process panning effects), wrap (0: + * don't wrap to restart position when module is finished) are OK with us as + * set internally by libmikmod::Player_Init(). just change the loop setting + * to 0, i.e. don't process in-module loops: */ + priv->module->loop = 0; + Player_Start(priv->module); + + stream->info.rate = md_mixfreq; + stream->info.bits = (md_mode & DMODE_16BITS)? 16: 8; + stream->info.width = stream->info.bits / 8; + stream->info.channels = (md_mode & DMODE_STEREO)? 2 : 1; +/* Con_DPrintf("Playing %s (%d chn)\n", priv->module->songname, priv->module->numchn);*/ + + return true; +} + +static int S_MIKMOD_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) +{ + if (!Player_Active()) + return 0; + return (int) VC_WriteBytes((SBYTE *)buffer, bytes); +} + +static void S_MIKMOD_CodecCloseStream (snd_stream_t *stream) +{ + Player_Stop(); + Player_Free(((mik_priv_t *)stream->priv)->module); + Z_Free(stream->priv); + S_CodecUtilClose(&stream); +} + +static int S_MIKMOD_CodecRewindStream (snd_stream_t *stream) +{ + Player_SetPosition (0); + return 0; +} + +snd_codec_t mikmod_codec = +{ + CODECTYPE_MOD, + false, + "s3m", + S_MIKMOD_CodecInitialize, + S_MIKMOD_CodecShutdown, + S_MIKMOD_CodecOpenStream, + S_MIKMOD_CodecReadStream, + S_MIKMOD_CodecRewindStream, + S_MIKMOD_CodecCloseStream, + NULL +}; + +#endif /* USE_CODEC_MIKMOD */ + diff --git a/Quake/snd_mikmod.h b/Quake/snd_mikmod.h new file mode 100644 index 00000000..9f0338bc --- /dev/null +++ b/Quake/snd_mikmod.h @@ -0,0 +1,13 @@ +/* module tracker decoding support using libmikmod */ + +#if !defined(_SND_MIKMOD_H_) +#define _SND_MIKMOD_H_ + +#if defined(USE_CODEC_MIKMOD) + +extern snd_codec_t mikmod_codec; + +#endif /* USE_CODEC_MIKMOD */ + +#endif /* ! _SND_MIKMOD_H_ */ + diff --git a/Quake/snd_modplug.c b/Quake/snd_modplug.c new file mode 100644 index 00000000..1aaec66d --- /dev/null +++ b/Quake/snd_modplug.c @@ -0,0 +1,121 @@ +/* + * tracker music (module file) decoding support using libmodplug + * + * Copyright (C) 2013 O.Sezer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "quakedef.h" + +#if defined(USE_CODEC_MODPLUG) +#include "snd_codec.h" +#include "snd_codeci.h" +#include "snd_modplug.h" +#include + +static void S_MODPLUG_SetSettings (snd_stream_t *stream) +{ + ModPlug_Settings settings; + + ModPlug_GetSettings(&settings); + settings.mFlags = MODPLUG_ENABLE_OVERSAMPLING; + settings.mChannels = shm->channels; + settings.mBits = shm->samplebits; + settings.mFrequency = shm->speed; + settings.mResamplingMode = MODPLUG_RESAMPLE_SPLINE;/*MODPLUG_RESAMPLE_FIR*/ + settings.mLoopCount = 0; + ModPlug_SetSettings(&settings); + + if (stream) { + stream->info.rate = shm->speed; + stream->info.bits = shm->samplebits; + stream->info.width = stream->info.bits / 8; + stream->info.channels = shm->channels; + } +} + +static qboolean S_MODPLUG_CodecInitialize (void) +{ + return true; +} + +static void S_MODPLUG_CodecShutdown (void) +{ +} + +static qboolean S_MODPLUG_CodecOpenStream (snd_stream_t *stream) +{ +/* need to load the whole file into memory and pass it to libmodplug */ + byte *moddata; + long len; + int mark; + + len = FS_filelength (&stream->fh); + mark = Hunk_LowMark(); + moddata = (byte *) Hunk_Alloc(len); + FS_fread(moddata, 1, len, &stream->fh); + + S_MODPLUG_SetSettings(stream); + stream->priv = ModPlug_Load(moddata, len); + Hunk_FreeToLowMark(mark); /* free original file data */ + if (!stream->priv) + { + Con_DPrintf("Could not load module %s\n", stream->name); + return false; + } + + ModPlug_Seek((ModPlugFile*)stream->priv, 0); +#if 0 + /* default volume (128) sounds rather low? */ + ModPlug_SetMasterVolume((ModPlugFile*)stream->priv, 384); /* 0-512 */ +#endif + return true; +} + +static int S_MODPLUG_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) +{ + return ModPlug_Read((ModPlugFile*)stream->priv, buffer, bytes); +} + +static void S_MODPLUG_CodecCloseStream (snd_stream_t *stream) +{ + ModPlug_Unload((ModPlugFile*)stream->priv); + S_CodecUtilClose(&stream); +} + +static int S_MODPLUG_CodecRewindStream (snd_stream_t *stream) +{ + ModPlug_Seek((ModPlugFile*)stream->priv, 0); + return 0; +} + +snd_codec_t modplug_codec = +{ + CODECTYPE_MOD, + true, /* always available. */ + "s3m", + S_MODPLUG_CodecInitialize, + S_MODPLUG_CodecShutdown, + S_MODPLUG_CodecOpenStream, + S_MODPLUG_CodecReadStream, + S_MODPLUG_CodecRewindStream, + S_MODPLUG_CodecCloseStream, + NULL +}; + +#endif /* USE_CODEC_MODPLUG */ + diff --git a/Quake/snd_modplug.h b/Quake/snd_modplug.h new file mode 100644 index 00000000..40f6397b --- /dev/null +++ b/Quake/snd_modplug.h @@ -0,0 +1,12 @@ +/* module tracker decoding support using libmodplug */ +#if !defined(_SND_MODPLUG_H_) +#define _SND_MODPLUG_H_ + +#if defined(USE_CODEC_MODPLUG) + +extern snd_codec_t modplug_codec; + +#endif /* USE_CODEC_MODPLUG */ + +#endif /* ! _SND_MODPLUG_H_ */ + diff --git a/Quake/snd_mp3.c b/Quake/snd_mp3.c index 2ee4e2c5..8a5348c6 100644 --- a/Quake/snd_mp3.c +++ b/Quake/snd_mp3.c @@ -491,49 +491,40 @@ static void S_MP3_CodecShutdown (void) { } -static snd_stream_t *S_MP3_CodecOpenStream (const char *filename) +static qboolean S_MP3_CodecOpenStream (snd_stream_t *stream) { - snd_stream_t *stream; int err; - stream = S_CodecUtilOpen(filename, &mp3_codec); - if (!stream) - return NULL; - #if 0 /*defined(CODECS_USE_ZONE)*/ stream->priv = Z_Malloc(sizeof(mp3_priv_t)); #else stream->priv = calloc(1, sizeof(mp3_priv_t)); if (!stream->priv) { - S_CodecUtilClose(&stream); Con_Printf("Insufficient memory for MP3 audio\n"); - return NULL; + return false; } #endif - err = mp3_startread(stream); if (err != 0) { - Con_Printf("%s is not a valid mp3 file\n", filename); + Con_Printf("%s is not a valid mp3 file\n", stream->name); } else if (stream->info.channels != 1 && stream->info.channels != 2) { Con_Printf("Unsupported number of channels %d in %s\n", - stream->info.channels, filename); + stream->info.channels, stream->name); } else { - return stream; + return true; } - #if 0 /*defined(CODECS_USE_ZONE)*/ Z_Free(stream->priv); #else free(stream->priv); #endif - S_CodecUtilClose(&stream); - return NULL; + return false; } static int S_MP3_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) diff --git a/Quake/snd_mpg123.c b/Quake/snd_mpg123.c index c34c0048..159e190b 100644 --- a/Quake/snd_mpg123.c +++ b/Quake/snd_mpg123.c @@ -86,17 +86,12 @@ static void S_MP3_CodecShutdown (void) } } -static snd_stream_t *S_MP3_CodecOpenStream (const char *filename) +static qboolean S_MP3_CodecOpenStream (snd_stream_t *stream) { - snd_stream_t *stream; long rate = 0; int encoding = 0, channels = 0; mp3_priv_t *priv = NULL; - stream = S_CodecUtilOpen(filename, &mp3_codec); - if (!stream) - return NULL; - stream->priv = Z_Malloc(sizeof(mp3_priv_t)); priv = (mp3_priv_t *) stream->priv; priv->handle = mpg123_new(NULL, NULL); @@ -117,7 +112,7 @@ static snd_stream_t *S_MP3_CodecOpenStream (const char *filename) if (mpg123_getformat(priv->handle, &rate, &channels, &encoding) != MPG123_OK) { - Con_Printf("Unable to retrieve mpg123 format for %s\n", filename); + Con_Printf("Unable to retrieve mpg123 format for %s\n", stream->name); goto _fail; } @@ -130,7 +125,7 @@ static snd_stream_t *S_MP3_CodecOpenStream (const char *filename) stream->info.channels = 2; break; default: - Con_Printf("Unsupported number of channels %d in %s\n", channels, filename); + Con_Printf("Unsupported number of channels %d in %s\n", channels, stream->name); goto _fail; } @@ -162,13 +157,13 @@ static snd_stream_t *S_MP3_CodecOpenStream (const char *filename) } if (mpg123_format_support(priv->handle, rate, encoding) == 0) { - Con_Printf("Unsupported format for %s\n", filename); + Con_Printf("Unsupported format for %s\n", stream->name); goto _fail; } mpg123_format_none(priv->handle); mpg123_format(priv->handle, rate, channels, encoding); - return stream; + return true; _fail: if (priv) { @@ -178,8 +173,7 @@ _fail: mpg123_delete(priv->handle); Z_Free(stream->priv); } - S_CodecUtilClose(&stream); - return NULL; + return false; } static int S_MP3_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) diff --git a/Quake/snd_opus.c b/Quake/snd_opus.c index 09282c19..a2148e9f 100644 --- a/Quake/snd_opus.c +++ b/Quake/snd_opus.c @@ -83,23 +83,18 @@ static void S_OPUS_CodecShutdown (void) { } -static snd_stream_t *S_OPUS_CodecOpenStream (const char *filename) +static qboolean S_OPUS_CodecOpenStream (snd_stream_t *stream) { - snd_stream_t *stream; OggOpusFile *opFile; const OpusHead *op_info; long numstreams; int res; - stream = S_CodecUtilOpen(filename, &opus_codec); - if (!stream) - return NULL; - opFile = op_open_callbacks(&stream->fh, &opc_qfs, NULL, 0, &res); if (!opFile) { Con_Printf("%s is not a valid Opus file (error %i).\n", - filename, res); + stream->name, res); goto _fail; } @@ -107,14 +102,14 @@ static snd_stream_t *S_OPUS_CodecOpenStream (const char *filename) if (!op_seekable(opFile)) { - Con_Printf("Opus stream %s not seekable.\n", filename); + Con_Printf("Opus stream %s not seekable.\n", stream->name); goto _fail; } op_info = op_head(opFile, -1); if (!op_info) { - Con_Printf("Unable to get stream information for %s.\n", filename); + Con_Printf("Unable to get stream information for %s.\n", stream->name); goto _fail; } @@ -123,14 +118,14 @@ static snd_stream_t *S_OPUS_CodecOpenStream (const char *filename) if (numstreams != 1) { Con_Printf("More than one (%ld) stream in %s\n", - (long)op_info->stream_count, filename); + (long)op_info->stream_count, stream->name); goto _fail; } if (op_info->channel_count != 1 && op_info->channel_count != 2) { Con_Printf("Unsupported number of channels %d in %s\n", - op_info->channel_count, filename); + op_info->channel_count, stream->name); goto _fail; } @@ -144,12 +139,11 @@ static snd_stream_t *S_OPUS_CodecOpenStream (const char *filename) stream->info.bits = 16; stream->info.width = 2; - return stream; + return true; _fail: if (opFile) op_free(opFile); - S_CodecUtilClose(&stream); - return NULL; + return false; } static int S_OPUS_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) diff --git a/Quake/snd_umx.c b/Quake/snd_umx.c new file mode 100644 index 00000000..872bbe75 --- /dev/null +++ b/Quake/snd_umx.c @@ -0,0 +1,387 @@ +/* + * Unreal UMX container support. UMX parsing is based on Unreal Media + * Ripper (UMR) v0.3 by Andy Ward , with additional + * updates by O. Sezer - see git repo at https://github.com/sezero/umr/ + * + * Copyright (C) 2013 O.Sezer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "quakedef.h" + +#if defined(USE_CODEC_UMX) +#include "snd_codec.h" +#include "snd_codeci.h" +#include "snd_umx.h" + +#define UPKG_HDR_TAG 0x9e2a83c1 +#pragma pack(1) +struct upkg_hdr { + uint32_t tag; /* UPKG_HDR_TAG */ + int32_t file_version, /* 61 for original unreal */ + pkg_flags, /* bitflags - none needed */ + name_count, /* number of names in name table (>= 0) */ + name_offset, /* offset to name table (>= 0) */ + export_count, /* num. exports in export table (>= 0) */ + export_offset, /* offset to export table (>= 0) */ + import_count, /* num. imports in export table (>= 0) */ + import_offset; /* offset to import table (>= 0) */ + + /* number of GUIDs in heritage table (>= 1) and table's offset: + * only with versions < 68. */ + int32_t heritage_count, heritage_offset; +#if 0 + /* with versions >= 68: a GUID, a dword for generation count + * and export_count and name_count dwords for each generation: */ + uint32_t guid[4]; + int32_t generation_count; + struct _genhist { + int32_t export_count, + name_count; + } genhist[0/* generation_count */]; +#endif +}; +#pragma pack() + +/* read Little Endian data in an endian-neutral way */ +#define READ_INT32(b) ((b)[0] | ((b)[1] << 8) | ((b)[2] << 16) | ((b)[3] << 24)) + +#define UMUSIC_IT 0 +#define UMUSIC_S3M 1 +#define UMUSIC_XM 2 +#define UMUSIC_MOD 3 +#define UMUSIC_WAV 4 +#define UMUSIC_MP2 5 + +static const char *mustype[] = { + "IT", "S3M", "XM", "MOD", + "WAV", "MP2", NULL +}; + +/* decode an FCompactIndex. original documentation by Tim Sweeney + * was at http://unreal.epicgames.com/Packages.htm + */ +static int32_t get_fci (const char *in, int *pos) +{ + int32_t a; + int size; + + size = 1; + a = in[0] & 0x3f; + + if (in[0] & 0x40) { + size++; + a |= (in[1] & 0x7f) << 6; + + if (in[1] & 0x80) { + size++; + a |= (in[2] & 0x7f) << 13; + + if (in[2] & 0x80) { + size++; + a |= (in[3] & 0x7f) << 20; + + if (in[3] & 0x80) { + size++; + a |= (in[4] & 0x3f) << 27; + } + } + } + } + + if (in[0] & 0x80) + a = -a; + + *pos += size; + + return a; +} + +static int get_objtype (fshandle_t *f, int32_t ofs, int type) +{ + char sig[16]; +_retry: + FS_fseek(f, ofs, SEEK_SET); + FS_fread(sig, 16, 1, f); + if (type == UMUSIC_IT) { + if (memcmp(sig, "IMPM", 4) == 0) + return UMUSIC_IT; + return -1; + } + if (type == UMUSIC_XM) { + if (memcmp(sig, "Extended Module:", 16) == 0) + return UMUSIC_XM; + return -1; + } + if (type == UMUSIC_MP2) { + unsigned char *p = (unsigned char *)sig; + uint16_t u = ((p[0] << 8) | p[1]) & 0xFFFE; + if (u == 0xFFFC || u == 0xFFF4) + return UMUSIC_MP2; + return -1; + } + if (type == UMUSIC_WAV) { + if (memcmp(sig, "RIFF", 4) == 0 && memcmp(&sig[8], "WAVE", 4) == 0) + return UMUSIC_WAV; + return -1; + } + + FS_fseek(f, ofs + 44, SEEK_SET); + FS_fread(sig, 4, 1, f); + if (type == UMUSIC_S3M) { + if (memcmp(sig, "SCRM", 4) == 0) + return UMUSIC_S3M; + /*return -1;*/ + /* SpaceMarines.umx and Starseek.umx from Return to NaPali + * report as "s3m" whereas the actual music format is "it" */ + type = UMUSIC_IT; + goto _retry; + } + + FS_fseek(f, ofs + 1080, SEEK_SET); + FS_fread(sig, 4, 1, f); + if (type == UMUSIC_MOD) { + if (memcmp(sig, "M.K.", 4) == 0 || memcmp(sig, "M!K!", 4) == 0) + return UMUSIC_MOD; + return -1; + } + + return -1; +} + +static int read_export (fshandle_t *f, const struct upkg_hdr *hdr, + int32_t *ofs, int32_t *objsize) +{ + char buf[40]; + int idx = 0, t; + + FS_fseek(f, *ofs, SEEK_SET); + if (FS_fread(buf, 4, 10, f) < 10) + return -1; + + get_fci(&buf[idx], &idx); /* skip junk */ + t = get_fci(&buf[idx], &idx); /* type_name */ + if (hdr->file_version > 61) idx += 4; /* skip export size */ + *objsize = get_fci(&buf[idx], &idx); + *ofs += idx; /* offset for real data */ + + return t; /* return type_name index */ +} + +static int read_typname(fshandle_t *f, const struct upkg_hdr *hdr, + int idx, char *out) +{ + int i, s; + long l; + char buf[64]; + + if (idx >= hdr->name_count) return -1; + for (i = 0, l = 0; i <= idx; i++) { + FS_fseek(f, hdr->name_offset + l, SEEK_SET); + FS_fread(buf, 1, 64, f); + if (hdr->file_version >= 64) { + s = *(signed char *)buf; /* numchars *including* terminator */ + if (s <= 0 || s >= 64) return -1; + l += s + 5; /* 1 for buf[0], 4 for int32_t name_flags */ + } else { + buf[63] = 0; + l += (long)strlen(buf); + l += 5; /* 1 for terminator, 4 for int32_t name_flags */ + } + } + + strcpy(out, (hdr->file_version >= 64)? &buf[1] : buf); + return 0; +} + +static int probe_umx (fshandle_t *f, const struct upkg_hdr *hdr, + int32_t *ofs, int32_t *objsize) +{ + int i, idx, t; + int32_t s, pos; + long fsiz; + char buf[64]; + + idx = 0; + fsiz = f->length; + + /* Find the offset and size of the first IT, S3M or XM + * by parsing the exports table. The umx files should + * have only one export. Kran32.umx from Unreal has two, + * but both pointing to the same music. */ + if (hdr->export_offset >= fsiz) return -1; + memset(buf, 0, 64); + FS_fseek(f, hdr->export_offset, SEEK_SET); + FS_fread(buf, 1, 64, f); + + get_fci(&buf[idx], &idx); /* skip class_index */ + idx += 4; /* skip int32 package_index */ + get_fci(&buf[idx], &idx); /* skip super_index */ + get_fci(&buf[idx], &idx); /* skip object_name */ + idx += 4; /* skip int32 object_flags */ + + s = get_fci(&buf[idx], &idx); /* get serial_size */ + if (s <= 0) return -1; + pos = get_fci(&buf[idx],&idx); /* get serial_offset */ + if (pos < 0 || pos > fsiz - 40) return -1; + + if ((t = read_export(f, hdr, &pos, &s)) < 0) return -1; + if (s <= 0 || s > fsiz - pos) return -1; + + if (read_typname(f, hdr, t, buf) < 0) return -1; + for (i = 0; mustype[i] != NULL; i++) { + if (!strcasecmp(buf, mustype[i])) { + t = i; + break; + } + } + if (mustype[i] == NULL) return -1; + if ((t = get_objtype(f, pos, t)) < 0) return -1; + + *ofs = pos; + *objsize = s; + return t; +} + +static int32_t probe_header (void *header) +{ + struct upkg_hdr *hdr; + unsigned char *p; + uint32_t *swp; + int i; + + /* byte swap the header - all members are 32 bit LE values */ + p = (unsigned char *) header; + swp = (uint32_t *) header; + for (i = 0; i < (int)sizeof(struct upkg_hdr)/4; i++, p += 4) { + swp[i] = READ_INT32(p); + } + + hdr = (struct upkg_hdr *) header; + if (hdr->tag != UPKG_HDR_TAG) { + Con_DPrintf("Unknown header tag 0x%x\n", hdr->tag); + return -1; + } + if (hdr->name_count < 0 || + hdr->name_offset < 0 || + hdr->export_count < 0 || + hdr->export_offset < 0 || + hdr->import_count < 0 || + hdr->import_offset < 0 ) { + Con_DPrintf("Negative values in header\n"); + return -1; + } + switch (hdr->file_version) { + case 61:/* Unreal */ + case 62:/* Unreal Tournament */ + case 63:/* Return to NaPali */ + case 64:/* Unreal Tournament */ + case 66:/* Unreal Tournament */ + case 68:/* Unreal Tournament */ + case 69:/* Tactical Ops */ + case 75:/* Harry Potter and the Philosopher's Stone */ + case 76: /* mpeg layer II data */ + case 83:/* Mobile Forces */ + return 0; + } + + Con_DPrintf("Unknown upkg version %d\n", hdr->file_version); + return -1; +} + +static int process_upkg (fshandle_t *f, int32_t *ofs, int32_t *objsize) +{ + char header[64]; + + if (FS_fread(header, 1, 64, f) < 64) + return -1; + if (probe_header(header) < 0) + return -1; + + return probe_umx(f, (struct upkg_hdr *)header, ofs, objsize); +} + +static qboolean S_UMX_CodecInitialize (void) +{ + return true; +} + +static void S_UMX_CodecShutdown (void) +{ +} + +static qboolean S_UMX_CodecOpenStream (snd_stream_t *stream) +{ + int32_t ofs, size; + int type; + + type = process_upkg(&stream->fh, &ofs, &size); + if (type < 0) { + Con_DPrintf("%s: unrecognized umx\n", stream->name); + return false; + } + + Con_DPrintf("%s: %s data @ 0x%x, %d bytes\n", stream->name, mustype[type], ofs, size); + /* hack the fshandle_t start pos and length members so + * that only the relevant data is accessed from now on */ + stream->fh.start = ofs; + stream->fh.length = size; + FS_fseek(&stream->fh, 0, SEEK_SET); + + switch (type) { + case UMUSIC_IT: + case UMUSIC_S3M: + case UMUSIC_XM: + case UMUSIC_MOD: return S_CodecForwardStream(stream, CODECTYPE_MOD); + case UMUSIC_WAV: return S_CodecForwardStream(stream, CODECTYPE_WAV); + case UMUSIC_MP2: return S_CodecForwardStream(stream, CODECTYPE_MP3); + } + + return false; +} + +static int S_UMX_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) +{ + return -1; +} + +static void S_UMX_CodecCloseStream (snd_stream_t *stream) +{ + S_CodecUtilClose(&stream); +} + +static int S_UMX_CodecRewindStream (snd_stream_t *stream) +{ + return -1; +} + +snd_codec_t umx_codec = +{ + CODECTYPE_UMX, + true, /* always available. */ + "umx", + S_UMX_CodecInitialize, + S_UMX_CodecShutdown, + S_UMX_CodecOpenStream, + S_UMX_CodecReadStream, + S_UMX_CodecRewindStream, + S_UMX_CodecCloseStream, + NULL +}; + +#endif /* USE_CODEC_UMX */ + diff --git a/Quake/snd_umx.h b/Quake/snd_umx.h new file mode 100644 index 00000000..da3107d2 --- /dev/null +++ b/Quake/snd_umx.h @@ -0,0 +1,12 @@ +/* Unreal UMX format support */ +#if !defined(_SND_UMX_H_) +#define _SND_UMX_H_ + +#if defined(USE_CODEC_UMX) + +extern snd_codec_t umx_codec; + +#endif /* USE_CODEC_UMX */ + +#endif /* ! _SND_UMX_H_ */ + diff --git a/Quake/snd_vorbis.c b/Quake/snd_vorbis.c index c677ebc5..ed92d803 100644 --- a/Quake/snd_vorbis.c +++ b/Quake/snd_vorbis.c @@ -75,38 +75,33 @@ static void S_VORBIS_CodecShutdown (void) { } -static snd_stream_t *S_VORBIS_CodecOpenStream (const char *filename) +static qboolean S_VORBIS_CodecOpenStream (snd_stream_t *stream) { - snd_stream_t *stream; OggVorbis_File *ovFile; vorbis_info *ovf_info; long numstreams; int res; - stream = S_CodecUtilOpen(filename, &vorbis_codec); - if (!stream) - return NULL; - ovFile = (OggVorbis_File *) Z_Malloc(sizeof(OggVorbis_File)); stream->priv = ovFile; res = OV_OPEN_CALLBACKS(&stream->fh, ovFile, NULL, 0, ovc_qfs); if (res != 0) { Con_Printf("%s is not a valid Ogg Vorbis file (error %i).\n", - filename, res); + stream->name, res); goto _fail; } if (!ov_seekable(ovFile)) { - Con_Printf("Stream %s not seekable.\n", filename); + Con_Printf("Stream %s not seekable.\n", stream->name); goto _fail; } ovf_info = ov_info(ovFile, 0); if (!ovf_info) { - Con_Printf("Unable to get stream info for %s.\n", filename); + Con_Printf("Unable to get stream info for %s.\n", stream->name); goto _fail; } @@ -115,14 +110,14 @@ static snd_stream_t *S_VORBIS_CodecOpenStream (const char *filename) if (numstreams != 1) { Con_Printf("More than one (%ld) stream in %s.\n", - numstreams, filename); + numstreams, stream->name); goto _fail; } if (ovf_info->channels != 1 && ovf_info->channels != 2) { Con_Printf("Unsupported number of channels %d in %s\n", - ovf_info->channels, filename); + ovf_info->channels, stream->name); goto _fail; } @@ -131,13 +126,12 @@ static snd_stream_t *S_VORBIS_CodecOpenStream (const char *filename) stream->info.bits = VORBIS_SAMPLEBITS; stream->info.width = VORBIS_SAMPLEWIDTH; - return stream; + return true; _fail: if (res == 0) ov_clear(ovFile); Z_Free(ovFile); - S_CodecUtilClose(&stream); - return NULL; + return false; } static int S_VORBIS_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer) diff --git a/Quake/snd_wave.c b/Quake/snd_wave.c index c08b9435..b31011a2 100644 --- a/Quake/snd_wave.c +++ b/Quake/snd_wave.c @@ -192,35 +192,25 @@ static qboolean WAV_ReadRIFFHeader(const char *name, FILE *file, snd_info_t *inf S_WAV_CodecOpenStream ================= */ -snd_stream_t *S_WAV_CodecOpenStream(const char *filename) +static qboolean S_WAV_CodecOpenStream(snd_stream_t *stream) { - snd_stream_t *stream; - long start; - - stream = S_CodecUtilOpen(filename, &wav_codec); - if (!stream) - return NULL; - - start = stream->fh.start; + long start = stream->fh.start; /* Read the RIFF header */ /* The file reads are sequential, therefore no need * for the FS_*() functions: We will manipulate the * file by ourselves from now on. */ - if (!WAV_ReadRIFFHeader(filename, stream->fh.file, &stream->info)) - goto _fail; + if (!WAV_ReadRIFFHeader(stream->name, stream->fh.file, &stream->info)) + return false; stream->fh.start = ftell(stream->fh.file); /* reset to data position */ if (stream->fh.start - start + stream->info.size > stream->fh.length) { - Con_Printf("%s data size mismatch\n", filename); - goto _fail; + Con_Printf("%s data size mismatch\n", stream->name); + return false; } - return stream; -_fail: - S_CodecUtilClose(&stream); - return NULL; + return true; } /*