added tracker music support using libxmp >= v4.2.0 (off by default.)

git-svn-id: svn+ssh://svn.code.sf.net/p/quakespasm/code/trunk@1364 af15c1b1-3010-417e-b628-4374ebc0bcbd
This commit is contained in:
sezero 2016-12-07 09:24:49 +00:00
parent 7078ee136d
commit c79f121b81
22 changed files with 970 additions and 7 deletions

View file

@ -290,6 +290,10 @@
<Option compilerVar="CC" />
</Unit>
<Unit filename="../../Quake/snd_wave.h" />
<Unit filename="../../Quake/snd_xmp.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../../Quake/snd_xmp.h" />
<Unit filename="../../Quake/spritegn.h" />
<Unit filename="../../Quake/strl_fn.h" />
<Unit filename="../../Quake/strlcat.c">

View file

@ -289,6 +289,10 @@
<Option compilerVar="CC" />
</Unit>
<Unit filename="../../Quake/snd_wave.h" />
<Unit filename="../../Quake/snd_xmp.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../../Quake/snd_xmp.h" />
<Unit filename="../../Quake/spritegn.h" />
<Unit filename="../../Quake/strl_fn.h" />
<Unit filename="../../Quake/strlcat.c">

View file

@ -0,0 +1,360 @@
#ifndef XMP_H
#define XMP_H
#ifdef __cplusplus
extern "C" {
#endif
#define XMP_VERSION "4.4.2"
#define XMP_VERCODE 0x040402
#define XMP_VER_MAJOR 4
#define XMP_VER_MINOR 4
#define XMP_VER_RELEASE 2
#if defined(_WIN32) && !defined(__CYGWIN__)
# if defined(BUILDING_STATIC)
# define EXPORT
# elif defined(BUILDING_DLL)
# define EXPORT __declspec(dllexport)
# else
# define EXPORT __declspec(dllimport)
# endif
#elif defined(__OS2__) && defined(__WATCOMC__) && defined(__SW_BD)
# define EXPORT __declspec(dllexport)
#elif (defined(__GNUC__) || defined(__clang__) || defined(__HP_cc)) && defined(XMP_SYM_VISIBILITY)
# define EXPORT __attribute__((visibility ("default")))
#elif defined(__SUNPRO_C) && defined(XMP_LDSCOPE_GLOBAL)
# define EXPORT __global
#elif defined(EMSCRIPTEN)
# define EXPORT EMSCRIPTEN_KEEPALIVE
#else
# define EXPORT
#endif
#define XMP_NAME_SIZE 64 /* Size of module name and type */
#define XMP_KEY_OFF 0x81 /* Note number for key off event */
#define XMP_KEY_CUT 0x82 /* Note number for key cut event */
#define XMP_KEY_FADE 0x83 /* Note number for fade event */
/* mixer parameter macros */
/* sample format flags */
#define XMP_FORMAT_8BIT (1 << 0) /* Mix to 8-bit instead of 16 */
#define XMP_FORMAT_UNSIGNED (1 << 1) /* Mix to unsigned samples */
#define XMP_FORMAT_MONO (1 << 2) /* Mix to mono instead of stereo */
/* player parameters */
#define XMP_PLAYER_AMP 0 /* Amplification factor */
#define XMP_PLAYER_MIX 1 /* Stereo mixing */
#define XMP_PLAYER_INTERP 2 /* Interpolation type */
#define XMP_PLAYER_DSP 3 /* DSP effect flags */
#define XMP_PLAYER_FLAGS 4 /* Player flags */
#define XMP_PLAYER_CFLAGS 5 /* Player flags for current module */
#define XMP_PLAYER_SMPCTL 6 /* Sample control flags */
#define XMP_PLAYER_VOLUME 7 /* Player module volume */
#define XMP_PLAYER_STATE 8 /* Internal player state (read only) */
#define XMP_PLAYER_SMIX_VOLUME 9 /* SMIX volume */
#define XMP_PLAYER_DEFPAN 10 /* Default pan setting */
#define XMP_PLAYER_MODE 11 /* Player personality */
#define XMP_PLAYER_MIXER_TYPE 12 /* Current mixer (read only) */
#define XMP_PLAYER_VOICES 13 /* Maximum number of mixer voices */
/* interpolation types */
#define XMP_INTERP_NEAREST 0 /* Nearest neighbor */
#define XMP_INTERP_LINEAR 1 /* Linear (default) */
#define XMP_INTERP_SPLINE 2 /* Cubic spline */
/* dsp effect types */
#define XMP_DSP_LOWPASS (1 << 0) /* Lowpass filter effect */
#define XMP_DSP_ALL (XMP_DSP_LOWPASS)
/* player state */
#define XMP_STATE_UNLOADED 0 /* Context created */
#define XMP_STATE_LOADED 1 /* Module loaded */
#define XMP_STATE_PLAYING 2 /* Module playing */
/* player flags */
#define XMP_FLAGS_VBLANK (1 << 0) /* Use vblank timing */
#define XMP_FLAGS_FX9BUG (1 << 1) /* Emulate FX9 bug */
#define XMP_FLAGS_FIXLOOP (1 << 2) /* Emulate sample loop bug */
#define XMP_FLAGS_A500 (1 << 3) /* Use Paula mixer in Amiga modules */
/* player modes */
#define XMP_MODE_AUTO 0 /* Autodetect mode (default) */
#define XMP_MODE_MOD 1 /* Play as a generic MOD player */
#define XMP_MODE_NOISETRACKER 2 /* Play using Noisetracker quirks */
#define XMP_MODE_PROTRACKER 3 /* Play using Protracker quirks */
#define XMP_MODE_S3M 4 /* Play as a generic S3M player */
#define XMP_MODE_ST3 5 /* Play using ST3 bug emulation */
#define XMP_MODE_ST3GUS 6 /* Play using ST3+GUS quirks */
#define XMP_MODE_XM 7 /* Play as a generic XM player */
#define XMP_MODE_FT2 8 /* Play using FT2 bug emulation */
#define XMP_MODE_IT 9 /* Play using IT quirks */
#define XMP_MODE_ITSMP 10 /* Play using IT sample mode quirks */
/* mixer types */
#define XMP_MIXER_STANDARD 0 /* Standard mixer */
#define XMP_MIXER_A500 1 /* Amiga 500 */
#define XMP_MIXER_A500F 2 /* Amiga 500 with led filter */
/* sample flags */
#define XMP_SMPCTL_SKIP (1 << 0) /* Don't load samples */
/* limits */
#define XMP_MAX_KEYS 121 /* Number of valid keys */
#define XMP_MAX_ENV_POINTS 32 /* Max number of envelope points */
#define XMP_MAX_MOD_LENGTH 256 /* Max number of patterns in module */
#define XMP_MAX_CHANNELS 64 /* Max number of channels in module */
#define XMP_MAX_SRATE 49170 /* max sampling rate (Hz) */
#define XMP_MIN_SRATE 4000 /* min sampling rate (Hz) */
#define XMP_MIN_BPM 20 /* min BPM */
/* frame rate = (50 * bpm / 125) Hz */
/* frame size = (sampling rate * channels * size) / frame rate */
#define XMP_MAX_FRAMESIZE (5 * XMP_MAX_SRATE * 2 / XMP_MIN_BPM)
/* error codes */
#define XMP_END 1
#define XMP_ERROR_INTERNAL 2 /* Internal error */
#define XMP_ERROR_FORMAT 3 /* Unsupported module format */
#define XMP_ERROR_LOAD 4 /* Error loading file */
#define XMP_ERROR_DEPACK 5 /* Error depacking file */
#define XMP_ERROR_SYSTEM 6 /* System error */
#define XMP_ERROR_INVALID 7 /* Invalid parameter */
#define XMP_ERROR_STATE 8 /* Invalid player state */
struct xmp_channel {
int pan; /* Channel pan (0x80 is center) */
int vol; /* Channel volume */
#define XMP_CHANNEL_SYNTH (1 << 0) /* Channel is synthesized */
#define XMP_CHANNEL_MUTE (1 << 1) /* Channel is muted */
#define XMP_CHANNEL_SPLIT (1 << 2) /* Split Amiga channel in bits 5-4 */
#define XMP_CHANNEL_SURROUND (1 << 4) /* Surround channel */
int flg; /* Channel flags */
};
struct xmp_pattern {
int rows; /* Number of rows */
int index[1]; /* Track index */
};
struct xmp_event {
unsigned char note; /* Note number (0 means no note) */
unsigned char ins; /* Patch number */
unsigned char vol; /* Volume (0 to basevol) */
unsigned char fxt; /* Effect type */
unsigned char fxp; /* Effect parameter */
unsigned char f2t; /* Secondary effect type */
unsigned char f2p; /* Secondary effect parameter */
unsigned char _flag; /* Internal (reserved) flags */
};
struct xmp_track {
int rows; /* Number of rows */
struct xmp_event event[1]; /* Event data */
};
struct xmp_envelope {
#define XMP_ENVELOPE_ON (1 << 0) /* Envelope is enabled */
#define XMP_ENVELOPE_SUS (1 << 1) /* Envelope has sustain point */
#define XMP_ENVELOPE_LOOP (1 << 2) /* Envelope has loop */
#define XMP_ENVELOPE_FLT (1 << 3) /* Envelope is used for filter */
#define XMP_ENVELOPE_SLOOP (1 << 4) /* Envelope has sustain loop */
#define XMP_ENVELOPE_CARRY (1 << 5) /* Don't reset envelope position */
int flg; /* Flags */
int npt; /* Number of envelope points */
int scl; /* Envelope scaling */
int sus; /* Sustain start point */
int sue; /* Sustain end point */
int lps; /* Loop start point */
int lpe; /* Loop end point */
short data[XMP_MAX_ENV_POINTS * 2];
};
struct xmp_instrument {
char name[32]; /* Instrument name */
int vol; /* Instrument volume */
int nsm; /* Number of samples */
int rls; /* Release (fadeout) */
struct xmp_envelope aei; /* Amplitude envelope info */
struct xmp_envelope pei; /* Pan envelope info */
struct xmp_envelope fei; /* Frequency envelope info */
struct {
unsigned char ins; /* Instrument number for each key */
signed char xpo; /* Instrument transpose for each key */
} map[XMP_MAX_KEYS];
struct xmp_subinstrument {
int vol; /* Default volume */
int gvl; /* Global volume */
int pan; /* Pan */
int xpo; /* Transpose */
int fin; /* Finetune */
int vwf; /* Vibrato waveform */
int vde; /* Vibrato depth */
int vra; /* Vibrato rate */
int vsw; /* Vibrato sweep */
int rvv; /* Random volume/pan variation (IT) */
int sid; /* Sample number */
#define XMP_INST_NNA_CUT 0x00
#define XMP_INST_NNA_CONT 0x01
#define XMP_INST_NNA_OFF 0x02
#define XMP_INST_NNA_FADE 0x03
int nna; /* New note action */
#define XMP_INST_DCT_OFF 0x00
#define XMP_INST_DCT_NOTE 0x01
#define XMP_INST_DCT_SMP 0x02
#define XMP_INST_DCT_INST 0x03
int dct; /* Duplicate check type */
#define XMP_INST_DCA_CUT XMP_INST_NNA_CUT
#define XMP_INST_DCA_OFF XMP_INST_NNA_OFF
#define XMP_INST_DCA_FADE XMP_INST_NNA_FADE
int dca; /* Duplicate check action */
int ifc; /* Initial filter cutoff */
int ifr; /* Initial filter resonance */
} *sub;
void *extra; /* Extra fields */
};
struct xmp_sample {
char name[32]; /* Sample name */
int len; /* Sample length */
int lps; /* Loop start */
int lpe; /* Loop end */
#define XMP_SAMPLE_16BIT (1 << 0) /* 16bit sample */
#define XMP_SAMPLE_LOOP (1 << 1) /* Sample is looped */
#define XMP_SAMPLE_LOOP_BIDIR (1 << 2) /* Bidirectional sample loop */
#define XMP_SAMPLE_LOOP_REVERSE (1 << 3) /* Backwards sample loop */
#define XMP_SAMPLE_LOOP_FULL (1 << 4) /* Play full sample before looping */
#define XMP_SAMPLE_SLOOP (1 << 5) /* Sample has sustain loop */
#define XMP_SAMPLE_SLOOP_BIDIR (1 << 6) /* Bidirectional sustain loop */
#define XMP_SAMPLE_SYNTH (1 << 15) /* Data contains synth patch */
int flg; /* Flags */
unsigned char *data; /* Sample data */
};
struct xmp_sequence {
int entry_point;
int duration;
};
struct xmp_module {
char name[XMP_NAME_SIZE]; /* Module title */
char type[XMP_NAME_SIZE]; /* Module format */
int pat; /* Number of patterns */
int trk; /* Number of tracks */
int chn; /* Tracks per pattern */
int ins; /* Number of instruments */
int smp; /* Number of samples */
int spd; /* Initial speed */
int bpm; /* Initial BPM */
int len; /* Module length in patterns */
int rst; /* Restart position */
int gvl; /* Global volume */
struct xmp_pattern **xxp; /* Patterns */
struct xmp_track **xxt; /* Tracks */
struct xmp_instrument *xxi; /* Instruments */
struct xmp_sample *xxs; /* Samples */
struct xmp_channel xxc[XMP_MAX_CHANNELS]; /* Channel info */
unsigned char xxo[XMP_MAX_MOD_LENGTH]; /* Orders */
};
struct xmp_test_info {
char name[XMP_NAME_SIZE]; /* Module title */
char type[XMP_NAME_SIZE]; /* Module format */
};
struct xmp_module_info {
unsigned char md5[16]; /* MD5 message digest */
int vol_base; /* Volume scale */
struct xmp_module *mod; /* Pointer to module data */
char *comment; /* Comment text, if any */
int num_sequences; /* Number of valid sequences */
struct xmp_sequence *seq_data; /* Pointer to sequence data */
};
struct xmp_frame_info { /* Current frame information */
int pos; /* Current position */
int pattern; /* Current pattern */
int row; /* Current row in pattern */
int num_rows; /* Number of rows in current pattern */
int frame; /* Current frame */
int speed; /* Current replay speed */
int bpm; /* Current bpm */
int time; /* Current module time in ms */
int total_time; /* Estimated replay time in ms*/
int frame_time; /* Frame replay time in us */
void *buffer; /* Pointer to sound buffer */
int buffer_size; /* Used buffer size */
int total_size; /* Total buffer size */
int volume; /* Current master volume */
int loop_count; /* Loop counter */
int virt_channels; /* Number of virtual channels */
int virt_used; /* Used virtual channels */
int sequence; /* Current sequence */
struct xmp_channel_info { /* Current channel information */
unsigned int period; /* Sample period (* 4096) */
unsigned int position; /* Sample position */
short pitchbend; /* Linear bend from base note*/
unsigned char note; /* Current base note number */
unsigned char instrument; /* Current instrument number */
unsigned char sample; /* Current sample number */
unsigned char volume; /* Current volume */
unsigned char pan; /* Current stereo pan */
unsigned char reserved; /* Reserved */
struct xmp_event event; /* Current track event */
} channel_info[XMP_MAX_CHANNELS];
};
typedef char *xmp_context;
EXPORT extern const char *xmp_version;
EXPORT extern const unsigned int xmp_vercode;
EXPORT xmp_context xmp_create_context (void);
EXPORT void xmp_free_context (xmp_context);
EXPORT int xmp_test_module (char *, struct xmp_test_info *);
EXPORT int xmp_load_module (xmp_context, char *);
EXPORT void xmp_scan_module (xmp_context);
EXPORT void xmp_release_module (xmp_context);
EXPORT int xmp_start_player (xmp_context, int, int);
EXPORT int xmp_play_frame (xmp_context);
EXPORT int xmp_play_buffer (xmp_context, void *, int, int);
EXPORT void xmp_get_frame_info (xmp_context, struct xmp_frame_info *);
EXPORT void xmp_end_player (xmp_context);
EXPORT void xmp_inject_event (xmp_context, int, struct xmp_event *);
EXPORT void xmp_get_module_info (xmp_context, struct xmp_module_info *);
EXPORT char **xmp_get_format_list (void);
EXPORT int xmp_next_position (xmp_context);
EXPORT int xmp_prev_position (xmp_context);
EXPORT int xmp_set_position (xmp_context, int);
EXPORT void xmp_stop_module (xmp_context);
EXPORT void xmp_restart_module (xmp_context);
EXPORT int xmp_seek_time (xmp_context, int);
EXPORT int xmp_channel_mute (xmp_context, int, int);
EXPORT int xmp_channel_vol (xmp_context, int, int);
EXPORT int xmp_set_player (xmp_context, int, int);
EXPORT int xmp_get_player (xmp_context, int);
EXPORT int xmp_set_instrument_path (xmp_context, char *);
EXPORT int xmp_load_module_from_memory (xmp_context, void *, long);
EXPORT int xmp_load_module_from_file (xmp_context, void *, long);
/* External sample mixer API */
EXPORT int xmp_start_smix (xmp_context, int, int);
EXPORT void xmp_end_smix (xmp_context);
EXPORT int xmp_smix_play_instrument(xmp_context, int, int, int, int);
EXPORT int xmp_smix_play_sample (xmp_context, int, int, int, int);
EXPORT int xmp_smix_channel_pan (xmp_context, int, int);
EXPORT int xmp_smix_load_sample (xmp_context, int, char *);
EXPORT int xmp_smix_release_sample (xmp_context, int);
#ifdef __cplusplus
}
#endif
#endif /* XMP_H */

Binary file not shown.

View file

@ -16,8 +16,9 @@ USE_CODEC_FLAC=0
USE_CODEC_MP3=1
USE_CODEC_VORBIS=1
USE_CODEC_OPUS=0
# either mikmod (preferred) or modplug, not both
# either mikmod, or xmp (or modplug.)
USE_CODEC_MIKMOD=0
USE_CODEC_XMP=0
USE_CODEC_MODPLUG=0
USE_CODEC_UMX=0
@ -168,6 +169,10 @@ ifeq ($(USE_CODEC_MIKMOD),1)
CFLAGS+= -DUSE_CODEC_MIKMOD
CODECLIBS+= -lmikmod
endif
ifeq ($(USE_CODEC_XMP),1)
CFLAGS+= -DUSE_CODEC_XMP
CODECLIBS+= -lxmp
endif
ifeq ($(USE_CODEC_MODPLUG),1)
CFLAGS+= -DUSE_CODEC_MODPLUG
CODECLIBS+= -lmodplug
@ -208,6 +213,7 @@ MUSIC_OBJS:= bgmusic.o \
$(mp3_obj) \
snd_mikmod.o \
snd_modplug.o \
snd_xmp.o \
snd_umx.o
COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
SYSOBJ_SND := snd_sdl.o

