mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2024-11-10 15:31:39 +00:00
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+ssh://svn.code.sf.net/p/quakespasm/code/trunk@867 af15c1b1-3010-417e-b628-4374ebc0bcbd
This commit is contained in:
parent
b5b1bc07e1
commit
32d841af26
22 changed files with 971 additions and 130 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_ */
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
199
quakespasm/Quake/snd_mikmod.c
Normal file
199
quakespasm/Quake/snd_mikmod.c
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* tracker music (module file) decoding support using libmikmod
|
||||
*
|
||||
* Copyright (C) 2013 O.Sezer <sezero@users.sourceforge.net>
|
||||
*
|
||||
* 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 <mikmod.h>
|
||||
|
||||
#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 */
|
||||
|
13
quakespasm/Quake/snd_mikmod.h
Normal file
13
quakespasm/Quake/snd_mikmod.h
Normal file
|
@ -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_ */
|
||||
|
121
quakespasm/Quake/snd_modplug.c
Normal file
121
quakespasm/Quake/snd_modplug.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* tracker music (module file) decoding support using libmodplug
|
||||
*
|
||||
* Copyright (C) 2013 O.Sezer <sezero@users.sourceforge.net>
|
||||
*
|
||||
* 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 <libmodplug/modplug.h>
|
||||
|
||||
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 */
|
||||
|
12
quakespasm/Quake/snd_modplug.h
Normal file
12
quakespasm/Quake/snd_modplug.h
Normal file
|
@ -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_ */
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
387
quakespasm/Quake/snd_umx.c
Normal file
387
quakespasm/Quake/snd_umx.c
Normal file
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* Unreal UMX container support. UMX parsing is based on Unreal Media
|
||||
* Ripper (UMR) v0.3 by Andy Ward <wardwh@swbell.net>, with additional
|
||||
* updates by O. Sezer - see git repo at https://github.com/sezero/umr/
|
||||
*
|
||||
* Copyright (C) 2013 O.Sezer <sezero@users.sourceforge.net>
|
||||
*
|
||||
* 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 */
|
||||
|
12
quakespasm/Quake/snd_umx.h
Normal file
12
quakespasm/Quake/snd_umx.h
Normal file
|
@ -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_ */
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue