mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2024-11-09 23:11:39 +00:00
Updates for tracker music:
- New console command music_jump: Jump to given order in music, like Unreal's music change. Only for module (tracker) music. - stream layer: Store the loop setting. - umx reader: Replaced questionable byte-swap. - libxmp backend: Handled the loop setting through libxmp apis. - mikmod backend: Enabled in-module loops. Respect global loop setting. More compatible reader callback structure.
This commit is contained in:
parent
b60dae8acd
commit
81adf62374
14 changed files with 122 additions and 79 deletions
|
@ -76,14 +76,11 @@ static snd_stream_t *bgmstream = NULL;
|
|||
|
||||
static void BGM_Play_f (void)
|
||||
{
|
||||
if (Cmd_Argc() == 2)
|
||||
{
|
||||
if (Cmd_Argc() == 2) {
|
||||
BGM_Play (Cmd_Argv(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
Con_Printf ("music <musicfile>\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,16 +96,17 @@ static void BGM_Resume_f (void)
|
|||
|
||||
static void BGM_Loop_f (void)
|
||||
{
|
||||
if (Cmd_Argc() == 2)
|
||||
{
|
||||
if (Cmd_Argc() == 2) {
|
||||
if (q_strcasecmp(Cmd_Argv(1), "0") == 0 ||
|
||||
q_strcasecmp(Cmd_Argv(1),"off") == 0)
|
||||
bgmloop = false;
|
||||
else if (q_strcasecmp(Cmd_Argv(1), "1") == 0 ||
|
||||
q_strcasecmp(Cmd_Argv(1),"on") == 0)
|
||||
q_strcasecmp(Cmd_Argv(1),"on") == 0)
|
||||
bgmloop = true;
|
||||
else if (q_strcasecmp(Cmd_Argv(1),"toggle") == 0)
|
||||
bgmloop = !bgmloop;
|
||||
|
||||
if (bgmstream) bgmstream->loop = bgmloop;
|
||||
}
|
||||
|
||||
if (bgmloop)
|
||||
|
@ -122,6 +120,16 @@ static void BGM_Stop_f (void)
|
|||
BGM_Stop();
|
||||
}
|
||||
|
||||
static void BGM_Jump_f (void)
|
||||
{
|
||||
if (Cmd_Argc() != 2) {
|
||||
Con_Printf ("music_jump <ordernum>\n");
|
||||
}
|
||||
else if (bgmstream) {
|
||||
S_CodecJumpToOrder(bgmstream, atoi(Cmd_Argv(1)));
|
||||
}
|
||||
}
|
||||
|
||||
qboolean BGM_Init (void)
|
||||
{
|
||||
music_handler_t *handlers = NULL;
|
||||
|
@ -133,6 +141,7 @@ qboolean BGM_Init (void)
|
|||
Cmd_AddCommand("music_resume", BGM_Resume_f);
|
||||
Cmd_AddCommand("music_loop", BGM_Loop_f);
|
||||
Cmd_AddCommand("music_stop", BGM_Stop_f);
|
||||
Cmd_AddCommand("music_jump", BGM_Jump_f);
|
||||
|
||||
if (COM_CheckParm("-noextmusic") != 0)
|
||||
no_extmusic = true;
|
||||
|
@ -206,7 +215,7 @@ static void BGM_Play_noext (const char *filename, unsigned int allowed_types)
|
|||
/* not supported in quake */
|
||||
break;
|
||||
case BGM_STREAMER:
|
||||
bgmstream = S_CodecOpenStreamType(tmp, handler->type);
|
||||
bgmstream = S_CodecOpenStreamType(tmp, handler->type, bgmloop);
|
||||
if (bgmstream)
|
||||
return; /* success */
|
||||
break;
|
||||
|
@ -264,7 +273,7 @@ void BGM_Play (const char *filename)
|
|||
/* not supported in quake */
|
||||
break;
|
||||
case BGM_STREAMER:
|
||||
bgmstream = S_CodecOpenStreamType(tmp, handler->type);
|
||||
bgmstream = S_CodecOpenStreamType(tmp, handler->type, bgmloop);
|
||||
if (bgmstream)
|
||||
return; /* success */
|
||||
break;
|
||||
|
@ -329,7 +338,7 @@ void BGM_PlayCDtrack (byte track, qboolean looping)
|
|||
{
|
||||
q_snprintf(tmp, sizeof(tmp), "%s/track%02d.%s",
|
||||
MUSIC_DIRNAME, (int)track, ext);
|
||||
bgmstream = S_CodecOpenStreamType(tmp, type);
|
||||
bgmstream = S_CodecOpenStreamType(tmp, type, bgmloop);
|
||||
if (! bgmstream)
|
||||
Con_Printf("Couldn't handle music file %s\n", tmp);
|
||||
}
|
||||
|
|
|
@ -117,7 +117,7 @@ void S_CodecShutdown (void)
|
|||
S_CodecOpenStream
|
||||
=================
|
||||
*/
|
||||
snd_stream_t *S_CodecOpenStreamType (const char *filename, unsigned int type)
|
||||
snd_stream_t *S_CodecOpenStreamType (const char *filename, unsigned int type, qboolean loop)
|
||||
{
|
||||
snd_codec_t *codec;
|
||||
snd_stream_t *stream;
|
||||
|
@ -140,7 +140,7 @@ snd_stream_t *S_CodecOpenStreamType (const char *filename, unsigned int type)
|
|||
Con_Printf("Unknown type for %s\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
stream = S_CodecUtilOpen(filename, codec);
|
||||
stream = S_CodecUtilOpen(filename, codec, loop);
|
||||
if (stream) {
|
||||
if (codec->codec_open(stream))
|
||||
stream->status = STREAM_PLAY;
|
||||
|
@ -149,7 +149,7 @@ snd_stream_t *S_CodecOpenStreamType (const char *filename, unsigned int type)
|
|||
return stream;
|
||||
}
|
||||
|
||||
snd_stream_t *S_CodecOpenStreamExt (const char *filename)
|
||||
snd_stream_t *S_CodecOpenStreamExt (const char *filename, qboolean loop)
|
||||
{
|
||||
snd_codec_t *codec;
|
||||
snd_stream_t *stream;
|
||||
|
@ -174,7 +174,7 @@ snd_stream_t *S_CodecOpenStreamExt (const char *filename)
|
|||
Con_Printf("Unknown extension for %s\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
stream = S_CodecUtilOpen(filename, codec);
|
||||
stream = S_CodecUtilOpen(filename, codec, loop);
|
||||
if (stream) {
|
||||
if (codec->codec_open(stream))
|
||||
stream->status = STREAM_PLAY;
|
||||
|
@ -183,7 +183,7 @@ snd_stream_t *S_CodecOpenStreamExt (const char *filename)
|
|||
return stream;
|
||||
}
|
||||
|
||||
snd_stream_t *S_CodecOpenStreamAny (const char *filename)
|
||||
snd_stream_t *S_CodecOpenStreamAny (const char *filename, qboolean loop)
|
||||
{
|
||||
snd_codec_t *codec;
|
||||
snd_stream_t *stream;
|
||||
|
@ -198,7 +198,7 @@ snd_stream_t *S_CodecOpenStreamAny (const char *filename)
|
|||
while (codec)
|
||||
{
|
||||
q_snprintf(tmp, sizeof(tmp), "%s.%s", filename, codec->ext);
|
||||
stream = S_CodecUtilOpen(tmp, codec);
|
||||
stream = S_CodecUtilOpen(tmp, codec, loop);
|
||||
if (stream) {
|
||||
if (codec->codec_open(stream)) {
|
||||
stream->status = STREAM_PLAY;
|
||||
|
@ -225,7 +225,7 @@ snd_stream_t *S_CodecOpenStreamAny (const char *filename)
|
|||
Con_Printf("Unknown extension for %s\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
stream = S_CodecUtilOpen(filename, codec);
|
||||
stream = S_CodecUtilOpen(filename, codec, loop);
|
||||
if (stream) {
|
||||
if (codec->codec_open(stream))
|
||||
stream->status = STREAM_PLAY;
|
||||
|
@ -261,6 +261,14 @@ int S_CodecRewindStream (snd_stream_t *stream)
|
|||
return stream->codec->codec_rewind(stream);
|
||||
}
|
||||
|
||||
int S_CodecJumpToOrder (snd_stream_t *stream, int to)
|
||||
{
|
||||
if (stream->codec->codec_jump) {
|
||||
return stream->codec->codec_jump(stream, to);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int S_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer)
|
||||
{
|
||||
return stream->codec->codec_read(stream, bytes, buffer);
|
||||
|
@ -268,7 +276,7 @@ int S_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer)
|
|||
|
||||
/* Util functions (used by codecs) */
|
||||
|
||||
snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec)
|
||||
snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec, qboolean loop)
|
||||
{
|
||||
snd_stream_t *stream;
|
||||
FILE *handle;
|
||||
|
@ -287,6 +295,7 @@ snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec)
|
|||
/* Allocate a stream, Z_Malloc zeroes its content */
|
||||
stream = (snd_stream_t *) Z_Malloc(sizeof(snd_stream_t));
|
||||
stream->codec = codec;
|
||||
stream->loop = loop;
|
||||
stream->fh.file = handle;
|
||||
stream->fh.start = ftell(handle);
|
||||
stream->fh.pos = 0;
|
||||
|
|
|
@ -54,6 +54,7 @@ typedef struct snd_stream_s
|
|||
snd_info_t info;
|
||||
stream_status_t status;
|
||||
snd_codec_t *codec; /* codec handling this stream */
|
||||
qboolean loop;
|
||||
void *priv; /* data private to the codec. */
|
||||
} snd_stream_t;
|
||||
|
||||
|
@ -64,22 +65,24 @@ void S_CodecShutdown (void);
|
|||
/* Callers of the following S_CodecOpenStream* functions
|
||||
* are reponsible for attaching any path to the filename */
|
||||
|
||||
snd_stream_t *S_CodecOpenStreamType (const char *filename, unsigned int type);
|
||||
snd_stream_t *S_CodecOpenStreamType (const char *filename, unsigned int type,
|
||||
qboolean loop);
|
||||
/* Decides according to the required type. */
|
||||
|
||||
snd_stream_t *S_CodecOpenStreamAny (const char *filename);
|
||||
snd_stream_t *S_CodecOpenStreamAny (const char *filename, qboolean loop);
|
||||
/* Decides according to file extension. if the
|
||||
* name has no extension, try all available. */
|
||||
|
||||
snd_stream_t *S_CodecOpenStreamExt (const char *filename);
|
||||
snd_stream_t *S_CodecOpenStreamExt (const char *filename, qboolean loop);
|
||||
/* Decides according to file extension. the name
|
||||
* MUST have an extension. */
|
||||
|
||||
void S_CodecCloseStream (snd_stream_t *stream);
|
||||
int S_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer);
|
||||
int S_CodecRewindStream (snd_stream_t *stream);
|
||||
int S_CodecJumpToOrder (snd_stream_t *stream, int to);
|
||||
|
||||
snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec);
|
||||
snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec, qboolean loop);
|
||||
void S_CodecUtilClose(snd_stream_t **stream);
|
||||
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ typedef void (*CODEC_SHUTDOWN)(void);
|
|||
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 int (*CODEC_JUMP)(snd_stream_t *stream, int order);
|
||||
typedef void (*CODEC_CLOSE)(snd_stream_t *stream);
|
||||
|
||||
struct snd_codec_s
|
||||
|
@ -44,6 +45,7 @@ struct snd_codec_s
|
|||
CODEC_OPEN codec_open;
|
||||
CODEC_READ codec_read;
|
||||
CODEC_REWIND codec_rewind;
|
||||
CODEC_JUMP codec_jump;
|
||||
CODEC_CLOSE codec_close;
|
||||
snd_codec_t *next;
|
||||
};
|
||||
|
|
|
@ -356,8 +356,7 @@ static void S_FLAC_CodecCloseStream (snd_stream_t *stream)
|
|||
FLAC__stream_decoder_finish (ff->decoder);
|
||||
FLAC__stream_decoder_delete (ff->decoder);
|
||||
|
||||
if (ff->buffer)
|
||||
free(ff->buffer);
|
||||
if (ff->buffer) free(ff->buffer);
|
||||
Z_Free(ff);
|
||||
|
||||
S_CodecUtilClose(&stream);
|
||||
|
@ -382,6 +381,7 @@ snd_codec_t flac_codec =
|
|||
S_FLAC_CodecOpenStream,
|
||||
S_FLAC_CodecReadStream,
|
||||
S_FLAC_CodecRewindStream,
|
||||
NULL, /* jump */
|
||||
S_FLAC_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -43,12 +43,15 @@
|
|||
#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;
|
||||
/* MREADER core members in libmikmod2/3: */
|
||||
int (*Seek)(struct MREADER*, long, int);
|
||||
long (*Tell)(struct MREADER*);
|
||||
BOOL (*Read)(struct MREADER*, void*, size_t);
|
||||
int (*Get)(struct MREADER*);
|
||||
BOOL (*Eof)(struct MREADER*);
|
||||
/* no iobase members in libmikmod <= 3.2.0-beta2 */
|
||||
long iobase, prev_iobase;
|
||||
|
||||
fshandle_t *fh;
|
||||
MODULE *module;
|
||||
} mik_priv_t;
|
||||
|
@ -132,11 +135,11 @@ static qboolean S_MIKMOD_CodecOpenStream (snd_stream_t *stream)
|
|||
|
||||
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->Seek = MIK_Seek;
|
||||
priv->Tell = MIK_Tell;
|
||||
priv->Read = MIK_Read;
|
||||
priv->Get = MIK_Get;
|
||||
priv->Eof = MIK_Eof;
|
||||
priv->fh = &stream->fh;
|
||||
|
||||
priv->module = Player_LoadGeneric((MREADER *)stream->priv, 64, 0);
|
||||
|
@ -147,13 +150,16 @@ static qboolean S_MIKMOD_CodecOpenStream (snd_stream_t *stream)
|
|||
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;
|
||||
/* default values of module options set by Player_Init():
|
||||
* fadeout (0): don't fade out volume during when last position of the
|
||||
* module is being played,
|
||||
* extspd (1): process Protracker extended speed effect,
|
||||
* panflag (1): process panning effects,
|
||||
* wrap (0): don't wrap to restart position when module is finished,
|
||||
* loop (1): process all in-module loops -- possible backward loops
|
||||
* would make the module to loop endlessly.
|
||||
*/
|
||||
priv->module->wrap = stream->loop;
|
||||
Player_Start(priv->module);
|
||||
|
||||
stream->info.rate = md_mixfreq;
|
||||
|
@ -169,6 +175,10 @@ static int S_MIKMOD_CodecReadStream (snd_stream_t *stream, int bytes, void *buff
|
|||
{
|
||||
if (!Player_Active())
|
||||
return 0;
|
||||
|
||||
/* handle possible loop setting change: */
|
||||
((mik_priv_t *)stream->priv)->module->wrap = stream->loop;
|
||||
|
||||
return (int) VC_WriteBytes((SBYTE *)buffer, bytes);
|
||||
}
|
||||
|
||||
|
@ -180,9 +190,15 @@ static void S_MIKMOD_CodecCloseStream (snd_stream_t *stream)
|
|||
S_CodecUtilClose(&stream);
|
||||
}
|
||||
|
||||
static int S_MIKMOD_CodecJumpToOrder (snd_stream_t *stream, int to)
|
||||
{
|
||||
Player_SetPosition ((UWORD)to);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int S_MIKMOD_CodecRewindStream (snd_stream_t *stream)
|
||||
{
|
||||
Player_SetPosition (0);
|
||||
Player_SetPosition (0); /* FIXME: WRONG: THIS IS NOT A TIME SEEK */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -196,6 +212,7 @@ snd_codec_t mikmod_codec =
|
|||
S_MIKMOD_CodecOpenStream,
|
||||
S_MIKMOD_CodecReadStream,
|
||||
S_MIKMOD_CodecRewindStream,
|
||||
S_MIKMOD_CodecJumpToOrder,
|
||||
S_MIKMOD_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -452,6 +452,7 @@ snd_codec_t mp3_codec =
|
|||
S_MP3_CodecOpenStream,
|
||||
S_MP3_CodecReadStream,
|
||||
S_MP3_CodecRewindStream,
|
||||
NULL, /* jump */
|
||||
S_MP3_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -49,7 +49,7 @@ static ssize_t mp3_read (void *f, void *buf, size_t size)
|
|||
}
|
||||
static off_t mp3_seek (void *f, off_t offset, int whence)
|
||||
{
|
||||
if (f == NULL) return (-1);
|
||||
if (f == NULL) return -1;
|
||||
if (FS_fseek((fshandle_t *)f, (long) offset, whence) < 0)
|
||||
return (off_t)-1;
|
||||
return (off_t) FS_ftell((fshandle_t *)f);
|
||||
|
@ -200,7 +200,7 @@ static int S_MP3_CodecRewindStream (snd_stream_t *stream)
|
|||
{
|
||||
mp3_priv_t *priv = (mp3_priv_t *) stream->priv;
|
||||
off_t res = mpg123_seek(priv->handle, 0, SEEK_SET);
|
||||
if (res >= 0) return (0);
|
||||
if (res >= 0) return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -214,6 +214,7 @@ snd_codec_t mp3_codec =
|
|||
S_MP3_CodecOpenStream,
|
||||
S_MP3_CodecReadStream,
|
||||
S_MP3_CodecRewindStream,
|
||||
NULL, /* jump */
|
||||
S_MP3_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -202,6 +202,7 @@ snd_codec_t opus_codec =
|
|||
S_OPUS_CodecOpenStream,
|
||||
S_OPUS_CodecReadStream,
|
||||
S_OPUS_CodecRewindStream,
|
||||
NULL, /* jump */
|
||||
S_OPUS_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -2,12 +2,7 @@
|
|||
* Unreal UMX container support.
|
||||
* UPKG parsing partially 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/
|
||||
*
|
||||
* The cheaper way, i.e. linear search of music object like libxmp
|
||||
* and libmodplug does, is possible. With this however we're using
|
||||
* the embedded offset, size and object type directly from the umx
|
||||
* file, and I feel safer with it.
|
||||
* by O. Sezer - see git repo at https://github.com/sezero/umr.git
|
||||
*
|
||||
* Copyright (C) 2013 O. Sezer <sezero@users.sourceforge.net>
|
||||
*
|
||||
|
@ -63,10 +58,9 @@ struct upkg_hdr {
|
|||
uint32_t guid[4];
|
||||
int32_t generation_count;
|
||||
#define UPKG_HDR_SIZE 64 /* 64 bytes up until here */
|
||||
/*struct _genhist *gen;*/
|
||||
struct _genhist *gen;
|
||||
};
|
||||
/*COMPILE_TIME_ASSERT(upkg_hdr, offsetof(struct upkg_hdr, gen) == UPKG_HDR_SIZE);*/
|
||||
COMPILE_TIME_ASSERT(upkg_hdr, sizeof(struct upkg_hdr) == UPKG_HDR_SIZE);
|
||||
COMPILE_TIME_ASSERT(upkg_hdr, offsetof(struct upkg_hdr, gen) == UPKG_HDR_SIZE);
|
||||
|
||||
#define UMUSIC_IT 0
|
||||
#define UMUSIC_S3M 1
|
||||
|
@ -274,21 +268,21 @@ static int probe_umx (fshandle_t *f, const struct upkg_hdr *hdr,
|
|||
return t;
|
||||
}
|
||||
|
||||
static int32_t probe_header (void *header)
|
||||
static int32_t probe_header (fshandle_t *f, struct upkg_hdr *hdr)
|
||||
{
|
||||
struct upkg_hdr *hdr;
|
||||
unsigned char *p;
|
||||
uint32_t *swp;
|
||||
int i;
|
||||
|
||||
if (FS_fread(hdr, 1, UPKG_HDR_SIZE, f) < UPKG_HDR_SIZE)
|
||||
return -1;
|
||||
/* byte swap the header - all members are 32 bit LE values */
|
||||
p = (unsigned char *) header;
|
||||
swp = (uint32_t *) header;
|
||||
for (i = 0; i < UPKG_HDR_SIZE/4; i++, p += 4) {
|
||||
swp[i] = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||
}
|
||||
hdr->tag = (uint32_t) LittleLong(hdr->tag);
|
||||
hdr->file_version = LittleLong(hdr->file_version);
|
||||
hdr->pkg_flags = (uint32_t) LittleLong(hdr->pkg_flags);
|
||||
hdr->name_count = LittleLong(hdr->name_count);
|
||||
hdr->name_offset = LittleLong(hdr->name_offset);
|
||||
hdr->export_count = LittleLong(hdr->export_count);
|
||||
hdr->export_offset = LittleLong(hdr->export_offset);
|
||||
hdr->import_count = LittleLong(hdr->import_count);
|
||||
hdr->import_offset = LittleLong(hdr->import_offset);
|
||||
|
||||
hdr = (struct upkg_hdr *) header;
|
||||
if (hdr->tag != UPKG_HDR_TAG) {
|
||||
Con_DPrintf("Unknown header tag 0x%x\n", hdr->tag);
|
||||
return -1;
|
||||
|
@ -325,14 +319,13 @@ static int32_t probe_header (void *header)
|
|||
|
||||
static int process_upkg (fshandle_t *f, int32_t *ofs, int32_t *objsize)
|
||||
{
|
||||
char header[UPKG_HDR_SIZE];
|
||||
struct upkg_hdr header;
|
||||
|
||||
if (FS_fread(header, 1, UPKG_HDR_SIZE, f) < UPKG_HDR_SIZE)
|
||||
return -1;
|
||||
if (probe_header(header) < 0)
|
||||
memset(&header, 0, sizeof(header));
|
||||
if (probe_header(f, &header) < 0)
|
||||
return -1;
|
||||
|
||||
return probe_umx(f, (struct upkg_hdr *)header, ofs, objsize);
|
||||
return probe_umx(f, &header, ofs, objsize);
|
||||
}
|
||||
|
||||
static qboolean S_UMX_CodecInitialize (void)
|
||||
|
@ -399,6 +392,7 @@ snd_codec_t umx_codec =
|
|||
S_UMX_CodecOpenStream,
|
||||
S_UMX_CodecReadStream,
|
||||
S_UMX_CodecRewindStream,
|
||||
NULL, /* jump */
|
||||
S_UMX_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -196,6 +196,7 @@ snd_codec_t vorbis_codec =
|
|||
S_VORBIS_CodecOpenStream,
|
||||
S_VORBIS_CodecReadStream,
|
||||
S_VORBIS_CodecRewindStream,
|
||||
NULL, /* jump */
|
||||
S_VORBIS_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -37,9 +37,7 @@ FGetLittleLong
|
|||
static int FGetLittleLong (FILE *f)
|
||||
{
|
||||
int v;
|
||||
|
||||
fread(&v, 1, sizeof(v), f);
|
||||
|
||||
return LittleLong(v);
|
||||
}
|
||||
|
||||
|
@ -51,9 +49,7 @@ FGetLittleShort
|
|||
static short FGetLittleShort(FILE *f)
|
||||
{
|
||||
short v;
|
||||
|
||||
fread(&v, 1, sizeof(v), f);
|
||||
|
||||
return LittleShort(v);
|
||||
}
|
||||
|
||||
|
@ -268,6 +264,7 @@ snd_codec_t wav_codec =
|
|||
S_WAV_CodecOpenStream,
|
||||
S_WAV_CodecReadStream,
|
||||
S_WAV_CodecRewindStream,
|
||||
NULL, /* jump */
|
||||
S_WAV_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* tracker music (module file) decoding support using libxmp >= v4.2.0
|
||||
* https://sourceforge.net/projects/xmp/
|
||||
* https://github.com/cmatsuoka/libxmp.git
|
||||
* https://github.com/libxmp/libxmp.git
|
||||
*
|
||||
* Copyright (C) 2016 O.Sezer <sezero@users.sourceforge.net>
|
||||
*
|
||||
|
@ -105,7 +105,7 @@ static int S_XMP_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer)
|
|||
* is partial, the rest of the buffer will be zero-filled.
|
||||
* the last param is the max number that the current sequence
|
||||
* of song will be looped, or 0 to disable loop checking. */
|
||||
r = xmp_play_buffer((xmp_context)stream->priv, buffer, bytes, 1);
|
||||
r = xmp_play_buffer((xmp_context)stream->priv, buffer, bytes, !stream->loop);
|
||||
if (r == 0) {
|
||||
return bytes;
|
||||
}
|
||||
|
@ -125,12 +125,16 @@ static void S_XMP_CodecCloseStream (snd_stream_t *stream)
|
|||
S_CodecUtilClose(&stream);
|
||||
}
|
||||
|
||||
static int S_XMP_CodecJumpToOrder (snd_stream_t *stream, int to)
|
||||
{
|
||||
return xmp_set_position((xmp_context)stream->priv, to);
|
||||
}
|
||||
|
||||
static int S_XMP_CodecRewindStream (snd_stream_t *stream)
|
||||
{
|
||||
int ret = xmp_seek_time((xmp_context)stream->priv, 0);
|
||||
if (ret < 0) return ret;
|
||||
/* reset internal state */
|
||||
xmp_play_buffer((xmp_context)stream->priv, NULL, 0, 0);
|
||||
xmp_play_buffer((xmp_context)stream->priv, NULL, 0, 0); /* reset internal state */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -144,6 +148,7 @@ snd_codec_t xmp_codec =
|
|||
S_XMP_CodecOpenStream,
|
||||
S_XMP_CodecReadStream,
|
||||
S_XMP_CodecRewindStream,
|
||||
S_XMP_CodecJumpToOrder,
|
||||
S_XMP_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
|
|
@ -59,6 +59,9 @@ New console commands:
|
|||
- music_loop 0
|
||||
Makes the background music to play once and then stop
|
||||
|
||||
- music_jump
|
||||
Jump to a given order in music (only for module (tracker) music)
|
||||
|
||||
New cvars:
|
||||
-------------------------
|
||||
- bgm_extmusic (0 or 1): Disable or enable playback of external music
|
||||
|
|
Loading…
Reference in a new issue