View file

@ -1,6 +1,6 @@
# GNU Makefile for compiling Mac OS X version of QuakeSpasm.
# Usage: "make -f Makefile.darwin"
# To cross-compile on Linux hosts, see the "build_cross_osx*.sh" scripts.
# To cross-compile on Linux hosts, see the build_cross_osx*.sh scripts.
# "make DEBUG=1" to build a debug client.
# "make SDL_FRAMEWORK_PATH=/path/to/Frameworks" to specify the directory
# containing SDL.framework and override the locally included versions.
@ -18,8 +18,9 @@ USE_CODEC_FLAC=1
USE_CODEC_MP3=1
USE_CODEC_VORBIS=1
USE_CODEC_OPUS=1
# either mikmod (preferred) or modplug, not both
# either mikmod, or xmp (or modplug.)
USE_CODEC_MIKMOD=1
USE_CODEC_XMP=0
USE_CODEC_MODPLUG=0
USE_CODEC_UMX=1
@ -187,6 +188,12 @@ CODEC_INC = -I../MacOSX/codecs/include
CODEC_LINK= -L../MacOSX/codecs/lib
CODECLIBS+= -lmikmod
endif
ifeq ($(USE_CODEC_XMP),1)
CFLAGS+= -DUSE_CODEC_XMP
CODEC_INC = -I../MacOSX/codecs/include
CODEC_LINK= -L../MacOSX/codecs/lib
CODECLIBS+= -lxmp
endif
ifeq ($(USE_CODEC_MODPLUG),1)
CFLAGS+= -DUSE_CODEC_MODPLUG
CODEC_INC = -I../MacOSX/codecs/include
@ -234,6 +241,7 @@ MUSIC_OBJS:= bgmusic.o \
$(mp3_obj) \
snd_mikmod.o \
snd_modplug.o \
snd_xmp.o \
snd_umx.o
COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
SYSOBJ_SND := snd_sdl.o

