diff --git a/Linux/CodeBlocks/QuakeSpasm-SDL2.cbp b/Linux/CodeBlocks/QuakeSpasm-SDL2.cbp index 3085352e..c726ba4b 100644 --- a/Linux/CodeBlocks/QuakeSpasm-SDL2.cbp +++ b/Linux/CodeBlocks/QuakeSpasm-SDL2.cbp @@ -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"> diff --git a/Linux/CodeBlocks/QuakeSpasm.cbp b/Linux/CodeBlocks/QuakeSpasm.cbp index b1812e31..cb2e1bd0 100644 --- a/Linux/CodeBlocks/QuakeSpasm.cbp +++ b/Linux/CodeBlocks/QuakeSpasm.cbp @@ -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"> diff --git a/MacOSX/codecs/include/xmp.h b/MacOSX/codecs/include/xmp.h new file mode 100644 index 00000000..52a8257e --- /dev/null +++ b/MacOSX/codecs/include/xmp.h @@ -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 */ diff --git a/MacOSX/codecs/lib/libxmp.dylib b/MacOSX/codecs/lib/libxmp.dylib new file mode 100755 index 00000000..49401edb Binary files /dev/null and b/MacOSX/codecs/lib/libxmp.dylib differ diff --git a/Quake/Makefile b/Quake/Makefile index d0c8214e..ce000730 100644 --- a/Quake/Makefile +++ b/Quake/Makefile @@ -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 diff --git a/Quake/Makefile.darwin b/Quake/Makefile.darwin index 258f7c51..5e59d219 100644 --- a/Quake/Makefile.darwin +++ b/Quake/Makefile.darwin @@ -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 diff --git a/Quake/Makefile.w32 b/Quake/Makefile.w32 index 1b84bc3d..bfc34be7 100644 --- a/Quake/Makefile.w32 +++ b/Quake/Makefile.w32 @@ -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 diff --git a/Quake/Makefile.w64 b/Quake/Makefile.w64 index 538a9d62..6ae90860 100644 --- a/Quake/Makefile.w64 +++ b/Quake/Makefile.w64 @@ -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 diff --git a/Quake/snd_codec.c b/Quake/snd_codec.c index 243dd3d0..96a82d79 100644 --- a/Quake/snd_codec.c +++ b/Quake/snd_codec.c @@ -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 diff --git a/Quake/snd_xmp.c b/Quake/snd_xmp.c new file mode 100644 index 00000000..90718fb0 --- /dev/null +++ b/Quake/snd_xmp.c @@ -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 */ diff --git a/Quake/snd_xmp.h b/Quake/snd_xmp.h new file mode 100644 index 00000000..9516a498 --- /dev/null +++ b/Quake/snd_xmp.h @@ -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_ */ + diff --git a/Windows/CodeBlocks/QuakeSpasm-SDL2.cbp b/Windows/CodeBlocks/QuakeSpasm-SDL2.cbp index 396442b3..2b312ae8 100644 --- a/Windows/CodeBlocks/QuakeSpasm-SDL2.cbp +++ b/Windows/CodeBlocks/QuakeSpasm-SDL2.cbp @@ -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"> diff --git a/Windows/CodeBlocks/QuakeSpasm.cbp b/Windows/CodeBlocks/QuakeSpasm.cbp index 63015844..58398cc1 100644 --- a/Windows/CodeBlocks/QuakeSpasm.cbp +++ b/Windows/CodeBlocks/QuakeSpasm.cbp @@ -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"> diff --git a/Windows/VisualStudio/quakespasm-sdl2.vcproj b/Windows/VisualStudio/quakespasm-sdl2.vcproj index a9ff8532..8e86a0e0 100644 --- a/Windows/VisualStudio/quakespasm-sdl2.vcproj +++ b/Windows/VisualStudio/quakespasm-sdl2.vcproj @@ -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" > diff --git a/Windows/VisualStudio/quakespasm.vcproj b/Windows/VisualStudio/quakespasm.vcproj index c93207ac..a38c42a6 100644 --- a/Windows/VisualStudio/quakespasm.vcproj +++ b/Windows/VisualStudio/quakespasm.vcproj @@ -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" > diff --git a/Windows/codecs/include/xmp.h b/Windows/codecs/include/xmp.h new file mode 100644 index 00000000..52a8257e --- /dev/null +++ b/Windows/codecs/include/xmp.h @@ -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 */ diff --git a/Windows/codecs/x64/libxmp.dll b/Windows/codecs/x64/libxmp.dll new file mode 100644 index 00000000..3cd61103 Binary files /dev/null and b/Windows/codecs/x64/libxmp.dll differ diff --git a/Windows/codecs/x64/libxmp.dll.a b/Windows/codecs/x64/libxmp.dll.a new file mode 100644 index 00000000..abe2da52 Binary files /dev/null and b/Windows/codecs/x64/libxmp.dll.a differ diff --git a/Windows/codecs/x64/libxmp.lib b/Windows/codecs/x64/libxmp.lib new file mode 100644 index 00000000..c3d388a0 Binary files /dev/null and b/Windows/codecs/x64/libxmp.lib differ diff --git a/Windows/codecs/x86/libxmp.dll b/Windows/codecs/x86/libxmp.dll new file mode 100644 index 00000000..d2d5b2e4 Binary files /dev/null and b/Windows/codecs/x86/libxmp.dll differ diff --git a/Windows/codecs/x86/libxmp.dll.a b/Windows/codecs/x86/libxmp.dll.a new file mode 100644 index 00000000..7d25914a Binary files /dev/null and b/Windows/codecs/x86/libxmp.dll.a differ diff --git a/Windows/codecs/x86/libxmp.lib b/Windows/codecs/x86/libxmp.lib new file mode 100644 index 00000000..eb373f7d Binary files /dev/null and b/Windows/codecs/x86/libxmp.lib differ