View file

@ -1,6 +1,6 @@
# GNU Makefile for compiling Win32 quakespasm.exe using MinGW or MinGW-w64.
# Usage: "make -f Makefile.w32"
# To cross-compile on Linux hosts, see the "build_cross_win32*.sh" scripts.
# To cross-compile on Linux hosts, see the build_cross_win32*.sh scripts.
# "make DEBUG=1" to build a debug client.
# "make SDL_CONFIG=/path/to/sdl-config" to override the locally included SDL versions.
# "make WINSOCK2=1" to use WinSock2 api instead of old WinSock 1.1.
@ -14,8 +14,9 @@ USE_CODEC_FLAC=1
USE_CODEC_MP3=1
USE_CODEC_VORBIS=1
USE_CODEC_OPUS=1
# either mikmod (preferred) or modplug, not both
# either mikmod, or xmp (or modplug.)
USE_CODEC_MIKMOD=1
USE_CODEC_XMP=0
USE_CODEC_MODPLUG=0
USE_CODEC_UMX=1
@ -153,6 +154,12 @@ CODEC_INC = -I../Windows/codecs/include
CODEC_LINK= -L../Windows/codecs/x86
CODECLIBS+= -lmikmod
endif
ifeq ($(USE_CODEC_XMP),1)
CFLAGS+= -DUSE_CODEC_XMP
CODEC_INC = -I../Windows/codecs/include
CODEC_LINK= -L../Windows/codecs/x86
CODECLIBS+= -lxmp
endif
ifeq ($(USE_CODEC_MODPLUG),1)
CFLAGS+= -DUSE_CODEC_MODPLUG
CODEC_INC = -I../Windows/codecs/include
@ -198,6 +205,7 @@ MUSIC_OBJS:= bgmusic.o \
$(mp3_obj) \
snd_mikmod.o \
snd_modplug.o \
snd_xmp.o \
snd_umx.o
COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
SYSOBJ_SND := snd_sdl.o

View file

@ -1,6 +1,6 @@
# GNU Makefile for compiling Win64 quakespasm.exe using MinGW-w64.
# Usage: "make -f Makefile.w64"
# To cross-compile on Linux hosts, see the "build_cross_win32*.sh" scripts.
# To cross-compile on Linux hosts, see the build_cross_win32*.sh scripts.
# "make DEBUG=1" to build a debug client.
# "make SDL_CONFIG=/path/to/sdl-config" to override the locally included SDL versions.
# "make WINSOCK2=0" to use the old WinSock 1.1 api (NOT RECOMMENDED)
@ -14,8 +14,9 @@ USE_CODEC_FLAC=1
USE_CODEC_MP3=1
USE_CODEC_VORBIS=1
USE_CODEC_OPUS=1
# either mikmod (preferred) or modplug, not both
# either mikmod, or xmp (or modplug.)
USE_CODEC_MIKMOD=1
USE_CODEC_XMP=0
USE_CODEC_MODPLUG=0
USE_CODEC_UMX=1
@ -151,6 +152,12 @@ CODEC_INC = -I../Windows/codecs/include
CODEC_LINK= -L../Windows/codecs/x64
CODECLIBS+= -lmikmod
endif
ifeq ($(USE_CODEC_XMP),1)
CFLAGS+= -DUSE_CODEC_XMP
CODEC_INC = -I../Windows/codecs/include
CODEC_LINK= -L../Windows/codecs/x64
CODECLIBS+= -lxmp
endif
ifeq ($(USE_CODEC_MODPLUG),1)
CFLAGS+= -DUSE_CODEC_MODPLUG
CODEC_INC = -I../Windows/codecs/include
@ -196,6 +203,7 @@ MUSIC_OBJS:= bgmusic.o \
$(mp3_obj) \
snd_mikmod.o \
snd_modplug.o \
snd_xmp.o \
snd_umx.o
COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
SYSOBJ_SND := snd_sdl.o

View file

@ -30,6 +30,7 @@
/* headers for individual codecs */
#include "snd_mikmod.h"
#include "snd_modplug.h"
#include "snd_xmp.h"
#include "snd_umx.h"
#include "snd_wave.h"
#include "snd_flac.h"
@ -72,6 +73,9 @@ void S_CodecInit (void)
#ifdef USE_CODEC_MIKMOD
S_CodecRegister(&mikmod_codec);
#endif
#ifdef USE_CODEC_XMP
S_CodecRegister(&xmp_codec);
#endif
#ifdef USE_CODEC_WAVE
S_CodecRegister(&wav_codec);
#endif

165
quakespasm/Quake/snd_xmp.c Normal file
View file

@ -0,0 +1,165 @@
/* tracker music (module file) decoding support using libxmp >= v4.2.0
* https://sourceforge.net/projects/xmp/
* https://github.com/cmatsuoka/libxmp.git
*
* Copyright (C) 2016 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_XMP)
#include "snd_codec.h"
#include "snd_codeci.h"
#include "snd_xmp.h"
#include <xmp.h>
#if ((XMP_VERCODE+0) < 0x040200)
#error libxmp version 4.2 or newer is required
#endif
static int S_XMP_StartPlay (snd_stream_t *stream)
{
int fmt = 0;
if (stream->info.channels == 1)
fmt |= XMP_FORMAT_MONO;
if (stream->info.width == 1)
fmt |= XMP_FORMAT_8BIT|XMP_FORMAT_UNSIGNED;
return xmp_start_player((xmp_context)stream->priv, stream->info.rate, fmt);
}
static qboolean S_XMP_CodecInitialize (void)
{
return true;
}
static void S_XMP_CodecShutdown (void)
{
}
static qboolean S_XMP_CodecOpenStream (snd_stream_t *stream)
{
/* need to load the whole file into memory and pass it to libxmp
* using xmp_load_module_from_memory() which requires libxmp >= 4.2.
* libxmp-4.0/4.1 only have xmp_load_module() which accepts a file
* name which isn't good with files in containers like paks, etc. */
xmp_context c;
byte *moddata;
long len;
int mark;
c = xmp_create_context();
if (c == NULL)
return false;
len = FS_filelength (&stream->fh);
mark = Hunk_LowMark();
moddata = (byte *) Hunk_Alloc(len);
FS_fread(moddata, 1, len, &stream->fh);
if (xmp_load_module_from_memory(c, moddata, len) != 0)
{
Con_DPrintf("Could not load module %s\n", stream->name);
goto err1;
}
Hunk_FreeToLowMark(mark); /* free original file data */
stream->priv = c;
if (shm->speed > XMP_MAX_SRATE)
stream->info.rate = 44100;
else if (shm->speed < XMP_MIN_SRATE)
stream->info.rate = 11025;
else stream->info.rate = shm->speed;
stream->info.bits = shm->samplebits;
stream->info.width = stream->info.bits / 8;
stream->info.channels = shm->channels;
if (S_XMP_StartPlay(stream) != 0)
goto err2;
/* percentual left/right channel separation, default is 70. */
if (stream->info.channels == 2)
if (xmp_set_player(c, XMP_PLAYER_MIX, 100) != 0)
goto err3;
/* interpolation type, default is XMP_INTERP_LINEAR */
if (xmp_set_player(c, XMP_PLAYER_INTERP, XMP_INTERP_SPLINE) != 0)
goto err3;
return true;
err3: xmp_end_player(c);
err2: xmp_release_module(c);
err1: xmp_free_context(c);
return false;
}
static int S_XMP_CodecReadStream (snd_stream_t *stream, int bytes, void *buffer)
{
int r;
/* xmp_play_buffer() requires libxmp >= 4.1. it will write
* native-endian pcm data to the buffer. if the data write
* is partial, the rest of the buffer will be zero-filled.
* the last param is the number that the current sequence of
* the song will be looped at max. */
r = xmp_play_buffer((xmp_context)stream->priv, buffer, bytes, 1);
if (r == 0) {
return bytes;
}
if (r == -XMP_END) {
Con_DPrintf("XMP EOF\n");
return 0;
}
return -1;
}
static void S_XMP_CodecCloseStream (snd_stream_t *stream)
{
xmp_context c = (xmp_context)stream->priv;
xmp_end_player(c);
xmp_release_module(c);
xmp_free_context(c);
S_CodecUtilClose(&stream);
}
static int S_XMP_CodecRewindStream (snd_stream_t *stream)
{
int ret;
ret = S_XMP_StartPlay(stream);
if (ret < 0) return ret;
/*ret = xmp_set_position((xmp_context)stream->priv, 0);*/
ret = xmp_seek_time((xmp_context)stream->priv, 0);
if (ret < 0) return ret;
return 0;
}
snd_codec_t xmp_codec =
{
CODECTYPE_MOD,
true, /* always available. */
"s3m",
S_XMP_CodecInitialize,
S_XMP_CodecShutdown,
S_XMP_CodecOpenStream,
S_XMP_CodecReadStream,
S_XMP_CodecRewindStream,
S_XMP_CodecCloseStream,
NULL
};
#endif /* USE_CODEC_XMP */

View file

@ -0,0 +1,12 @@
/* module tracker decoding support using libxmp */
#if !defined(_SND_XMP_H_)
#define _SND_XMP_H_
#if defined(USE_CODEC_XMP)
extern snd_codec_t xmp_codec;
#endif /* USE_CODEC_XMP */
#endif /* ! _SND_XMP_H_ */

View file

@ -308,6 +308,10 @@
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\..\Quake\snd_wave.h" />
<Unit filename="..\..\Quake\snd_xmp.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\..\Quake\snd_xmp.h" />
<Unit filename="..\..\Quake\spritegn.h" />
<Unit filename="..\..\Quake\strl_fn.h" />
<Unit filename="..\..\Quake\strlcat.c">

View file

@ -307,6 +307,10 @@
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\..\Quake\snd_wave.h" />
<Unit filename="..\..\Quake\snd_xmp.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\..\Quake\snd_xmp.h" />
<Unit filename="..\..\Quake\spritegn.h" />
<Unit filename="..\..\Quake\strl_fn.h" />
<Unit filename="..\..\Quake\strlcat.c">

View file

@ -585,6 +585,10 @@
RelativePath="..\..\Quake\snd_wave.c"
>
</File>
<File
RelativePath="..\..\Quake\snd_xmp.c"
>
</File>
<File
RelativePath="..\..\Quake\strlcat.c"
>
@ -855,6 +859,10 @@
RelativePath="..\..\Quake\snd_wave.h"
>
</File>
<File
RelativePath="..\..\Quake\snd_xmp.h"
>
</File>
<File
RelativePath="..\..\Quake\spritegn.h"
>

View file

@ -585,6 +585,10 @@
RelativePath="..\..\Quake\snd_wave.c"
>
</File>
<File
RelativePath="..\..\Quake\snd_xmp.c"
>
</File>
<File
RelativePath="..\..\Quake\strlcat.c"
>
@ -855,6 +859,10 @@
RelativePath="..\..\Quake\snd_wave.h"
>
</File>
<File
RelativePath="..\..\Quake\snd_xmp.h"
>
</File>
<File
RelativePath="..\..\Quake\spritegn.h"
>

View file

@ -0,0 +1,360 @@
#ifndef XMP_H
#define XMP_H
#ifdef __cplusplus
extern "C" {
#endif
#define XMP_VERSION "4.4.2"
#define XMP_VERCODE 0x040402
#define XMP_VER_MAJOR 4
#define XMP_VER_MINOR 4
#define XMP_VER_RELEASE 2
#if defined(_WIN32) && !defined(__CYGWIN__)
# if defined(BUILDING_STATIC)
# define EXPORT
# elif defined(BUILDING_DLL)
# define EXPORT __declspec(dllexport)
# else
# define EXPORT __declspec(dllimport)
# endif
#elif defined(__OS2__) && defined(__WATCOMC__) && defined(__SW_BD)
# define EXPORT __declspec(dllexport)
#elif (defined(__GNUC__) || defined(__clang__) || defined(__HP_cc)) && defined(XMP_SYM_VISIBILITY)
# define EXPORT __attribute__((visibility ("default")))
#elif defined(__SUNPRO_C) && defined(XMP_LDSCOPE_GLOBAL)
# define EXPORT __global
#elif defined(EMSCRIPTEN)
# define EXPORT EMSCRIPTEN_KEEPALIVE
#else
# define EXPORT
#endif
#define XMP_NAME_SIZE 64 /* Size of module name and type */
#define XMP_KEY_OFF 0x81 /* Note number for key off event */
#define XMP_KEY_CUT 0x82 /* Note number for key cut event */
#define XMP_KEY_FADE 0x83 /* Note number for fade event */
/* mixer parameter macros */
/* sample format flags */
#define XMP_FORMAT_8BIT (1 << 0) /* Mix to 8-bit instead of 16 */
#define XMP_FORMAT_UNSIGNED (1 << 1) /* Mix to unsigned samples */
#define XMP_FORMAT_MONO (1 << 2) /* Mix to mono instead of stereo */
/* player parameters */
#define XMP_PLAYER_AMP 0 /* Amplification factor */
#define XMP_PLAYER_MIX 1 /* Stereo mixing */
#define XMP_PLAYER_INTERP 2 /* Interpolation type */
#define XMP_PLAYER_DSP 3 /* DSP effect flags */
#define XMP_PLAYER_FLAGS 4 /* Player flags */
#define XMP_PLAYER_CFLAGS 5 /* Player flags for current module */
#define XMP_PLAYER_SMPCTL 6 /* Sample control flags */
#define XMP_PLAYER_VOLUME 7 /* Player module volume */
#define XMP_PLAYER_STATE 8 /* Internal player state (read only) */
#define XMP_PLAYER_SMIX_VOLUME 9 /* SMIX volume */
#define XMP_PLAYER_DEFPAN 10 /* Default pan setting */
#define XMP_PLAYER_MODE 11 /* Player personality */
#define XMP_PLAYER_MIXER_TYPE 12 /* Current mixer (read only) */
#define XMP_PLAYER_VOICES 13 /* Maximum number of mixer voices */
/* interpolation types */
#define XMP_INTERP_NEAREST 0 /* Nearest neighbor */
#define XMP_INTERP_LINEAR 1 /* Linear (default) */
#define XMP_INTERP_SPLINE 2 /* Cubic spline */
/* dsp effect types */
#define XMP_DSP_LOWPASS (1 << 0) /* Lowpass filter effect */
#define XMP_DSP_ALL (XMP_DSP_LOWPASS)
/* player state */
#define XMP_STATE_UNLOADED 0 /* Context created */
#define XMP_STATE_LOADED 1 /* Module loaded */
#define XMP_STATE_PLAYING 2 /* Module playing */
/* player flags */
#define XMP_FLAGS_VBLANK (1 << 0) /* Use vblank timing */
#define XMP_FLAGS_FX9BUG (1 << 1) /* Emulate FX9 bug */
#define XMP_FLAGS_FIXLOOP (1 << 2) /* Emulate sample loop bug */
#define XMP_FLAGS_A500 (1 << 3) /* Use Paula mixer in Amiga modules */
/* player modes */
#define XMP_MODE_AUTO 0 /* Autodetect mode (default) */
#define XMP_MODE_MOD 1 /* Play as a generic MOD player */
#define XMP_MODE_NOISETRACKER 2 /* Play using Noisetracker quirks */
#define XMP_MODE_PROTRACKER 3 /* Play using Protracker quirks */
#define XMP_MODE_S3M 4 /* Play as a generic S3M player */
#define XMP_MODE_ST3 5 /* Play using ST3 bug emulation */
#define XMP_MODE_ST3GUS 6 /* Play using ST3+GUS quirks */
#define XMP_MODE_XM 7 /* Play as a generic XM player */
#define XMP_MODE_FT2 8 /* Play using FT2 bug emulation */
#define XMP_MODE_IT 9 /* Play using IT quirks */
#define XMP_MODE_ITSMP 10 /* Play using IT sample mode quirks */
/* mixer types */
#define XMP_MIXER_STANDARD 0 /* Standard mixer */
#define XMP_MIXER_A500 1 /* Amiga 500 */
#define XMP_MIXER_A500F 2 /* Amiga 500 with led filter */
/* sample flags */
#define XMP_SMPCTL_SKIP (1 << 0) /* Don't load samples */
/* limits */
#define XMP_MAX_KEYS 121 /* Number of valid keys */
#define XMP_MAX_ENV_POINTS 32 /* Max number of envelope points */
#define XMP_MAX_MOD_LENGTH 256 /* Max number of patterns in module */
#define XMP_MAX_CHANNELS 64 /* Max number of channels in module */
#define XMP_MAX_SRATE 49170 /* max sampling rate (Hz) */
#define XMP_MIN_SRATE 4000 /* min sampling rate (Hz) */
#define XMP_MIN_BPM 20 /* min BPM */
/* frame rate = (50 * bpm / 125) Hz */
/* frame size = (sampling rate * channels * size) / frame rate */
#define XMP_MAX_FRAMESIZE (5 * XMP_MAX_SRATE * 2 / XMP_MIN_BPM)
/* error codes */
#define XMP_END 1
#define XMP_ERROR_INTERNAL 2 /* Internal error */
#define XMP_ERROR_FORMAT 3 /* Unsupported module format */
#define XMP_ERROR_LOAD 4 /* Error loading file */
#define XMP_ERROR_DEPACK 5 /* Error depacking file */
#define XMP_ERROR_SYSTEM 6 /* System error */
#define XMP_ERROR_INVALID 7 /* Invalid parameter */
#define XMP_ERROR_STATE 8 /* Invalid player state */
struct xmp_channel {
int pan; /* Channel pan (0x80 is center) */
int vol; /* Channel volume */
#define XMP_CHANNEL_SYNTH (1 << 0) /* Channel is synthesized */
#define XMP_CHANNEL_MUTE (1 << 1) /* Channel is muted */
#define XMP_CHANNEL_SPLIT (1 << 2) /* Split Amiga channel in bits 5-4 */
#define XMP_CHANNEL_SURROUND (1 << 4) /* Surround channel */
int flg; /* Channel flags */
};
struct xmp_pattern {
int rows; /* Number of rows */
int index[1]; /* Track index */
};
struct xmp_event {
unsigned char note; /* Note number (0 means no note) */
unsigned char ins; /* Patch number */
unsigned char vol; /* Volume (0 to basevol) */
unsigned char fxt; /* Effect type */
unsigned char fxp; /* Effect parameter */
unsigned char f2t; /* Secondary effect type */
unsigned char f2p; /* Secondary effect parameter */
unsigned char _flag; /* Internal (reserved) flags */
};
struct xmp_track {
int rows; /* Number of rows */
struct xmp_event event[1]; /* Event data */
};
struct xmp_envelope {
#define XMP_ENVELOPE_ON (1 << 0) /* Envelope is enabled */
#define XMP_ENVELOPE_SUS (1 << 1) /* Envelope has sustain point */
#define XMP_ENVELOPE_LOOP (1 << 2) /* Envelope has loop */
#define XMP_ENVELOPE_FLT (1 << 3) /* Envelope is used for filter */
#define XMP_ENVELOPE_SLOOP (1 << 4) /* Envelope has sustain loop */
#define XMP_ENVELOPE_CARRY (1 << 5) /* Don't reset envelope position */
int flg; /* Flags */
int npt; /* Number of envelope points */
int scl; /* Envelope scaling */
int sus; /* Sustain start point */
int sue; /* Sustain end point */
int lps; /* Loop start point */
int lpe; /* Loop end point */
short data[XMP_MAX_ENV_POINTS * 2];
};
struct xmp_instrument {
char name[32]; /* Instrument name */
int vol; /* Instrument volume */
int nsm; /* Number of samples */
int rls; /* Release (fadeout) */
struct xmp_envelope aei; /* Amplitude envelope info */
struct xmp_envelope pei; /* Pan envelope info */
struct xmp_envelope fei; /* Frequency envelope info */
struct {
unsigned char ins; /* Instrument number for each key */
signed char xpo; /* Instrument transpose for each key */
} map[XMP_MAX_KEYS];
struct xmp_subinstrument {
int vol; /* Default volume */
int gvl; /* Global volume */
int pan; /* Pan */
int xpo; /* Transpose */
int fin; /* Finetune */
int vwf; /* Vibrato waveform */
int vde; /* Vibrato depth */
int vra; /* Vibrato rate */
int vsw; /* Vibrato sweep */
int rvv; /* Random volume/pan variation (IT) */
int sid; /* Sample number */
#define XMP_INST_NNA_CUT 0x00
#define XMP_INST_NNA_CONT 0x01
#define XMP_INST_NNA_OFF 0x02
#define XMP_INST_NNA_FADE 0x03
int nna; /* New note action */
#define XMP_INST_DCT_OFF 0x00
#define XMP_INST_DCT_NOTE 0x01
#define XMP_INST_DCT_SMP 0x02
#define XMP_INST_DCT_INST 0x03
int dct; /* Duplicate check type */
#define XMP_INST_DCA_CUT XMP_INST_NNA_CUT
#define XMP_INST_DCA_OFF XMP_INST_NNA_OFF
#define XMP_INST_DCA_FADE XMP_INST_NNA_FADE
int dca; /* Duplicate check action */
int ifc; /* Initial filter cutoff */
int ifr; /* Initial filter resonance */
} *sub;
void *extra; /* Extra fields */
};
struct xmp_sample {
char name[32]; /* Sample name */
int len; /* Sample length */
int lps; /* Loop start */
int lpe; /* Loop end */
#define XMP_SAMPLE_16BIT (1 << 0) /* 16bit sample */
#define XMP_SAMPLE_LOOP (1 << 1) /* Sample is looped */
#define XMP_SAMPLE_LOOP_BIDIR (1 << 2) /* Bidirectional sample loop */
#define XMP_SAMPLE_LOOP_REVERSE (1 << 3) /* Backwards sample loop */
#define XMP_SAMPLE_LOOP_FULL (1 << 4) /* Play full sample before looping */
#define XMP_SAMPLE_SLOOP (1 << 5) /* Sample has sustain loop */
#define XMP_SAMPLE_SLOOP_BIDIR (1 << 6) /* Bidirectional sustain loop */
#define XMP_SAMPLE_SYNTH (1 << 15) /* Data contains synth patch */
int flg; /* Flags */
unsigned char *data; /* Sample data */
};
struct xmp_sequence {
int entry_point;
int duration;
};
struct xmp_module {
char name[XMP_NAME_SIZE]; /* Module title */
char type[XMP_NAME_SIZE]; /* Module format */
int pat; /* Number of patterns */
int trk; /* Number of tracks */
int chn; /* Tracks per pattern */
int ins; /* Number of instruments */
int smp; /* Number of samples */
int spd; /* Initial speed */
int bpm; /* Initial BPM */
int len; /* Module length in patterns */
int rst; /* Restart position */
int gvl; /* Global volume */
struct xmp_pattern **xxp; /* Patterns */
struct xmp_track **xxt; /* Tracks */
struct xmp_instrument *xxi; /* Instruments */
struct xmp_sample *xxs; /* Samples */
struct xmp_channel xxc[XMP_MAX_CHANNELS]; /* Channel info */
unsigned char xxo[XMP_MAX_MOD_LENGTH]; /* Orders */
};
struct xmp_test_info {
char name[XMP_NAME_SIZE]; /* Module title */
char type[XMP_NAME_SIZE]; /* Module format */
};
struct xmp_module_info {
unsigned char md5[16]; /* MD5 message digest */
int vol_base; /* Volume scale */
struct xmp_module *mod; /* Pointer to module data */
char *comment; /* Comment text, if any */
int num_sequences; /* Number of valid sequences */
struct xmp_sequence *seq_data; /* Pointer to sequence data */
};
struct xmp_frame_info { /* Current frame information */
int pos; /* Current position */
int pattern; /* Current pattern */
int row; /* Current row in pattern */
int num_rows; /* Number of rows in current pattern */
int frame; /* Current frame */
int speed; /* Current replay speed */
int bpm; /* Current bpm */
int time; /* Current module time in ms */
int total_time; /* Estimated replay time in ms*/
int frame_time; /* Frame replay time in us */
void *buffer; /* Pointer to sound buffer */
int buffer_size; /* Used buffer size */
int total_size; /* Total buffer size */
int volume; /* Current master volume */
int loop_count; /* Loop counter */
int virt_channels; /* Number of virtual channels */
int virt_used; /* Used virtual channels */
int sequence; /* Current sequence */
struct xmp_channel_info { /* Current channel information */
unsigned int period; /* Sample period (* 4096) */
unsigned int position; /* Sample position */
short pitchbend; /* Linear bend from base note*/
unsigned char note; /* Current base note number */
unsigned char instrument; /* Current instrument number */
unsigned char sample; /* Current sample number */
unsigned char volume; /* Current volume */
unsigned char pan; /* Current stereo pan */
unsigned char reserved; /* Reserved */
struct xmp_event event; /* Current track event */
} channel_info[XMP_MAX_CHANNELS];
};
typedef char *xmp_context;
EXPORT extern const char *xmp_version;
EXPORT extern const unsigned int xmp_vercode;
EXPORT xmp_context xmp_create_context (void);
EXPORT void xmp_free_context (xmp_context);
EXPORT int xmp_test_module (char *, struct xmp_test_info *);
EXPORT int xmp_load_module (xmp_context, char *);
EXPORT void xmp_scan_module (xmp_context);
EXPORT void xmp_release_module (xmp_context);
EXPORT int xmp_start_player (xmp_context, int, int);
EXPORT int xmp_play_frame (xmp_context);
EXPORT int xmp_play_buffer (xmp_context, void *, int, int);
EXPORT void xmp_get_frame_info (xmp_context, struct xmp_frame_info *);
EXPORT void xmp_end_player (xmp_context);
EXPORT void xmp_inject_event (xmp_context, int, struct xmp_event *);
EXPORT void xmp_get_module_info (xmp_context, struct xmp_module_info *);
EXPORT char **xmp_get_format_list (void);
EXPORT int xmp_next_position (xmp_context);
EXPORT int xmp_prev_position (xmp_context);
EXPORT int xmp_set_position (xmp_context, int);
EXPORT void xmp_stop_module (xmp_context);
EXPORT void xmp_restart_module (xmp_context);
EXPORT int xmp_seek_time (xmp_context, int);
EXPORT int xmp_channel_mute (xmp_context, int, int);
EXPORT int xmp_channel_vol (xmp_context, int, int);
EXPORT int xmp_set_player (xmp_context, int, int);
EXPORT int xmp_get_player (xmp_context, int);
EXPORT int xmp_set_instrument_path (xmp_context, char *);
EXPORT int xmp_load_module_from_memory (xmp_context, void *, long);
EXPORT int xmp_load_module_from_file (xmp_context, void *, long);
/* External sample mixer API */
EXPORT int xmp_start_smix (xmp_context, int, int);
EXPORT void xmp_end_smix (xmp_context);
EXPORT int xmp_smix_play_instrument(xmp_context, int, int, int, int);
EXPORT int xmp_smix_play_sample (xmp_context, int, int, int, int);
EXPORT int xmp_smix_channel_pan (xmp_context, int, int);
EXPORT int xmp_smix_load_sample (xmp_context, int, char *);
EXPORT int xmp_smix_release_sample (xmp_context, int);
#ifdef __cplusplus
}
#endif
#endif /* XMP_H */

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.