mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-23 07:30:40 +00:00
- removed libxmp.
This commit is contained in:
parent
ec6ce8b1ec
commit
9782b8180a
47 changed files with 0 additions and 17726 deletions
|
@ -1,42 +0,0 @@
|
|||
__ _ __ ___ __
|
||||
/ / (_) / __ __ __ _ ___ ____/ (_) /____
|
||||
/ /__/ / _ \\ \ // ' \/ _ \/___/ / / __/ -_)
|
||||
/____/_/_.__/_\_\/_/_/_/ .__/ /_/_/\__/\__/
|
||||
/_/
|
||||
|
||||
Libxmp-lite is a lean and lightweight subset of Libxmp that plays MOD, S3M,
|
||||
XM, and IT modules and retains full compatibility with the original API.
|
||||
It's intended for games and small or embedded applications where module
|
||||
format diversity and file depacking are not required.
|
||||
|
||||
Library size can be further reduced by disabling Impulse Tracker format
|
||||
support (configure with --disable-it). This option will also disable IT
|
||||
effects and lowpass filtering.
|
||||
|
||||
Please refer to http://xmp.sf.net/libxmp.html for details on the current
|
||||
Libxmp API.
|
||||
|
||||
|
||||
LICENSE
|
||||
|
||||
Extended Module Player Lite
|
||||
Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
|
@ -1,375 +0,0 @@
|
|||
#ifndef XMP_H
|
||||
#define XMP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define XMP_VERSION "4.5.0"
|
||||
#define XMP_VERCODE 0x040500
|
||||
#define XMP_VER_MAJOR 4
|
||||
#define XMP_VER_MINOR 5
|
||||
#define XMP_VER_RELEASE 0
|
||||
#define BUILDING_STATIC
|
||||
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
# if defined(BUILDING_STATIC)
|
||||
# define LIBXMP_EXPORT
|
||||
# elif defined(BUILDING_DLL)
|
||||
# define LIBXMP_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# define LIBXMP_EXPORT __declspec(dllimport)
|
||||
# endif
|
||||
#elif defined(__OS2__) && defined(__WATCOMC__) && defined(__SW_BD)
|
||||
# define LIBXMP_EXPORT __declspec(dllexport)
|
||||
#elif (defined(__GNUC__) || defined(__clang__) || defined(__HP_cc)) && defined(XMP_SYM_VISIBILITY)
|
||||
# define LIBXMP_EXPORT __attribute__((visibility ("default")))
|
||||
#elif defined(__SUNPRO_C) && defined(XMP_LDSCOPE_GLOBAL)
|
||||
# define LIBXMP_EXPORT __global
|
||||
#elif defined(EMSCRIPTEN)
|
||||
# define LIBXMP_EXPORT EMSCRIPTEN_KEEPALIVE
|
||||
#else
|
||||
# define LIBXMP_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_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 */
|
||||
};
|
||||
|
||||
|
||||
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 *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_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 */
|
||||
};
|
||||
|
||||
|
||||
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 channel_info[XMP_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
|
||||
typedef char *xmp_context;
|
||||
|
||||
LIBXMP_EXPORT extern const char *xmp_version;
|
||||
LIBXMP_EXPORT extern const unsigned int xmp_vercode;
|
||||
|
||||
LIBXMP_EXPORT xmp_context xmp_create_context (void);
|
||||
LIBXMP_EXPORT void xmp_free_context (xmp_context);
|
||||
#ifdef EDUKE32_DISABLED
|
||||
LIBXMP_EXPORT int xmp_test_module (char *, struct xmp_test_info *);
|
||||
LIBXMP_EXPORT int xmp_load_module (xmp_context, char *);
|
||||
#endif
|
||||
LIBXMP_EXPORT void xmp_scan_module (xmp_context);
|
||||
LIBXMP_EXPORT void xmp_release_module (xmp_context);
|
||||
LIBXMP_EXPORT int xmp_start_player (xmp_context, int, int);
|
||||
LIBXMP_EXPORT int xmp_play_frame (xmp_context);
|
||||
LIBXMP_EXPORT int xmp_play_buffer (xmp_context, void *, int, int);
|
||||
LIBXMP_EXPORT void xmp_get_frame_info (xmp_context, struct xmp_frame_info *);
|
||||
LIBXMP_EXPORT void xmp_end_player (xmp_context);
|
||||
LIBXMP_EXPORT void xmp_inject_event (xmp_context, int, struct xmp_event *);
|
||||
LIBXMP_EXPORT void xmp_get_module_info (xmp_context, struct xmp_module_info *);
|
||||
LIBXMP_EXPORT const char **xmp_get_format_list (void);
|
||||
LIBXMP_EXPORT int xmp_next_position (xmp_context);
|
||||
LIBXMP_EXPORT int xmp_prev_position (xmp_context);
|
||||
LIBXMP_EXPORT int xmp_set_position (xmp_context, int);
|
||||
LIBXMP_EXPORT int xmp_set_row (xmp_context, int);
|
||||
LIBXMP_EXPORT int xmp_set_tempo_factor(xmp_context, double);
|
||||
LIBXMP_EXPORT void xmp_stop_module (xmp_context);
|
||||
LIBXMP_EXPORT void xmp_restart_module (xmp_context);
|
||||
LIBXMP_EXPORT int xmp_seek_time (xmp_context, int);
|
||||
LIBXMP_EXPORT int xmp_channel_mute (xmp_context, int, int);
|
||||
LIBXMP_EXPORT int xmp_channel_vol (xmp_context, int, int);
|
||||
LIBXMP_EXPORT int xmp_set_player (xmp_context, int, int);
|
||||
LIBXMP_EXPORT int xmp_get_player (xmp_context, int);
|
||||
LIBXMP_EXPORT int xmp_set_instrument_path (xmp_context, char *);
|
||||
LIBXMP_EXPORT int xmp_load_module_from_memory (xmp_context, void *, long);
|
||||
#ifdef EDUKE32_DISABLED
|
||||
LIBXMP_EXPORT int xmp_load_module_from_file (xmp_context, void *, long);
|
||||
#endif
|
||||
/* External sample mixer API */
|
||||
LIBXMP_EXPORT int xmp_start_smix (xmp_context, int, int);
|
||||
LIBXMP_EXPORT void xmp_end_smix (xmp_context);
|
||||
LIBXMP_EXPORT int xmp_smix_play_instrument(xmp_context, int, int, int, int);
|
||||
LIBXMP_EXPORT int xmp_smix_play_sample (xmp_context, int, int, int, int);
|
||||
LIBXMP_EXPORT int xmp_smix_channel_pan (xmp_context, int, int);
|
||||
#ifdef EDUKE32_DISABLED
|
||||
LIBXMP_EXPORT int xmp_smix_load_sample (xmp_context, int, char *);
|
||||
#endif
|
||||
LIBXMP_EXPORT int xmp_smix_release_sample (xmp_context, int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* XMP_H */
|
|
@ -1,366 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#ifdef __WATCOMC__
|
||||
#include <direct.h>
|
||||
#elif !defined(_WIN32)
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#include "xmp.h"
|
||||
#include "common.h"
|
||||
#include "period.h"
|
||||
#include "loader.h"
|
||||
|
||||
int libxmp_init_instrument(struct module_data *m)
|
||||
{
|
||||
struct xmp_module *mod = &m->mod;
|
||||
|
||||
if (mod->ins > 0) {
|
||||
mod->xxi = (struct xmp_instrument *)calloc(sizeof (struct xmp_instrument), mod->ins);
|
||||
if (mod->xxi == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mod->smp > 0) {
|
||||
int i;
|
||||
|
||||
mod->xxs = (struct xmp_sample *)calloc(sizeof (struct xmp_sample), mod->smp);
|
||||
if (mod->xxs == NULL)
|
||||
return -1;
|
||||
m->xtra = (struct extra_sample_data *)calloc(sizeof (struct extra_sample_data), mod->smp);
|
||||
if (m->xtra == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < mod->smp; i++) {
|
||||
m->xtra[i].c5spd = m->c4rate;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxmp_alloc_subinstrument(struct xmp_module *mod, int i, int num)
|
||||
{
|
||||
if (num == 0)
|
||||
return 0;
|
||||
|
||||
mod->xxi[i].sub = (struct xmp_subinstrument *)calloc(sizeof (struct xmp_subinstrument), num);
|
||||
if (mod->xxi[i].sub == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxmp_init_pattern(struct xmp_module *mod)
|
||||
{
|
||||
mod->xxt = (struct xmp_track **)calloc(sizeof (struct xmp_track *), mod->trk);
|
||||
if (mod->xxt == NULL)
|
||||
return -1;
|
||||
|
||||
mod->xxp = (struct xmp_pattern **)calloc(sizeof (struct xmp_pattern *), mod->pat);
|
||||
if (mod->xxp == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxmp_alloc_pattern(struct xmp_module *mod, int num)
|
||||
{
|
||||
/* Sanity check */
|
||||
if (num < 0 || num >= mod->pat || mod->xxp[num] != NULL)
|
||||
return -1;
|
||||
|
||||
mod->xxp[num] = (struct xmp_pattern *)calloc(1, sizeof (struct xmp_pattern) +
|
||||
sizeof (int) * (mod->chn - 1));
|
||||
if (mod->xxp[num] == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxmp_alloc_track(struct xmp_module *mod, int num, int rows)
|
||||
{
|
||||
/* Sanity check */
|
||||
if (num < 0 || num >= mod->trk || mod->xxt[num] != NULL || rows <= 0)
|
||||
return -1;
|
||||
|
||||
mod->xxt[num] = (struct xmp_track *)calloc(sizeof (struct xmp_track) +
|
||||
sizeof (struct xmp_event) * (rows - 1), 1);
|
||||
if (mod->xxt[num] == NULL)
|
||||
return -1;
|
||||
|
||||
mod->xxt[num]->rows = rows;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxmp_alloc_tracks_in_pattern(struct xmp_module *mod, int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
D_(D_INFO "Alloc %d tracks of %d rows", mod->chn, mod->xxp[num]->rows);
|
||||
for (i = 0; i < mod->chn; i++) {
|
||||
int t = num * mod->chn + i;
|
||||
int rows = mod->xxp[num]->rows;
|
||||
|
||||
if (libxmp_alloc_track(mod, t, rows) < 0)
|
||||
return -1;
|
||||
|
||||
mod->xxp[num]->index[i] = t;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxmp_alloc_pattern_tracks(struct xmp_module *mod, int num, int rows)
|
||||
{
|
||||
/* Sanity check */
|
||||
if (rows < 0 || rows > 256)
|
||||
return -1;
|
||||
|
||||
if (libxmp_alloc_pattern(mod, num) < 0)
|
||||
return -1;
|
||||
|
||||
mod->xxp[num]->rows = rows;
|
||||
|
||||
if (libxmp_alloc_tracks_in_pattern(mod, num) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sample number adjustment by Vitamin/CAIG */
|
||||
struct xmp_sample *libxmp_realloc_samples(struct xmp_sample *buf, int *size, int new_size)
|
||||
{
|
||||
buf = (struct xmp_sample *)realloc(buf, sizeof (struct xmp_sample) * new_size);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
if (new_size > *size)
|
||||
memset(buf + *size, 0, sizeof (struct xmp_sample) * (new_size - *size));
|
||||
*size = new_size;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *libxmp_instrument_name(struct xmp_module *mod, int i, uint8 *r, int n)
|
||||
{
|
||||
CLAMP(n, 0, 31);
|
||||
|
||||
return libxmp_copy_adjust(mod->xxi[i].name, r, n);
|
||||
}
|
||||
|
||||
char *libxmp_copy_adjust(char *s, uint8 *r, int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(s, 0, n + 1);
|
||||
strncpy(s, (char *)r, n);
|
||||
|
||||
for (i = 0; s[i] && i < n; i++) {
|
||||
if (!isprint((int)s[i]) || ((uint8)s[i] > 127))
|
||||
s[i] = '.';
|
||||
}
|
||||
|
||||
while (*s && (s[strlen(s) - 1] == ' '))
|
||||
s[strlen(s) - 1] = 0;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void libxmp_read_title(HIO_HANDLE *f, char *t, int s)
|
||||
{
|
||||
uint8 buf[XMP_NAME_SIZE];
|
||||
|
||||
if (t == NULL)
|
||||
return;
|
||||
|
||||
if (s >= XMP_NAME_SIZE)
|
||||
s = XMP_NAME_SIZE -1;
|
||||
|
||||
memset(t, 0, s + 1);
|
||||
|
||||
hio_read(buf, 1, s, f); /* coverity[check_return] */
|
||||
buf[s] = 0;
|
||||
libxmp_copy_adjust(t, buf, s);
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
|
||||
int libxmp_test_name(uint8 *s, int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (s[i] > 0x7f)
|
||||
return -1;
|
||||
/* ACS_Team2.mod has a backspace in instrument name */
|
||||
if (s[i] > 0 && s[i] < 32 && s[i] != 0x08)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Honor Noisetracker effects:
|
||||
*
|
||||
* 0 - arpeggio
|
||||
* 1 - portamento up
|
||||
* 2 - portamento down
|
||||
* 3 - Tone-portamento
|
||||
* 4 - Vibrato
|
||||
* A - Slide volume
|
||||
* B - Position jump
|
||||
* C - Set volume
|
||||
* D - Pattern break
|
||||
* E - Set filter (keep the led off, please!)
|
||||
* F - Set speed (now up to $1F)
|
||||
*
|
||||
* Pex Tufvesson's notes from http://www.livet.se/mahoney/:
|
||||
*
|
||||
* Note that some of the modules will have bugs in the playback with all
|
||||
* known PC module players. This is due to that in many demos where I synced
|
||||
* events in the demo with the music, I used commands that these newer PC
|
||||
* module players erroneously interpret as "newer-version-trackers commands".
|
||||
* Which they aren't.
|
||||
*/
|
||||
void libxmp_decode_noisetracker_event(struct xmp_event *event, uint8 *mod_event)
|
||||
{
|
||||
int fxt;
|
||||
|
||||
memset(event, 0, sizeof (struct xmp_event));
|
||||
event->note = libxmp_period_to_note((LSN(mod_event[0]) << 8) + mod_event[1]);
|
||||
event->ins = ((MSN(mod_event[0]) << 4) | MSN(mod_event[2]));
|
||||
fxt = LSN(mod_event[2]);
|
||||
|
||||
if (fxt <= 0x06 || (fxt >= 0x0a && fxt != 0x0e)) {
|
||||
event->fxt = fxt;
|
||||
event->fxp = mod_event[3];
|
||||
}
|
||||
|
||||
libxmp_disable_continue_fx(event);
|
||||
}
|
||||
#endif
|
||||
|
||||
void libxmp_decode_protracker_event(struct xmp_event *event, uint8 *mod_event)
|
||||
{
|
||||
int fxt = LSN(mod_event[2]);
|
||||
|
||||
memset(event, 0, sizeof (struct xmp_event));
|
||||
event->note = libxmp_period_to_note((LSN(mod_event[0]) << 8) + mod_event[1]);
|
||||
event->ins = ((MSN(mod_event[0]) << 4) | MSN(mod_event[2]));
|
||||
|
||||
if (fxt != 0x08) {
|
||||
event->fxt = fxt;
|
||||
event->fxp = mod_event[3];
|
||||
}
|
||||
|
||||
libxmp_disable_continue_fx(event);
|
||||
}
|
||||
|
||||
void libxmp_disable_continue_fx(struct xmp_event *event)
|
||||
{
|
||||
if (event->fxp == 0) {
|
||||
switch (event->fxt) {
|
||||
case 0x05:
|
||||
event->fxt = 0x03;
|
||||
break;
|
||||
case 0x06:
|
||||
event->fxt = 0x04;
|
||||
break;
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x0a:
|
||||
event->fxt = 0x00;
|
||||
}
|
||||
} else if (event->fxt == 0x0e) {
|
||||
if (event->fxp == 0xa0 || event->fxp == 0xb0) {
|
||||
event->fxt = event->fxp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
#ifndef WIN32
|
||||
|
||||
/* Given a directory, see if file exists there, ignoring case */
|
||||
|
||||
int libxmp_check_filename_case(char *dir, char *name, char *new_name, int size)
|
||||
{
|
||||
int found = 0;
|
||||
DIR *dirfd;
|
||||
struct dirent *d;
|
||||
|
||||
dirfd = opendir(dir);
|
||||
if (dirfd == NULL)
|
||||
return 0;
|
||||
|
||||
while ((d = readdir(dirfd))) {
|
||||
if (!strcasecmp(d->d_name, name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
strncpy(new_name, d->d_name, size);
|
||||
|
||||
closedir(dirfd);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* FIXME: implement functionality for Win32 */
|
||||
|
||||
int libxmp_check_filename_case(char *dir, char *name, char *new_name, int size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void libxmp_get_instrument_path(struct module_data *m, char *path, int size)
|
||||
{
|
||||
if (m->instrument_path) {
|
||||
strncpy(path, m->instrument_path, size);
|
||||
} else if (getenv("XMP_INSTRUMENT_PATH")) {
|
||||
strncpy(path, getenv("XMP_INSTRUMENT_PATH"), size);
|
||||
} else {
|
||||
strncpy(path, ".", size);
|
||||
}
|
||||
}
|
||||
#endif /* LIBXMP_CORE_PLAYER */
|
||||
|
||||
void libxmp_set_type(struct module_data *m, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
vsnprintf(m->mod.type, XMP_NAME_SIZE, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
|
@ -1,447 +0,0 @@
|
|||
#ifndef LIBXMP_COMMON_H
|
||||
#define LIBXMP_COMMON_H
|
||||
|
||||
#ifdef __AROS__
|
||||
#define __AMIGA__
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "xmp.h"
|
||||
|
||||
#if (defined(__GNUC__) || defined(__clang__)) && defined(XMP_SYM_VISIBILITY)
|
||||
#if !defined(WIN32) && !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__AMIGA__) && !defined(__MSDOS__) && !defined(B_BEOS_VERSION) && !defined(__ATHEOS__) && !defined(EMSCRIPTEN) && !defined(__MINT__)
|
||||
#define USE_VERSIONED_SYMBOLS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* AmigaOS fixes by Chris Young <cdyoung@ntlworld.com>, Nov 25, 2007
|
||||
*/
|
||||
#if defined B_BEOS_VERSION
|
||||
# include <SupportDefs.h>
|
||||
#elif defined __amigaos4__
|
||||
# include <exec/types.h>
|
||||
#else
|
||||
typedef signed char int8;
|
||||
typedef signed short int int16;
|
||||
typedef signed int int32;
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short int uint16;
|
||||
typedef unsigned int uint32;
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER /* MSVC++6.0 has no long long */
|
||||
typedef signed __int64 int64;
|
||||
typedef unsigned __int64 uint64;
|
||||
#elif !defined B_BEOS_VERSION /* BeOS has its own int64 definition */
|
||||
typedef unsigned long long uint64;
|
||||
typedef signed long long int64;
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
#define LIBXMP_PAULA_SIMULATOR
|
||||
#endif
|
||||
|
||||
/* Constants */
|
||||
#define PAL_RATE 250.0 /* 1 / (50Hz * 80us) */
|
||||
#define NTSC_RATE 208.0 /* 1 / (60Hz * 80us) */
|
||||
#define C4_PAL_RATE 8287 /* 7093789.2 / period (C4) * 2 */
|
||||
#define C4_NTSC_RATE 8363 /* 7159090.5 / period (C4) * 2 */
|
||||
|
||||
/* [Amiga] PAL color carrier frequency (PCCF) = 4.43361825 MHz */
|
||||
/* [Amiga] CPU clock = 1.6 * PCCF = 7.0937892 MHz */
|
||||
|
||||
#define DEFAULT_AMPLIFY 1
|
||||
#define DEFAULT_MIX 100
|
||||
|
||||
#define MSN(x) (((x)&0xf0)>>4)
|
||||
#define LSN(x) ((x)&0x0f)
|
||||
#define SET_FLAG(a,b) ((a)|=(b))
|
||||
#define RESET_FLAG(a,b) ((a)&=~(b))
|
||||
#define TEST_FLAG(a,b) !!((a)&(b))
|
||||
|
||||
#define CLAMP(x,a,b) do { \
|
||||
if ((x) < (a)) (x) = (a); \
|
||||
else if ((x) > (b)) (x) = (b); \
|
||||
} while (0)
|
||||
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
||||
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
#define TRACK_NUM(a,c) m->mod.xxp[a]->index[c]
|
||||
#define EVENT(a,c,r) m->mod.xxt[TRACK_NUM((a),(c))]->event[r]
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define D_CRIT " Error: "
|
||||
#define D_WARN "Warning: "
|
||||
#define D_INFO " Info: "
|
||||
#ifndef CLIB_DECL
|
||||
#define CLIB_DECL
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
#ifndef ATTR_PRINTF
|
||||
#define ATTR_PRINTF(x,y)
|
||||
#endif
|
||||
void CLIB_DECL D_(const char *text, ...) ATTR_PRINTF(1,2);
|
||||
#else
|
||||
// VS prior to VC7.1 does not support variadic macros. VC8.0 does not optimize unused parameters passing
|
||||
#if _MSC_VER < 1400
|
||||
void __inline CLIB_DECL D_(const char *text, ...) { do {} while (0); }
|
||||
#else
|
||||
#define D_(args, ...) do {} while (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif defined __ANDROID__
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <android/log.h>
|
||||
#define D_CRIT " Error: "
|
||||
#define D_WARN "Warning: "
|
||||
#define D_INFO " Info: "
|
||||
#define D_(args...) do { \
|
||||
__android_log_print(ANDROID_LOG_DEBUG, "libxmp", args); \
|
||||
} while (0)
|
||||
#else
|
||||
#define D_(args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#elif defined(__WATCOMC__)
|
||||
#ifdef DEBUG
|
||||
#define D_INFO "\x1b[33m"
|
||||
#define D_CRIT "\x1b[31m"
|
||||
#define D_WARN "\x1b[36m"
|
||||
#define D_(...) do { \
|
||||
printf("\x1b[33m%s \x1b[37m[%s:%d] " D_INFO, __FUNCTION__, \
|
||||
__FILE__, __LINE__); printf (__VA_ARGS__); printf ("\x1b[0m\n"); \
|
||||
} while (0)
|
||||
#else
|
||||
#define D_(...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifdef DEBUG
|
||||
#define D_INFO "\x1b[33m"
|
||||
#define D_CRIT "\x1b[31m"
|
||||
#define D_WARN "\x1b[36m"
|
||||
#define D_(args...) do { \
|
||||
printf("\x1b[33m%s \x1b[37m[%s:%d] " D_INFO, __FUNCTION__, \
|
||||
__FILE__, __LINE__); printf (args); printf ("\x1b[0m\n"); \
|
||||
} while (0)
|
||||
#else
|
||||
#define D_(args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#endif /* !_MSC_VER */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define dup _dup
|
||||
#define fileno _fileno
|
||||
#define strnicmp _strnicmp
|
||||
#define strdup _strdup
|
||||
#define fdopen _fdopen
|
||||
#define open _open
|
||||
#define close _close
|
||||
#define unlink _unlink
|
||||
#endif
|
||||
#if defined(_WIN32) || defined(__WATCOMC__) /* in win32.c */
|
||||
int libxmp_vsnprintf(char *, size_t, const char *, va_list);
|
||||
int libxmp_snprintf (char *, size_t, const char *, ...);
|
||||
#define snprintf libxmp_snprintf
|
||||
#define vsnprintf libxmp_vsnprintf
|
||||
#endif
|
||||
|
||||
/* Quirks */
|
||||
#define QUIRK_S3MLOOP (1 << 0) /* S3M loop mode */
|
||||
#define QUIRK_ENVFADE (1 << 1) /* Fade at end of envelope */
|
||||
#define QUIRK_PROTRACK (1 << 2) /* Use Protracker-specific quirks */
|
||||
#define QUIRK_ST3BUGS (1 << 4) /* Scream Tracker 3 bug compatibility */
|
||||
#define QUIRK_FINEFX (1 << 5) /* Enable 0xf/0xe for fine effects */
|
||||
#define QUIRK_VSALL (1 << 6) /* Volume slides in all frames */
|
||||
#define QUIRK_PBALL (1 << 7) /* Pitch bending in all frames */
|
||||
#define QUIRK_PERPAT (1 << 8) /* Cancel persistent fx at pat start */
|
||||
#define QUIRK_VOLPDN (1 << 9) /* Set priority to volume slide down */
|
||||
#define QUIRK_UNISLD (1 << 10) /* Unified pitch slide/portamento */
|
||||
#define QUIRK_ITVPOR (1 << 11) /* Disable fine bends in IT vol fx */
|
||||
#define QUIRK_FTMOD (1 << 12) /* Flag for multichannel mods */
|
||||
/*#define QUIRK_MODRNG (1 << 13)*/ /* Limit periods to MOD range */
|
||||
#define QUIRK_INSVOL (1 << 14) /* Use instrument volume */
|
||||
#define QUIRK_VIRTUAL (1 << 15) /* Enable virtual channels */
|
||||
#define QUIRK_FILTER (1 << 16) /* Enable filter */
|
||||
#define QUIRK_IGSTPOR (1 << 17) /* Ignore stray tone portamento */
|
||||
#define QUIRK_KEYOFF (1 << 18) /* Keyoff doesn't reset fadeout */
|
||||
#define QUIRK_VIBHALF (1 << 19) /* Vibrato is half as deep */
|
||||
#define QUIRK_VIBALL (1 << 20) /* Vibrato in all frames */
|
||||
#define QUIRK_VIBINV (1 << 21) /* Vibrato has inverse waveform */
|
||||
#define QUIRK_PRENV (1 << 22) /* Portamento resets envelope & fade */
|
||||
#define QUIRK_ITOLDFX (1 << 23) /* IT old effects mode */
|
||||
#define QUIRK_S3MRTG (1 << 24) /* S3M-style retrig when count == 0 */
|
||||
#define QUIRK_RTDELAY (1 << 25) /* Delay effect retrigs instrument */
|
||||
#define QUIRK_FT2BUGS (1 << 26) /* FT2 bug compatibility */
|
||||
#define QUIRK_MARKER (1 << 27) /* Patterns 0xfe and 0xff reserved */
|
||||
#define QUIRK_NOBPM (1 << 28) /* Adjust speed only, no BPM */
|
||||
#define QUIRK_ARPMEM (1 << 29) /* Arpeggio has memory (S3M_ARPEGGIO) */
|
||||
#define QUIRK_RSTCHN (1 << 30) /* Reset channel on sample end */
|
||||
|
||||
#define HAS_QUIRK(x) (m->quirk & (x))
|
||||
|
||||
|
||||
/* Format quirks */
|
||||
#define QUIRKS_ST3 (QUIRK_S3MLOOP | QUIRK_VOLPDN | QUIRK_FINEFX | \
|
||||
QUIRK_S3MRTG | QUIRK_MARKER | QUIRK_RSTCHN )
|
||||
#define QUIRKS_FT2 (QUIRK_RTDELAY | QUIRK_FINEFX )
|
||||
#define QUIRKS_IT (QUIRK_S3MLOOP | QUIRK_FINEFX | QUIRK_VIBALL | \
|
||||
QUIRK_ENVFADE | QUIRK_ITVPOR | QUIRK_KEYOFF | \
|
||||
QUIRK_VIRTUAL | QUIRK_FILTER | QUIRK_RSTCHN | \
|
||||
QUIRK_IGSTPOR | QUIRK_S3MRTG | QUIRK_MARKER )
|
||||
|
||||
/* DSP effects */
|
||||
#define DSP_EFFECT_CUTOFF 0x02
|
||||
#define DSP_EFFECT_RESONANCE 0x03
|
||||
#define DSP_EFFECT_FILTER_A0 0xb0
|
||||
#define DSP_EFFECT_FILTER_B0 0xb1
|
||||
#define DSP_EFFECT_FILTER_B1 0xb2
|
||||
|
||||
/* Time factor */
|
||||
#define DEFAULT_TIME_FACTOR 10.0
|
||||
#define MED_TIME_FACTOR 2.64
|
||||
|
||||
#define MAX_SEQUENCES 16
|
||||
#define MAX_SAMPLE_SIZE 0x10000000
|
||||
#define MAX_SAMPLES 1024
|
||||
|
||||
#define IS_PLAYER_MODE_MOD() (m->read_event_type == READ_EVENT_MOD)
|
||||
#define IS_PLAYER_MODE_FT2() (m->read_event_type == READ_EVENT_FT2)
|
||||
#define IS_PLAYER_MODE_ST3() (m->read_event_type == READ_EVENT_ST3)
|
||||
#define IS_PLAYER_MODE_IT() (m->read_event_type == READ_EVENT_IT)
|
||||
#define IS_PLAYER_MODE_MED() (m->read_event_type == READ_EVENT_MED)
|
||||
#define IS_PERIOD_MODRNG() (m->period_type == PERIOD_MODRNG)
|
||||
#define IS_PERIOD_LINEAR() (m->period_type == PERIOD_LINEAR)
|
||||
#define IS_PERIOD_CSPD() (m->period_type == PERIOD_CSPD)
|
||||
|
||||
#define IS_AMIGA_MOD() (IS_PLAYER_MODE_MOD() && IS_PERIOD_MODRNG())
|
||||
|
||||
struct ord_data {
|
||||
int speed;
|
||||
int bpm;
|
||||
int gvl;
|
||||
int time;
|
||||
int start_row;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
int st26_speed;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Context */
|
||||
|
||||
struct smix_data {
|
||||
int chn;
|
||||
int ins;
|
||||
int smp;
|
||||
struct xmp_instrument *xxi;
|
||||
struct xmp_sample *xxs;
|
||||
};
|
||||
|
||||
/* This will be added to the sample structure in the next API revision */
|
||||
struct extra_sample_data {
|
||||
double c5spd;
|
||||
};
|
||||
|
||||
struct module_data {
|
||||
struct xmp_module mod;
|
||||
|
||||
char *dirname; /* file dirname */
|
||||
char *basename; /* file basename */
|
||||
char *filename; /* Module file name */
|
||||
char *comment; /* Comments, if any */
|
||||
uint8 md5[16]; /* MD5 message digest */
|
||||
int size; /* File size */
|
||||
double rrate; /* Replay rate */
|
||||
double time_factor; /* Time conversion constant */
|
||||
int c4rate; /* C4 replay rate */
|
||||
int volbase; /* Volume base */
|
||||
int gvolbase; /* Global volume base */
|
||||
int gvol; /* Global volume */
|
||||
int *vol_table; /* Volume translation table */
|
||||
int quirk; /* player quirks */
|
||||
#define READ_EVENT_MOD 0
|
||||
#define READ_EVENT_FT2 1
|
||||
#define READ_EVENT_ST3 2
|
||||
#define READ_EVENT_IT 3
|
||||
#define READ_EVENT_MED 4
|
||||
int read_event_type;
|
||||
#define PERIOD_AMIGA 0
|
||||
#define PERIOD_MODRNG 1
|
||||
#define PERIOD_LINEAR 2
|
||||
#define PERIOD_CSPD 3
|
||||
int period_type;
|
||||
int smpctl; /* sample control flags */
|
||||
int defpan; /* default pan setting */
|
||||
struct ord_data xxo_info[XMP_MAX_MOD_LENGTH];
|
||||
int num_sequences;
|
||||
struct xmp_sequence seq_data[MAX_SEQUENCES];
|
||||
char *instrument_path;
|
||||
void *extra; /* format-specific extra fields */
|
||||
char **scan_cnt; /* scan counters */
|
||||
struct extra_sample_data *xtra;
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
struct xmp_sample *xsmp; /* sustain loop samples */
|
||||
#endif
|
||||
};
|
||||
|
||||
struct pattern_loop {
|
||||
int start;
|
||||
int count;
|
||||
};
|
||||
|
||||
|
||||
struct flow_control {
|
||||
int pbreak;
|
||||
int jump;
|
||||
int delay;
|
||||
int jumpline;
|
||||
int loop_chn;
|
||||
|
||||
struct pattern_loop *loop;
|
||||
|
||||
int num_rows;
|
||||
int end_point;
|
||||
int rowdelay; /* For IT pattern row delay */
|
||||
int rowdelay_set;
|
||||
};
|
||||
|
||||
struct virt_channel {
|
||||
int count;
|
||||
int map;
|
||||
};
|
||||
|
||||
struct virt_control {
|
||||
int num_tracks; /* Number of tracks */
|
||||
int virt_channels; /* Number of virtual channels */
|
||||
int virt_used; /* Number of voices currently in use */
|
||||
int maxvoc; /* Number of sound card voices */
|
||||
|
||||
struct virt_channel *virt_channel;
|
||||
|
||||
struct mixer_voice *voice_array;
|
||||
};
|
||||
|
||||
struct player_data {
|
||||
int ord;
|
||||
int pos;
|
||||
int row;
|
||||
int frame;
|
||||
int speed;
|
||||
int bpm;
|
||||
int mode;
|
||||
int player_flags;
|
||||
int flags;
|
||||
|
||||
double current_time;
|
||||
double frame_time;
|
||||
|
||||
int loop_count;
|
||||
int sequence;
|
||||
unsigned char sequence_control[XMP_MAX_MOD_LENGTH];
|
||||
|
||||
int smix_vol; /* SFX volume */
|
||||
int master_vol; /* Music volume */
|
||||
int gvol;
|
||||
|
||||
struct flow_control flow;
|
||||
|
||||
struct {
|
||||
int time; /* replay time in ms */
|
||||
int ord;
|
||||
int row;
|
||||
int num;
|
||||
} scan[MAX_SEQUENCES];
|
||||
|
||||
struct channel_data *xc_data;
|
||||
|
||||
int channel_vol[XMP_MAX_CHANNELS];
|
||||
char channel_mute[XMP_MAX_CHANNELS];
|
||||
|
||||
struct virt_control virt;
|
||||
|
||||
struct xmp_event inject_event[XMP_MAX_CHANNELS];
|
||||
|
||||
struct {
|
||||
int consumed;
|
||||
int in_size;
|
||||
char *in_buffer;
|
||||
} buffer_data;
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
int st26_speed; /* For IceTracker speed effect */
|
||||
#endif
|
||||
int filter; /* Amiga led filter */
|
||||
};
|
||||
|
||||
struct mixer_data {
|
||||
int freq; /* sampling rate */
|
||||
int format; /* sample format */
|
||||
int amplify; /* amplification multiplier */
|
||||
int mix; /* percentage of channel separation */
|
||||
int interp; /* interpolation type */
|
||||
int dsp; /* dsp effect flags */
|
||||
char* buffer; /* output buffer */
|
||||
int32* buf32; /* temporary buffer for 32 bit samples */
|
||||
int numvoc; /* default softmixer voices number */
|
||||
int ticksize;
|
||||
int dtright; /* anticlick control, right channel */
|
||||
int dtleft; /* anticlick control, left channel */
|
||||
double pbase; /* period base */
|
||||
};
|
||||
|
||||
struct context_data {
|
||||
struct player_data p;
|
||||
struct mixer_data s;
|
||||
struct module_data m;
|
||||
struct smix_data smix;
|
||||
int state;
|
||||
};
|
||||
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
char *libxmp_adjust_string (char *);
|
||||
int libxmp_exclude_match (const char *);
|
||||
int libxmp_prepare_scan (struct context_data *);
|
||||
int libxmp_scan_sequences (struct context_data *);
|
||||
int libxmp_get_sequence (struct context_data *, int);
|
||||
int libxmp_set_player_mode (struct context_data *);
|
||||
|
||||
#ifdef EDUKE32_DISABLED
|
||||
int8 read8s (FILE *, int *err);
|
||||
uint8 read8 (FILE *, int *err);
|
||||
uint16 read16l (FILE *, int *err);
|
||||
uint16 read16b (FILE *, int *err);
|
||||
uint32 read24l (FILE *, int *err);
|
||||
uint32 read24b (FILE *, int *err);
|
||||
uint32 read32l (FILE *, int *err);
|
||||
uint32 read32b (FILE *, int *err);
|
||||
static inline void write8 (FILE *f, uint8 b) {
|
||||
fputc(b, f);
|
||||
}
|
||||
void write16l (FILE *, uint16);
|
||||
void write16b (FILE *, uint16);
|
||||
void write32l (FILE *, uint32);
|
||||
void write32b (FILE *, uint32);
|
||||
int move_data (FILE *, FILE *, int);
|
||||
#endif
|
||||
|
||||
uint16 readmem16l (const uint8 *);
|
||||
uint16 readmem16b (const uint8 *);
|
||||
uint32 readmem24l (const uint8 *);
|
||||
uint32 readmem24b (const uint8 *);
|
||||
uint32 readmem32l (const uint8 *);
|
||||
uint32 readmem32b (const uint8 *);
|
||||
|
||||
struct xmp_instrument *libxmp_get_instrument(struct context_data *, int);
|
||||
struct xmp_sample *libxmp_get_sample(struct context_data *, int);
|
||||
|
||||
#endif /* LIBXMP_COMMON_H */
|
|
@ -1,582 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "format.h"
|
||||
#include "virtual.h"
|
||||
#include "mixer.h"
|
||||
|
||||
const char *xmp_version = XMP_VERSION;
|
||||
const unsigned int xmp_vercode = XMP_VERCODE;
|
||||
|
||||
xmp_context xmp_create_context()
|
||||
{
|
||||
struct context_data *ctx;
|
||||
|
||||
ctx = (struct context_data *)calloc(1, sizeof(struct context_data));
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->state = XMP_STATE_UNLOADED;
|
||||
ctx->m.defpan = 100;
|
||||
ctx->s.numvoc = SMIX_NUMVOC;
|
||||
|
||||
return (xmp_context)ctx;
|
||||
}
|
||||
|
||||
void xmp_free_context(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
|
||||
if (ctx->state > XMP_STATE_UNLOADED)
|
||||
xmp_release_module(opaque);
|
||||
|
||||
free(opaque);
|
||||
}
|
||||
|
||||
static void set_position(struct context_data *ctx, int pos, int dir)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct flow_control *f = &p->flow;
|
||||
int seq;
|
||||
int has_marker;
|
||||
|
||||
/* If dir is 0, we can jump to a different sequence */
|
||||
if (dir == 0) {
|
||||
seq = libxmp_get_sequence(ctx, pos);
|
||||
} else {
|
||||
seq = p->sequence;
|
||||
}
|
||||
|
||||
if (seq == 0xff) {
|
||||
return;
|
||||
}
|
||||
|
||||
has_marker = HAS_QUIRK(QUIRK_MARKER);
|
||||
|
||||
if (seq >= 0) {
|
||||
int start = m->seq_data[seq].entry_point;
|
||||
|
||||
p->sequence = seq;
|
||||
|
||||
if (pos >= 0) {
|
||||
int pat;
|
||||
|
||||
while (has_marker && mod->xxo[pos] == 0xfe) {
|
||||
if (dir < 0) {
|
||||
if (pos > start) {
|
||||
pos--;
|
||||
}
|
||||
} else {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
pat = mod->xxo[pos];
|
||||
|
||||
if (pat < mod->pat) {
|
||||
if (has_marker && pat == 0xff) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pos > p->scan[seq].ord) {
|
||||
f->end_point = 0;
|
||||
} else {
|
||||
f->num_rows = mod->xxp[pat]->rows;
|
||||
f->end_point = p->scan[seq].num;
|
||||
f->jumpline = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pos < mod->len) {
|
||||
if (pos == 0) {
|
||||
p->pos = -1;
|
||||
} else {
|
||||
p->pos = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int xmp_next_position(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return -XMP_ERROR_STATE;
|
||||
|
||||
if (p->pos < m->mod.len)
|
||||
set_position(ctx, p->pos + 1, 1);
|
||||
|
||||
return p->pos;
|
||||
}
|
||||
|
||||
int xmp_prev_position(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return -XMP_ERROR_STATE;
|
||||
|
||||
if (p->pos == m->seq_data[p->sequence].entry_point) {
|
||||
set_position(ctx, -1, -1);
|
||||
} else if (p->pos > m->seq_data[p->sequence].entry_point) {
|
||||
set_position(ctx, p->pos - 1, -1);
|
||||
}
|
||||
return p->pos < 0 ? 0 : p->pos;
|
||||
}
|
||||
|
||||
int xmp_set_position(xmp_context opaque, int pos)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return -XMP_ERROR_STATE;
|
||||
|
||||
if (pos >= m->mod.len)
|
||||
return -XMP_ERROR_INVALID;
|
||||
|
||||
set_position(ctx, pos, 0);
|
||||
|
||||
return p->pos;
|
||||
}
|
||||
|
||||
int xmp_set_row(xmp_context opaque, int row)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct flow_control *f = &p->flow;
|
||||
int pos = p->pos;
|
||||
int pattern = mod->xxo[pos];
|
||||
|
||||
if (pos < 0 || pos >= mod->len) {
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return -XMP_ERROR_STATE;
|
||||
|
||||
if (row >= mod->xxp[pattern]->rows)
|
||||
return -XMP_ERROR_INVALID;
|
||||
|
||||
/* See set_position. */
|
||||
if (p->pos < 0)
|
||||
p->pos = 0;
|
||||
p->ord = p->pos;
|
||||
p->row = row;
|
||||
p->frame = -1;
|
||||
f->num_rows = mod->xxp[mod->xxo[p->ord]]->rows;
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
void xmp_stop_module(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return;
|
||||
|
||||
p->pos = -2;
|
||||
}
|
||||
|
||||
void xmp_restart_module(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return;
|
||||
|
||||
p->loop_count = 0;
|
||||
p->pos = -1;
|
||||
}
|
||||
|
||||
int xmp_seek_time(xmp_context opaque, int time)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
int i, t;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return -XMP_ERROR_STATE;
|
||||
|
||||
for (i = m->mod.len - 1; i >= 0; i--) {
|
||||
int pat = m->mod.xxo[i];
|
||||
if (pat >= m->mod.pat) {
|
||||
continue;
|
||||
}
|
||||
if (libxmp_get_sequence(ctx, i) != p->sequence) {
|
||||
continue;
|
||||
}
|
||||
t = m->xxo_info[i].time;
|
||||
if (time >= t) {
|
||||
set_position(ctx, i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < 0) {
|
||||
xmp_set_position(opaque, 0);
|
||||
}
|
||||
|
||||
return p->pos < 0 ? 0 : p->pos;
|
||||
}
|
||||
|
||||
int xmp_channel_mute(xmp_context opaque, int chn, int status)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
int ret;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return -XMP_ERROR_STATE;
|
||||
|
||||
if (chn < 0 || chn >= XMP_MAX_CHANNELS) {
|
||||
return -XMP_ERROR_INVALID;
|
||||
}
|
||||
|
||||
ret = p->channel_mute[chn];
|
||||
|
||||
if (status >= 2) {
|
||||
p->channel_mute[chn] = !p->channel_mute[chn];
|
||||
} else if (status >= 0) {
|
||||
p->channel_mute[chn] = status;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmp_channel_vol(xmp_context opaque, int chn, int vol)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
int ret;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return -XMP_ERROR_STATE;
|
||||
|
||||
if (chn < 0 || chn >= XMP_MAX_CHANNELS) {
|
||||
return -XMP_ERROR_INVALID;
|
||||
}
|
||||
|
||||
ret = p->channel_vol[chn];
|
||||
|
||||
if (vol >= 0 && vol <= 100) {
|
||||
p->channel_vol[chn] = vol;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef USE_VERSIONED_SYMBOLS
|
||||
LIBXMP_EXPORT extern int xmp_set_player_v40__(xmp_context, int, int);
|
||||
LIBXMP_EXPORT extern int xmp_set_player_v41__(xmp_context, int, int)
|
||||
__attribute__((alias("xmp_set_player_v40__")));
|
||||
LIBXMP_EXPORT extern int xmp_set_player_v43__(xmp_context, int, int)
|
||||
__attribute__((alias("xmp_set_player_v40__")));
|
||||
LIBXMP_EXPORT extern int xmp_set_player_v44__(xmp_context, int, int)
|
||||
__attribute__((alias("xmp_set_player_v40__")));
|
||||
|
||||
asm(".symver xmp_set_player_v40__, xmp_set_player@XMP_4.0");
|
||||
asm(".symver xmp_set_player_v41__, xmp_set_player@XMP_4.1");
|
||||
asm(".symver xmp_set_player_v43__, xmp_set_player@XMP_4.3");
|
||||
asm(".symver xmp_set_player_v44__, xmp_set_player@@XMP_4.4");
|
||||
|
||||
#define xmp_set_player__ xmp_set_player_v40__
|
||||
#else
|
||||
#define xmp_set_player__ xmp_set_player
|
||||
#endif
|
||||
|
||||
int xmp_set_player__(xmp_context opaque, int parm, int val)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct mixer_data *s = &ctx->s;
|
||||
int ret = -XMP_ERROR_INVALID;
|
||||
|
||||
|
||||
if (parm == XMP_PLAYER_SMPCTL || parm == XMP_PLAYER_DEFPAN) {
|
||||
/* these should be set before loading the module */
|
||||
if (ctx->state >= XMP_STATE_LOADED) {
|
||||
return -XMP_ERROR_STATE;
|
||||
}
|
||||
} else if (parm == XMP_PLAYER_VOICES) {
|
||||
/* these should be set before start playing */
|
||||
if (ctx->state >= XMP_STATE_PLAYING) {
|
||||
return -XMP_ERROR_STATE;
|
||||
}
|
||||
} else if (ctx->state < XMP_STATE_PLAYING) {
|
||||
return -XMP_ERROR_STATE;
|
||||
}
|
||||
|
||||
switch (parm) {
|
||||
case XMP_PLAYER_AMP:
|
||||
if (val >= 0 && val <= 3) {
|
||||
s->amplify = val;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case XMP_PLAYER_MIX:
|
||||
if (val >= -100 && val <= 100) {
|
||||
s->mix = val;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case XMP_PLAYER_INTERP:
|
||||
if (val >= XMP_INTERP_NEAREST && val <= XMP_INTERP_SPLINE) {
|
||||
s->interp = val;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case XMP_PLAYER_DSP:
|
||||
s->dsp = val;
|
||||
ret = 0;
|
||||
break;
|
||||
case XMP_PLAYER_FLAGS: {
|
||||
p->player_flags = val;
|
||||
ret = 0;
|
||||
break; }
|
||||
|
||||
/* 4.1 */
|
||||
case XMP_PLAYER_CFLAGS: {
|
||||
int vblank = p->flags & XMP_FLAGS_VBLANK;
|
||||
p->flags = val;
|
||||
if (vblank != (p->flags & XMP_FLAGS_VBLANK))
|
||||
libxmp_scan_sequences(ctx);
|
||||
ret = 0;
|
||||
break; }
|
||||
case XMP_PLAYER_SMPCTL:
|
||||
m->smpctl = val;
|
||||
ret = 0;
|
||||
break;
|
||||
case XMP_PLAYER_VOLUME:
|
||||
if (val >= 0 && val <= 200) {
|
||||
p->master_vol = val;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case XMP_PLAYER_SMIX_VOLUME:
|
||||
if (val >= 0 && val <= 200) {
|
||||
p->smix_vol = val;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
/* 4.3 */
|
||||
case XMP_PLAYER_DEFPAN:
|
||||
if (val >= 0 && val <= 100) {
|
||||
m->defpan = val;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
/* 4.4 */
|
||||
case XMP_PLAYER_MODE:
|
||||
p->mode = val;
|
||||
libxmp_set_player_mode(ctx);
|
||||
libxmp_scan_sequences(ctx);
|
||||
ret = 0;
|
||||
break;
|
||||
case XMP_PLAYER_VOICES:
|
||||
s->numvoc = val;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef USE_VERSIONED_SYMBOLS
|
||||
LIBXMP_EXPORT extern int xmp_get_player_v40__(xmp_context, int);
|
||||
LIBXMP_EXPORT extern int xmp_get_player_v41__(xmp_context, int)
|
||||
__attribute__((alias("xmp_get_player_v40__")));
|
||||
LIBXMP_EXPORT extern int xmp_get_player_v42__(xmp_context, int)
|
||||
__attribute__((alias("xmp_get_player_v40__")));
|
||||
LIBXMP_EXPORT extern int xmp_get_player_v43__(xmp_context, int)
|
||||
__attribute__((alias("xmp_get_player_v40__")));
|
||||
LIBXMP_EXPORT extern int xmp_get_player_v44__(xmp_context, int)
|
||||
__attribute__((alias("xmp_get_player_v40__")));
|
||||
|
||||
asm(".symver xmp_get_player_v40__, xmp_get_player@XMP_4.0");
|
||||
asm(".symver xmp_get_player_v41__, xmp_get_player@XMP_4.1");
|
||||
asm(".symver xmp_get_player_v42__, xmp_get_player@XMP_4.2");
|
||||
asm(".symver xmp_get_player_v43__, xmp_get_player@XMP_4.3");
|
||||
asm(".symver xmp_get_player_v44__, xmp_get_player@@XMP_4.4");
|
||||
|
||||
#define xmp_get_player__ xmp_get_player_v40__
|
||||
#else
|
||||
#define xmp_get_player__ xmp_get_player
|
||||
#endif
|
||||
|
||||
int xmp_get_player__(xmp_context opaque, int parm)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct mixer_data *s = &ctx->s;
|
||||
int ret = -XMP_ERROR_INVALID;
|
||||
|
||||
if (parm == XMP_PLAYER_SMPCTL || parm == XMP_PLAYER_DEFPAN) {
|
||||
// can read these at any time
|
||||
} else if (parm != XMP_PLAYER_STATE && ctx->state < XMP_STATE_PLAYING) {
|
||||
return -XMP_ERROR_STATE;
|
||||
}
|
||||
|
||||
switch (parm) {
|
||||
case XMP_PLAYER_AMP:
|
||||
ret = s->amplify;
|
||||
break;
|
||||
case XMP_PLAYER_MIX:
|
||||
ret = s->mix;
|
||||
break;
|
||||
case XMP_PLAYER_INTERP:
|
||||
ret = s->interp;
|
||||
break;
|
||||
case XMP_PLAYER_DSP:
|
||||
ret = s->dsp;
|
||||
break;
|
||||
case XMP_PLAYER_FLAGS:
|
||||
ret = p->player_flags;
|
||||
break;
|
||||
|
||||
/* 4.1 */
|
||||
case XMP_PLAYER_CFLAGS:
|
||||
ret = p->flags;
|
||||
break;
|
||||
case XMP_PLAYER_SMPCTL:
|
||||
ret = m->smpctl;
|
||||
break;
|
||||
case XMP_PLAYER_VOLUME:
|
||||
ret = p->master_vol;
|
||||
break;
|
||||
case XMP_PLAYER_SMIX_VOLUME:
|
||||
ret = p->smix_vol;
|
||||
break;
|
||||
|
||||
/* 4.2 */
|
||||
case XMP_PLAYER_STATE:
|
||||
ret = ctx->state;
|
||||
break;
|
||||
|
||||
/* 4.3 */
|
||||
case XMP_PLAYER_DEFPAN:
|
||||
ret = m->defpan;
|
||||
break;
|
||||
|
||||
/* 4.4 */
|
||||
case XMP_PLAYER_MODE:
|
||||
ret = p->mode;
|
||||
break;
|
||||
case XMP_PLAYER_MIXER_TYPE:
|
||||
ret = XMP_MIXER_STANDARD;
|
||||
if (p->flags & XMP_FLAGS_A500) {
|
||||
if (IS_AMIGA_MOD()) {
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
if (p->filter) {
|
||||
ret = XMP_MIXER_A500F;
|
||||
} else {
|
||||
ret = XMP_MIXER_A500;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XMP_PLAYER_VOICES:
|
||||
ret = s->numvoc;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char **xmp_get_format_list()
|
||||
{
|
||||
return format_list();
|
||||
}
|
||||
|
||||
void xmp_inject_event(xmp_context opaque, int channel, struct xmp_event *e)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return;
|
||||
|
||||
memcpy(&p->inject_event[channel], e, sizeof(struct xmp_event));
|
||||
p->inject_event[channel]._flag = 1;
|
||||
}
|
||||
|
||||
int xmp_set_instrument_path(xmp_context opaque, char *path)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct module_data *m = &ctx->m;
|
||||
|
||||
if (m->instrument_path != NULL)
|
||||
free(m->instrument_path);
|
||||
|
||||
m->instrument_path = strdup(path);
|
||||
if (m->instrument_path == NULL) {
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xmp_set_tempo_factor(xmp_context opaque, double val)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct mixer_data *s = &ctx->s;
|
||||
int ticksize;
|
||||
|
||||
if (val <= 0.0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
val *= 10;
|
||||
ticksize = s->freq * m->time_factor * m->rrate / p->bpm / 1000 * sizeof(int);
|
||||
if (ticksize > XMP_MAX_FRAMESIZE) {
|
||||
return -1;
|
||||
}
|
||||
m->time_factor = val;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,271 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#define read_byte(x) do { \
|
||||
(x) = fgetc(f); \
|
||||
if ((x) < 0) goto error; \
|
||||
} while (0)
|
||||
|
||||
#define set_error(x) do { \
|
||||
if (err != NULL) *err = (x); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#ifdef EDUKE32_DISABLED
|
||||
uint8 read8(FILE *f, int *err)
|
||||
{
|
||||
int a;
|
||||
|
||||
read_byte(a);
|
||||
set_error(0);
|
||||
return a;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
int8 read8s(FILE *f, int *err)
|
||||
{
|
||||
int a;
|
||||
|
||||
read_byte(a);
|
||||
set_error(0);
|
||||
return (int8)a;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16 read16l(FILE *f, int *err)
|
||||
{
|
||||
int a, b;
|
||||
|
||||
read_byte(a);
|
||||
read_byte(b);
|
||||
|
||||
set_error(0);
|
||||
return ((uint16)b << 8) | a;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
uint16 read16b(FILE *f, int *err)
|
||||
{
|
||||
int a, b;
|
||||
|
||||
read_byte(a);
|
||||
read_byte(b);
|
||||
|
||||
set_error(0);
|
||||
return (a << 8) | b;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
uint32 read24l(FILE *f, int *err)
|
||||
{
|
||||
int a, b, c;
|
||||
|
||||
read_byte(a);
|
||||
read_byte(b);
|
||||
read_byte(c);
|
||||
|
||||
set_error(0);
|
||||
return (c << 16) | (b << 8) | a;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0xffffff;
|
||||
}
|
||||
|
||||
uint32 read24b(FILE *f, int *err)
|
||||
{
|
||||
int a, b, c;
|
||||
|
||||
read_byte(a);
|
||||
read_byte(b);
|
||||
read_byte(c);
|
||||
|
||||
set_error(0);
|
||||
return (a << 16) | (b << 8) | c;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0xffffff;
|
||||
}
|
||||
|
||||
uint32 read32l(FILE *f, int *err)
|
||||
{
|
||||
int a, b, c, d;
|
||||
|
||||
read_byte(a);
|
||||
read_byte(b);
|
||||
read_byte(c);
|
||||
read_byte(d);
|
||||
|
||||
set_error(0);
|
||||
return (d << 24) | (c << 16) | (b << 8) | a;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
uint32 read32b(FILE *f, int *err)
|
||||
{
|
||||
int a, b, c, d;
|
||||
|
||||
read_byte(a);
|
||||
read_byte(b);
|
||||
read_byte(c);
|
||||
read_byte(d);
|
||||
|
||||
set_error(0);
|
||||
return (a << 24) | (b << 16) | (c << 8) | d;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0xffffffff;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16 readmem16l(const uint8 *m)
|
||||
{
|
||||
uint32 a, b;
|
||||
|
||||
a = m[0];
|
||||
b = m[1];
|
||||
|
||||
return (b << 8) | a;
|
||||
}
|
||||
|
||||
uint16 readmem16b(const uint8 *m)
|
||||
{
|
||||
uint32 a, b;
|
||||
|
||||
a = m[0];
|
||||
b = m[1];
|
||||
|
||||
return (a << 8) | b;
|
||||
}
|
||||
|
||||
uint32 readmem24l(const uint8 *m)
|
||||
{
|
||||
uint32 a, b, c;
|
||||
|
||||
a = m[0];
|
||||
b = m[1];
|
||||
c = m[2];
|
||||
|
||||
return (c << 16) | (b << 8) | a;
|
||||
}
|
||||
|
||||
uint32 readmem24b(const uint8 *m)
|
||||
{
|
||||
uint32 a, b, c;
|
||||
|
||||
a = m[0];
|
||||
b = m[1];
|
||||
c = m[2];
|
||||
|
||||
return (a << 16) | (b << 8) | c;
|
||||
}
|
||||
|
||||
uint32 readmem32l(const uint8 *m)
|
||||
{
|
||||
uint32 a, b, c, d;
|
||||
|
||||
a = m[0];
|
||||
b = m[1];
|
||||
c = m[2];
|
||||
d = m[3];
|
||||
|
||||
return (d << 24) | (c << 16) | (b << 8) | a;
|
||||
}
|
||||
|
||||
uint32 readmem32b(const uint8 *m)
|
||||
{
|
||||
uint32 a, b, c, d;
|
||||
|
||||
a = m[0];
|
||||
b = m[1];
|
||||
c = m[2];
|
||||
d = m[3];
|
||||
|
||||
return (a << 24) | (b << 16) | (c << 8) | d;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
|
||||
void write16l(FILE *f, uint16 w)
|
||||
{
|
||||
write8(f, w & 0x00ff);
|
||||
write8(f, (w & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
void write16b(FILE *f, uint16 w)
|
||||
{
|
||||
write8(f, (w & 0xff00) >> 8);
|
||||
write8(f, w & 0x00ff);
|
||||
}
|
||||
|
||||
void write32l(FILE *f, uint32 w)
|
||||
{
|
||||
write8(f, w & 0x000000ff);
|
||||
write8(f, (w & 0x0000ff00) >> 8);
|
||||
write8(f, (w & 0x00ff0000) >> 16);
|
||||
write8(f, (w & 0xff000000) >> 24);
|
||||
}
|
||||
|
||||
void write32b(FILE *f, uint32 w)
|
||||
{
|
||||
write8(f, (w & 0xff000000) >> 24);
|
||||
write8(f, (w & 0x00ff0000) >> 16);
|
||||
write8(f, (w & 0x0000ff00) >> 8);
|
||||
write8(f, w & 0x000000ff);
|
||||
}
|
||||
|
||||
int move_data(FILE *out, FILE *in, int len)
|
||||
{
|
||||
uint8 buf[1024];
|
||||
int l;
|
||||
|
||||
do {
|
||||
l = fread(buf, 1, len > 1024 ? 1024 : len, in);
|
||||
fwrite(buf, 1, l, out);
|
||||
len -= l;
|
||||
} while (l > 0 && len > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -1,143 +0,0 @@
|
|||
#ifndef LIBXMP_EFFECTS_H
|
||||
#define LIBXMP_EFFECTS_H
|
||||
|
||||
/* Protracker effects */
|
||||
#define FX_ARPEGGIO 0x00
|
||||
#define FX_PORTA_UP 0x01
|
||||
#define FX_PORTA_DN 0x02
|
||||
#define FX_TONEPORTA 0x03
|
||||
#define FX_VIBRATO 0x04
|
||||
#define FX_TONE_VSLIDE 0x05
|
||||
#define FX_VIBRA_VSLIDE 0x06
|
||||
#define FX_TREMOLO 0x07
|
||||
#define FX_OFFSET 0x09
|
||||
#define FX_VOLSLIDE 0x0a
|
||||
#define FX_JUMP 0x0b
|
||||
#define FX_VOLSET 0x0c
|
||||
#define FX_BREAK 0x0d
|
||||
#define FX_EXTENDED 0x0e
|
||||
#define FX_SPEED 0x0f
|
||||
|
||||
/* Fast tracker effects */
|
||||
#define FX_SETPAN 0x08
|
||||
|
||||
/* Fast Tracker II effects */
|
||||
#define FX_GLOBALVOL 0x10
|
||||
#define FX_GVOL_SLIDE 0x11
|
||||
#define FX_KEYOFF 0x14
|
||||
#define FX_ENVPOS 0x15
|
||||
#define FX_PANSLIDE 0x19
|
||||
#define FX_MULTI_RETRIG 0x1b
|
||||
#define FX_TREMOR 0x1d
|
||||
#define FX_XF_PORTA 0x21
|
||||
|
||||
/* Protracker extended effects */
|
||||
#define EX_FILTER 0x00
|
||||
#define EX_F_PORTA_UP 0x01
|
||||
#define EX_F_PORTA_DN 0x02
|
||||
#define EX_GLISS 0x03
|
||||
#define EX_VIBRATO_WF 0x04
|
||||
#define EX_FINETUNE 0x05
|
||||
#define EX_PATTERN_LOOP 0x06
|
||||
#define EX_TREMOLO_WF 0x07
|
||||
#define EX_SETPAN 0x08
|
||||
#define EX_RETRIG 0x09
|
||||
#define EX_F_VSLIDE_UP 0x0a
|
||||
#define EX_F_VSLIDE_DN 0x0b
|
||||
#define EX_CUT 0x0c
|
||||
#define EX_DELAY 0x0d
|
||||
#define EX_PATT_DELAY 0x0e
|
||||
#define EX_INVLOOP 0x0f
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
/* Oktalyzer effects */
|
||||
#define FX_OKT_ARP3 0x70
|
||||
#define FX_OKT_ARP4 0x71
|
||||
#define FX_OKT_ARP5 0x72
|
||||
#define FX_NSLIDE2_DN 0x73
|
||||
#define FX_NSLIDE2_UP 0x74
|
||||
#define FX_F_NSLIDE_DN 0x75
|
||||
#define FX_F_NSLIDE_UP 0x76
|
||||
|
||||
/* Persistent effects -- for FNK and FAR */
|
||||
#define FX_PER_PORTA_DN 0x78
|
||||
#define FX_PER_PORTA_UP 0x79
|
||||
#define FX_PER_TPORTA 0x7a
|
||||
#define FX_PER_VIBRATO 0x7b
|
||||
#define FX_PER_VSLD_UP 0x7c
|
||||
#define FX_PER_VSLD_DN 0x7d
|
||||
#define FX_SPEED_CP 0x7e
|
||||
#define FX_PER_CANCEL 0x7f
|
||||
|
||||
/* 669 frequency based effects */
|
||||
#define FX_669_PORTA_UP 0x60
|
||||
#define FX_669_PORTA_DN 0x61
|
||||
#define FX_669_TPORTA 0x62
|
||||
#define FX_669_FINETUNE 0x63
|
||||
#define FX_669_VIBRATO 0x64
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
/* IT effects */
|
||||
#define FX_TRK_VOL 0x80
|
||||
#define FX_TRK_VSLIDE 0x81
|
||||
#define FX_TRK_FVSLIDE 0x82
|
||||
#define FX_IT_INSTFUNC 0x83
|
||||
#define FX_FLT_CUTOFF 0x84
|
||||
#define FX_FLT_RESN 0x85
|
||||
#define FX_IT_BPM 0x87
|
||||
#define FX_IT_ROWDELAY 0x88
|
||||
#define FX_IT_PANSLIDE 0x89
|
||||
#define FX_PANBRELLO 0x8a
|
||||
#define FX_PANBRELLO_WF 0x8b
|
||||
#define FX_HIOFFSET 0x8c
|
||||
#define FX_IT_BREAK 0x8e /* like FX_BREAK with hex parameter */
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
/* MED effects */
|
||||
#define FX_HOLD_DECAY 0x90
|
||||
#define FX_SETPITCH 0x91
|
||||
#define FX_VIBRATO2 0x92
|
||||
|
||||
/* PTM effects */
|
||||
#define FX_NSLIDE_DN 0x9c /* IMF/PTM note slide down */
|
||||
#define FX_NSLIDE_UP 0x9d /* IMF/PTM note slide up */
|
||||
#define FX_NSLIDE_R_UP 0x9e /* PTM note slide down with retrigger */
|
||||
#define FX_NSLIDE_R_DN 0x9f /* PTM note slide up with retrigger */
|
||||
|
||||
/* Extra effects */
|
||||
#define FX_VOLSLIDE_UP 0xa0 /* SFX, MDL */
|
||||
#define FX_VOLSLIDE_DN 0xa1
|
||||
#define FX_F_VSLIDE 0xa5 /* IMF/MDL */
|
||||
#define FX_CHORUS 0xa9 /* IMF */
|
||||
#define FX_ICE_SPEED 0xa2
|
||||
#define FX_REVERB 0xaa /* IMF */
|
||||
#define FX_MED_HOLD 0xb1 /* MMD hold/decay */
|
||||
#define FX_MEGAARP 0xb2 /* Smaksak effect 7: MegaArp */
|
||||
#define FX_VOL_ADD 0xb6 /* SFX change volume up */
|
||||
#define FX_VOL_SUB 0xb7 /* SFX change volume down */
|
||||
#define FX_PITCH_ADD 0xb8 /* SFX add steps to current note */
|
||||
#define FX_PITCH_SUB 0xb9 /* SFX add steps to current note */
|
||||
#endif
|
||||
|
||||
#define FX_SURROUND 0x8d /* S3M/IT */
|
||||
#define FX_S3M_SPEED 0xa3 /* S3M */
|
||||
#define FX_VOLSLIDE_2 0xa4
|
||||
#define FX_FINETUNE 0xa6
|
||||
#define FX_S3M_BPM 0xab /* S3M */
|
||||
#define FX_FINE_VIBRATO 0xac /* S3M/PTM/IMF/LIQ */
|
||||
#define FX_F_VSLIDE_UP 0xad /* MMD */
|
||||
#define FX_F_VSLIDE_DN 0xae /* MMD */
|
||||
#define FX_F_PORTA_UP 0xaf /* MMD */
|
||||
#define FX_F_PORTA_DN 0xb0 /* MMD */
|
||||
#define FX_PATT_DELAY 0xb3 /* MMD */
|
||||
#define FX_S3M_ARPEGGIO 0xb4
|
||||
#define FX_PANSL_NOMEM 0xb5 /* XM volume column */
|
||||
|
||||
#define FX_VSLIDE_UP_2 0xc0 /* IT volume column volume slide */
|
||||
#define FX_VSLIDE_DN_2 0xc1
|
||||
#define FX_F_VSLIDE_UP_2 0xc2
|
||||
#define FX_F_VSLIDE_DN_2 0xc3
|
||||
|
||||
#endif /* LIBXMP_EFFECTS_H */
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
* Based on the public domain version by Olivier Lapicque
|
||||
* Rewritten for libxmp by Claudio Matsuoka
|
||||
*
|
||||
* Copyright (C) 2012 Claudio Matsuoka
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
#include <math.h>
|
||||
#include "xmp.h"
|
||||
#include "common.h"
|
||||
#include "mixer.h"
|
||||
|
||||
|
||||
/* LUT for 2 * damping factor */
|
||||
static const float resonance_table[128] = {
|
||||
1.0000000000000000f, 0.9786446094512940f, 0.9577452540397644f, 0.9372922182083130f,
|
||||
0.9172759056091309f, 0.8976871371269226f, 0.8785166740417481f, 0.8597555756568909f,
|
||||
0.8413951396942139f, 0.8234267830848694f, 0.8058421611785889f, 0.7886331081390381f,
|
||||
0.7717915177345276f, 0.7553095817565918f, 0.7391796708106995f, 0.7233941555023193f,
|
||||
0.7079457640647888f, 0.6928272843360901f, 0.6780316829681397f, 0.6635520458221436f,
|
||||
0.6493816375732422f, 0.6355138421058655f, 0.6219421625137329f, 0.6086603403091431f,
|
||||
0.5956621170043945f, 0.5829415321350098f, 0.5704925656318665f, 0.5583094954490662f,
|
||||
0.5463865399360657f, 0.5347182154655457f, 0.5232990980148315f, 0.5121238231658936f,
|
||||
0.5011872053146362f, 0.4904841780662537f, 0.4800096750259399f, 0.4697588682174683f,
|
||||
0.4597269892692566f, 0.4499093294143677f, 0.4403013288974762f, 0.4308985173702240f,
|
||||
0.4216965138912201f, 0.4126909971237183f, 0.4038778245449066f, 0.3952528536319733f,
|
||||
0.3868120610713959f, 0.3785515129566193f, 0.3704673945903778f, 0.3625559210777283f,
|
||||
0.3548133969306946f, 0.3472362160682678f, 0.3398208320140839f, 0.3325638175010681f,
|
||||
0.3254617750644684f, 0.3185114264488220f, 0.3117094635963440f, 0.3050527870655060f,
|
||||
0.2985382676124573f, 0.2921628654003143f, 0.2859236001968384f, 0.2798175811767578f,
|
||||
0.2738419771194458f, 0.2679939568042755f, 0.2622708380222321f, 0.2566699385643005f,
|
||||
0.2511886358261108f, 0.2458244115114212f, 0.2405747324228287f, 0.2354371547698975f,
|
||||
0.2304092943668366f, 0.2254888117313385f, 0.2206734120845795f, 0.2159608304500580f,
|
||||
0.2113489061594009f, 0.2068354636430740f, 0.2024184018373489f, 0.1980956792831421f,
|
||||
0.1938652694225311f, 0.1897251904010773f, 0.1856735348701477f, 0.1817083954811096f,
|
||||
0.1778279393911362f, 0.1740303486585617f, 0.1703138649463654f, 0.1666767448186874f,
|
||||
0.1631172895431519f, 0.1596338599920273f, 0.1562248021364212f, 0.1528885662555695f,
|
||||
0.1496235728263855f, 0.1464282870292664f, 0.1433012634515762f, 0.1402409970760346f,
|
||||
0.1372461020946503f, 0.1343151479959488f, 0.1314467936754227f, 0.1286396980285645f,
|
||||
0.1258925348520279f, 0.1232040524482727f, 0.1205729842185974f, 0.1179980933666229f,
|
||||
0.1154781952500343f, 0.1130121126770973f, 0.1105986908078194f, 0.1082368120551109f,
|
||||
0.1059253737330437f, 0.1036632955074310f, 0.1014495193958283f, 0.0992830246686935f,
|
||||
0.0971627980470657f, 0.0950878411531448f, 0.0930572077631950f, 0.0910699293017387f,
|
||||
0.0891250967979431f, 0.0872217938303947f, 0.0853591337800026f, 0.0835362523794174f,
|
||||
0.0817523002624512f, 0.0800064504146576f, 0.0782978758215904f, 0.0766257941722870f,
|
||||
0.0749894231557846f, 0.0733879879117012f, 0.0718207582831383f, 0.0702869966626167f,
|
||||
0.0687859877943993f, 0.0673170387744904f, 0.0658794566988945f, 0.0644725710153580f,
|
||||
};
|
||||
|
||||
|
||||
#if !defined(HAVE_POWF) || defined(__DJGPP__) || defined(__WATCOMC__)
|
||||
#define powf pow /* Watcom doesn't have powf. DJGPP have a C-only implementation in libm. */
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Simple 2-poles resonant filter
|
||||
*/
|
||||
#define FREQ_PARAM_MULT (128.0f / (24.0f * 256.0f))
|
||||
void libxmp_filter_setup(int srate, int cutoff, int res, int *a0, int *b0, int *b1)
|
||||
{
|
||||
float fc, fs = (float)srate;
|
||||
float fg, fb0, fb1;
|
||||
float r, d, e;
|
||||
|
||||
/* [0-255] => [100Hz-8000Hz] */
|
||||
CLAMP(cutoff, 0, 255);
|
||||
CLAMP(res, 0, 255);
|
||||
|
||||
fc = 110.0f * powf(2.0f, (float)cutoff * FREQ_PARAM_MULT + 0.25f);
|
||||
if (fc > fs / 2.0f) {
|
||||
fc = fs / 2.0f;
|
||||
}
|
||||
|
||||
r = fs / (2.0 * 3.14159265358979f * fc);
|
||||
d = resonance_table[res >> 1] * (r + 1.0) - 1.0;
|
||||
e = r * r;
|
||||
|
||||
fg = 1.0 / (1.0 + d + e);
|
||||
fb0 = (d + e + e) / (1.0 + d + e);
|
||||
fb1 = -e / (1.0 + d + e);
|
||||
|
||||
*a0 = (int)(fg * (1 << FILTER_SHIFT));
|
||||
*b0 = (int)(fb0 * (1 << FILTER_SHIFT));
|
||||
*b1 = (int)(fb1 * (1 << FILTER_SHIFT));
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,65 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
#include "loaders/prowizard/prowiz.h"
|
||||
#endif
|
||||
#include "format.h"
|
||||
|
||||
extern const struct format_loader libxmp_loader_xm;
|
||||
extern const struct format_loader libxmp_loader_mod;
|
||||
extern const struct format_loader libxmp_loader_it;
|
||||
extern const struct format_loader libxmp_loader_s3m;
|
||||
extern const struct format_loader libxmp_loader_mtm;
|
||||
|
||||
extern const struct pw_format *const pw_format[];
|
||||
|
||||
extern const struct format_loader *const format_loader[];
|
||||
const struct format_loader *const format_loader[] = {
|
||||
&libxmp_loader_xm,
|
||||
&libxmp_loader_mod,
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
&libxmp_loader_it,
|
||||
#endif
|
||||
&libxmp_loader_s3m,
|
||||
&libxmp_loader_mtm,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *_farray[sizeof(format_loader)/sizeof(struct format_loader *)] = { NULL };
|
||||
|
||||
const char **format_list()
|
||||
{
|
||||
int count, i;
|
||||
|
||||
if (_farray[0] == NULL) {
|
||||
for (count = i = 0; format_loader[i] != NULL; i++) {
|
||||
_farray[count++] = format_loader[i]->name;
|
||||
}
|
||||
|
||||
_farray[count] = NULL;
|
||||
}
|
||||
|
||||
return _farray;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#ifndef LIBXMP_FORMAT_H
|
||||
#define LIBXMP_FORMAT_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "common.h"
|
||||
#include "hio.h"
|
||||
|
||||
struct format_loader {
|
||||
const char *name;
|
||||
int (*const test)(HIO_HANDLE *, char *, const int);
|
||||
int (*const loader)(struct module_data *, HIO_HANDLE *, const int);
|
||||
};
|
||||
|
||||
const char **format_list(void);
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
|
||||
#define NUM_FORMATS 52
|
||||
#define NUM_PW_FORMATS 43
|
||||
|
||||
int pw_test_format(HIO_HANDLE *, char *, const int, struct xmp_test_info *);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,428 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
#include "hio.h"
|
||||
#include "mdataio.h"
|
||||
|
||||
#ifdef EDUKE32_DISABLED
|
||||
static long get_size(FILE *f)
|
||||
{
|
||||
long size, pos;
|
||||
|
||||
pos = ftell(f);
|
||||
if (pos >= 0) {
|
||||
if (fseek(f, 0, SEEK_END) < 0) {
|
||||
return -1;
|
||||
}
|
||||
size = ftell(f);
|
||||
if (fseek(f, pos, SEEK_SET) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return size;
|
||||
} else {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int8 hio_read8s(HIO_HANDLE *h)
|
||||
{
|
||||
#ifdef EDUKE32_DISABLED
|
||||
int err;
|
||||
#endif
|
||||
int8 ret = 0;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read8s(h->handle.file, &err);
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread8s(h->handle.mem);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8 hio_read8(HIO_HANDLE *h)
|
||||
{
|
||||
#ifdef EDUKE32_DISABLED
|
||||
int err;
|
||||
#endif
|
||||
uint8 ret = 0;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read8(h->handle.file, &err);
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread8(h->handle.mem);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16 hio_read16l(HIO_HANDLE *h)
|
||||
{
|
||||
#ifdef EDUKE32_DISABLED
|
||||
int err;
|
||||
#endif
|
||||
uint16 ret = 0;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read16l(h->handle.file, &err);
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread16l(h->handle.mem);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16 hio_read16b(HIO_HANDLE *h)
|
||||
{
|
||||
#ifdef EDUKE32_DISABLED
|
||||
int err;
|
||||
#endif
|
||||
uint16 ret = 0;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read16b(h->handle.file, &err);
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread16b(h->handle.mem);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 hio_read24l(HIO_HANDLE *h)
|
||||
{
|
||||
#ifdef EDUKE32_DISABLED
|
||||
int err;
|
||||
#endif
|
||||
uint32 ret = 0;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read24l(h->handle.file, &err);
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread24l(h->handle.mem);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 hio_read24b(HIO_HANDLE *h)
|
||||
{
|
||||
#ifdef EDUKE32_DISABLED
|
||||
int err;
|
||||
#endif
|
||||
uint32 ret = 0;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read24b(h->handle.file, &err);
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread24b(h->handle.mem);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 hio_read32l(HIO_HANDLE *h)
|
||||
{
|
||||
#ifdef EDUKE32_DISABLED
|
||||
int err;
|
||||
#endif
|
||||
uint32 ret = 0;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read32l(h->handle.file, &err);
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread32l(h->handle.mem);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 hio_read32b(HIO_HANDLE *h)
|
||||
{
|
||||
#ifdef EDUKE32_DISABLED
|
||||
int err;
|
||||
#endif
|
||||
uint32 ret = 0;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read32b(h->handle.file, &err);
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread32b(h->handle.mem);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t hio_read(void *buf, size_t size, size_t num, HIO_HANDLE *h)
|
||||
{
|
||||
size_t ret = 0;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = fread(buf, size, num, h->handle.file);
|
||||
if (ret != num) {
|
||||
if (ferror(h->handle.file)) {
|
||||
h->error = errno;
|
||||
} else {
|
||||
h->error = feof(h->handle.file) ? EOF : -2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread(buf, size, num, h->handle.mem);
|
||||
if (ret != num) {
|
||||
h->error = errno;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hio_seek(HIO_HANDLE *h, long offset, int whence)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = fseek(h->handle.file, offset, whence);
|
||||
if (ret < 0) {
|
||||
h->error = errno;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mseek(h->handle.mem, offset, whence);
|
||||
if (ret < 0) {
|
||||
h->error = errno;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
long hio_tell(HIO_HANDLE *h)
|
||||
{
|
||||
long ret = -1;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = ftell(h->handle.file);
|
||||
if (ret < 0) {
|
||||
h->error = errno;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mtell(h->handle.mem);
|
||||
if (ret < 0) {
|
||||
h->error = errno;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hio_eof(HIO_HANDLE *h)
|
||||
{
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
return feof(h->handle.file);
|
||||
#endif
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
return meof(h->handle.mem);
|
||||
default:
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
int hio_error(HIO_HANDLE *h)
|
||||
{
|
||||
int error = h->error;
|
||||
h->error = 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
#ifdef EDUKE32_DISABLED
|
||||
HIO_HANDLE *hio_open(const void *path, const char *mode)
|
||||
{
|
||||
HIO_HANDLE *h;
|
||||
|
||||
h = (HIO_HANDLE *)malloc(sizeof (HIO_HANDLE));
|
||||
if (h == NULL)
|
||||
goto err;
|
||||
|
||||
h->error = 0;
|
||||
h->type = HIO_HANDLE_TYPE_FILE;
|
||||
h->handle.file = fopen((const char *)path, mode);
|
||||
if (h->handle.file == NULL)
|
||||
goto err2;
|
||||
|
||||
h->size = get_size(h->handle.file);
|
||||
if (h->size < 0)
|
||||
goto err3;
|
||||
|
||||
return h;
|
||||
|
||||
err3:
|
||||
fclose(h->handle.file);
|
||||
err2:
|
||||
free(h);
|
||||
err:
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
HIO_HANDLE *hio_open_mem(const void *ptr, long size)
|
||||
{
|
||||
HIO_HANDLE *h;
|
||||
|
||||
h = (HIO_HANDLE *)malloc(sizeof (HIO_HANDLE));
|
||||
if (h == NULL)
|
||||
return NULL;
|
||||
|
||||
h->error = 0;
|
||||
h->type = HIO_HANDLE_TYPE_MEMORY;
|
||||
h->handle.mem = mopen(ptr, size);
|
||||
h->size = size;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
#ifdef EDUKE32_DISABLED
|
||||
HIO_HANDLE *hio_open_file(FILE *f)
|
||||
{
|
||||
HIO_HANDLE *h;
|
||||
|
||||
h = (HIO_HANDLE *)malloc(sizeof (HIO_HANDLE));
|
||||
if (h == NULL)
|
||||
return NULL;
|
||||
|
||||
h->error = 0;
|
||||
h->type = HIO_HANDLE_TYPE_FILE;
|
||||
h->handle.file = f /*fdopen(fileno(f), "rb")*/;
|
||||
h->size = get_size(f);
|
||||
|
||||
return h;
|
||||
}
|
||||
#endif
|
||||
|
||||
int hio_close(HIO_HANDLE *h)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = fclose(h->handle.file);
|
||||
break;
|
||||
#endif
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mclose(h->handle.mem);
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
free(h);
|
||||
return ret;
|
||||
}
|
||||
|
||||
long hio_size(HIO_HANDLE *h)
|
||||
{
|
||||
return h->size;
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
#ifndef XMP_HIO_H
|
||||
#define XMP_HIO_H
|
||||
|
||||
#ifdef EDUKE32_DISABLED
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
#include "memio.h"
|
||||
|
||||
#define HIO_HANDLE_TYPE(x) ((x)->type)
|
||||
|
||||
typedef struct {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
#define HIO_HANDLE_TYPE_FILE 0
|
||||
#endif
|
||||
#define HIO_HANDLE_TYPE_MEMORY 1
|
||||
int type;
|
||||
long size;
|
||||
union {
|
||||
#ifdef EDUKE32_DISABLED
|
||||
FILE *file;
|
||||
#endif
|
||||
MFILE *mem;
|
||||
} handle;
|
||||
int error;
|
||||
} HIO_HANDLE;
|
||||
|
||||
int8 hio_read8s (HIO_HANDLE *);
|
||||
uint8 hio_read8 (HIO_HANDLE *);
|
||||
uint16 hio_read16l (HIO_HANDLE *);
|
||||
uint16 hio_read16b (HIO_HANDLE *);
|
||||
uint32 hio_read24l (HIO_HANDLE *);
|
||||
uint32 hio_read24b (HIO_HANDLE *);
|
||||
uint32 hio_read32l (HIO_HANDLE *);
|
||||
uint32 hio_read32b (HIO_HANDLE *);
|
||||
size_t hio_read (void *, size_t, size_t, HIO_HANDLE *);
|
||||
int hio_seek (HIO_HANDLE *, long, int);
|
||||
long hio_tell (HIO_HANDLE *);
|
||||
int hio_eof (HIO_HANDLE *);
|
||||
int hio_error (HIO_HANDLE *);
|
||||
#ifdef EDUKE32_DISABLED
|
||||
HIO_HANDLE *hio_open (const void *, const char *);
|
||||
#endif
|
||||
HIO_HANDLE *hio_open_mem (const void *, long);
|
||||
#ifdef EDUKE32_DISABLED
|
||||
HIO_HANDLE *hio_open_file (FILE *);
|
||||
#endif
|
||||
int hio_close (HIO_HANDLE *);
|
||||
long hio_size (HIO_HANDLE *);
|
||||
|
||||
#endif
|
|
@ -1,181 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* IT flags */
|
||||
#define IT_STEREO 0x01
|
||||
#define IT_VOL_OPT 0x02 /* Not recognized */
|
||||
#define IT_USE_INST 0x04
|
||||
#define IT_LINEAR_FREQ 0x08
|
||||
#define IT_OLD_FX 0x10
|
||||
#define IT_LINK_GXX 0x20
|
||||
|
||||
/* IT special */
|
||||
#define IT_HAS_MSG 0x01
|
||||
|
||||
/* IT instrument flags */
|
||||
#define IT_INST_SAMPLE 0x01
|
||||
#define IT_INST_16BIT 0x02
|
||||
#define IT_INST_STEREO 0x04
|
||||
#define IT_INST_LOOP 0x10
|
||||
#define IT_INST_SLOOP 0x20
|
||||
#define IT_INST_BLOOP 0x40
|
||||
#define IT_INST_BSLOOP 0x80
|
||||
|
||||
/* IT sample flags */
|
||||
#define IT_SMP_SAMPLE 0x01
|
||||
#define IT_SMP_16BIT 0x02
|
||||
#define IT_SMP_STEREO 0x04 /* unsupported */
|
||||
#define IT_SMP_COMP 0x08 /* unsupported */
|
||||
#define IT_SMP_LOOP 0x10
|
||||
#define IT_SMP_SLOOP 0x20
|
||||
#define IT_SMP_BLOOP 0x40
|
||||
#define IT_SMP_BSLOOP 0x80
|
||||
|
||||
/* IT sample conversion flags */
|
||||
#define IT_CVT_SIGNED 0x01
|
||||
#define IT_CVT_BIGEND 0x02 /* 'safe to ignore' according to ittech.txt */
|
||||
#define IT_CVT_DIFF 0x04 /* Compressed sample flag */
|
||||
#define IT_CVT_BYTEDIFF 0x08 /* 'safe to ignore' according to ittech.txt */
|
||||
#define IT_CVT_12BIT 0x10 /* 'safe to ignore' according to ittech.txt */
|
||||
|
||||
/* IT envelope flags */
|
||||
#define IT_ENV_ON 0x01
|
||||
#define IT_ENV_LOOP 0x02
|
||||
#define IT_ENV_SLOOP 0x04
|
||||
#define IT_ENV_CARRY 0x08
|
||||
#define IT_ENV_FILTER 0x80
|
||||
|
||||
|
||||
struct it_file_header {
|
||||
uint32 magic; /* 'IMPM' */
|
||||
uint8 name[26]; /* ASCIIZ Song name */
|
||||
uint8 hilite_min; /* Pattern editor highlight */
|
||||
uint8 hilite_maj; /* Pattern editor highlight */
|
||||
uint16 ordnum; /* Number of orders (must be even) */
|
||||
uint16 insnum; /* Number of instruments */
|
||||
uint16 smpnum; /* Number of samples */
|
||||
uint16 patnum; /* Number of patterns */
|
||||
uint16 cwt; /* Tracker ID and version */
|
||||
uint16 cmwt; /* Format version */
|
||||
uint16 flags; /* Flags */
|
||||
uint16 special; /* More flags */
|
||||
uint8 gv; /* Global volume */
|
||||
uint8 mv; /* Master volume */
|
||||
uint8 is; /* Initial speed */
|
||||
uint8 it; /* Initial tempo */
|
||||
uint8 sep; /* Panning separation */
|
||||
uint8 pwd; /* Pitch wheel depth */
|
||||
uint16 msglen; /* Message length */
|
||||
uint32 msgofs; /* Message offset */
|
||||
uint32 rsvd; /* Reserved */
|
||||
uint8 chpan[64]; /* Channel pan settings */
|
||||
uint8 chvol[64]; /* Channel volume settings */
|
||||
};
|
||||
|
||||
struct it_instrument1_header {
|
||||
uint32 magic; /* 'IMPI' */
|
||||
uint8 dosname[12]; /* DOS filename */
|
||||
uint8 zero; /* Always zero */
|
||||
uint8 flags; /* Instrument flags */
|
||||
uint8 vls; /* Volume loop start */
|
||||
uint8 vle; /* Volume loop end */
|
||||
uint8 sls; /* Sustain loop start */
|
||||
uint8 sle; /* Sustain loop end */
|
||||
uint16 rsvd1; /* Reserved */
|
||||
uint16 fadeout; /* Fadeout (release) */
|
||||
uint8 nna; /* New note action */
|
||||
uint8 dnc; /* Duplicate note check */
|
||||
uint16 trkvers; /* Tracker version */
|
||||
uint8 nos; /* Number of samples */
|
||||
uint8 rsvd2; /* Reserved */
|
||||
uint8 name[26]; /* ASCIIZ Instrument name */
|
||||
uint8 rsvd3[6]; /* Reserved */
|
||||
uint8 keys[240];
|
||||
uint8 epoint[200];
|
||||
uint8 enode[50];
|
||||
};
|
||||
|
||||
struct it_instrument2_header {
|
||||
uint32 magic; /* 'IMPI' */
|
||||
uint8 dosname[12]; /* DOS filename */
|
||||
uint8 zero; /* Always zero */
|
||||
uint8 nna; /* New Note Action */
|
||||
uint8 dct; /* Duplicate Check Type */
|
||||
uint8 dca; /* Duplicate Check Action */
|
||||
uint16 fadeout;
|
||||
uint8 pps; /* Pitch-Pan Separation */
|
||||
uint8 ppc; /* Pitch-Pan Center */
|
||||
uint8 gbv; /* Global Volume */
|
||||
uint8 dfp; /* Default pan */
|
||||
uint8 rv; /* Random volume variation */
|
||||
uint8 rp; /* Random pan variation */
|
||||
uint16 trkvers; /* Not used: tracked version */
|
||||
uint8 nos; /* Not used: number of samples */
|
||||
uint8 rsvd1; /* Reserved */
|
||||
uint8 name[26]; /* ASCIIZ Instrument name */
|
||||
uint8 ifc; /* Initial filter cutoff */
|
||||
uint8 ifr; /* Initial filter resonance */
|
||||
uint8 mch; /* MIDI channel */
|
||||
uint8 mpr; /* MIDI program */
|
||||
uint16 mbnk; /* MIDI bank */
|
||||
uint8 keys[240];
|
||||
};
|
||||
|
||||
struct it_envelope_node {
|
||||
int8 y;
|
||||
uint16 x;
|
||||
};
|
||||
|
||||
struct it_envelope {
|
||||
uint8 flg; /* Flags */
|
||||
uint8 num; /* Number of node points */
|
||||
uint8 lpb; /* Loop beginning */
|
||||
uint8 lpe; /* Loop end */
|
||||
uint8 slb; /* Sustain loop beginning */
|
||||
uint8 sle; /* Sustain loop end */
|
||||
struct it_envelope_node node[25];
|
||||
uint8 unused;
|
||||
};
|
||||
|
||||
struct it_sample_header {
|
||||
uint32 magic; /* 'IMPS' */
|
||||
uint8 dosname[12]; /* DOS filename */
|
||||
uint8 zero; /* Always zero */
|
||||
uint8 gvl; /* Global volume for instrument */
|
||||
uint8 flags; /* Sample flags */
|
||||
uint8 vol; /* Volume */
|
||||
uint8 name[26]; /* ASCIIZ sample name */
|
||||
uint8 convert; /* Sample flags */
|
||||
uint8 dfp; /* Default pan */
|
||||
uint32 length; /* Length */
|
||||
uint32 loopbeg; /* Loop begin */
|
||||
uint32 loopend; /* Loop end */
|
||||
uint32 c5spd; /* C 5 speed */
|
||||
uint32 sloopbeg; /* SusLoop begin */
|
||||
uint32 sloopend; /* SusLoop end */
|
||||
uint32 sample_ptr; /* Sample pointer */
|
||||
uint8 vis; /* Vibrato speed */
|
||||
uint8 vid; /* Vibrato depth */
|
||||
uint8 vir; /* Vibrato rate */
|
||||
uint8 vit; /* Vibrato waveform */
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,232 +0,0 @@
|
|||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
|
||||
/* Public domain IT sample decompressor by Olivier Lapicque */
|
||||
|
||||
#include "loader.h"
|
||||
|
||||
static inline uint32 read_bits(HIO_HANDLE *ibuf, uint32 *bitbuf, int *bitnum, int n)
|
||||
{
|
||||
uint32 retval = 0;
|
||||
int i = n;
|
||||
int bnum = *bitnum, bbuf = *bitbuf;
|
||||
|
||||
if (n > 0) {
|
||||
do {
|
||||
if (bnum == 0) {
|
||||
bbuf = hio_read8(ibuf);
|
||||
bnum = 8;
|
||||
}
|
||||
retval >>= 1;
|
||||
retval |= bbuf << 31;
|
||||
bbuf >>= 1;
|
||||
bnum--;
|
||||
i--;
|
||||
} while (i != 0);
|
||||
|
||||
i = n;
|
||||
|
||||
*bitnum = bnum;
|
||||
*bitbuf = bbuf;
|
||||
}
|
||||
|
||||
return (retval >> (32 - i));
|
||||
}
|
||||
|
||||
|
||||
int itsex_decompress8(HIO_HANDLE *src, uint8 *dst, int len, int it215)
|
||||
{
|
||||
/* uint32 size = 0; */
|
||||
uint32 block_count = 0;
|
||||
uint32 bitbuf = 0;
|
||||
int bitnum = 0;
|
||||
uint8 left = 0, temp = 0, temp2 = 0;
|
||||
uint32 d, pos;
|
||||
|
||||
while (len) {
|
||||
if (!block_count) {
|
||||
block_count = 0x8000;
|
||||
/*size =*/ hio_read16l(src);
|
||||
left = 9;
|
||||
temp = temp2 = 0;
|
||||
bitbuf = bitnum = 0;
|
||||
}
|
||||
|
||||
d = block_count;
|
||||
if (d > len)
|
||||
d = len;
|
||||
|
||||
/* Unpacking */
|
||||
pos = 0;
|
||||
do {
|
||||
uint16 bits = read_bits(src, &bitbuf, &bitnum, left);
|
||||
if (hio_eof(src))
|
||||
return -1;
|
||||
|
||||
if (left < 7) {
|
||||
uint32 i = 1 << (left - 1);
|
||||
uint32 j = bits & 0xffff;
|
||||
if (i != j)
|
||||
goto unpack_byte;
|
||||
bits = (read_bits(src, &bitbuf, &bitnum, 3)
|
||||
+ 1) & 0xff;
|
||||
if (hio_eof(src))
|
||||
return -1;
|
||||
|
||||
left = ((uint8)bits < left) ? (uint8)bits :
|
||||
(uint8)((bits + 1) & 0xff);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (left < 9) {
|
||||
uint16 i = (0xff >> (9 - left)) + 4;
|
||||
uint16 j = i - 8;
|
||||
|
||||
if ((bits <= j) || (bits > i))
|
||||
goto unpack_byte;
|
||||
|
||||
bits -= j;
|
||||
left = ((uint8)(bits & 0xff) < left) ?
|
||||
(uint8)(bits & 0xff) :
|
||||
(uint8)((bits + 1) & 0xff);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (left >= 10)
|
||||
goto skip_byte;
|
||||
|
||||
if (bits >= 256) {
|
||||
left = (uint8) (bits + 1) & 0xff;
|
||||
goto next;
|
||||
}
|
||||
|
||||
unpack_byte:
|
||||
if (left < 8) {
|
||||
uint8 shift = 8 - left;
|
||||
signed char c = (signed char)(bits << shift);
|
||||
c >>= shift;
|
||||
bits = (uint16) c;
|
||||
}
|
||||
bits += temp;
|
||||
temp = (uint8)bits;
|
||||
temp2 += temp;
|
||||
dst[pos] = it215 ? temp2 : temp;
|
||||
|
||||
skip_byte:
|
||||
pos++;
|
||||
|
||||
next:
|
||||
/* if (slen <= 0)
|
||||
return -1 */;
|
||||
} while (pos < d);
|
||||
|
||||
/* Move On */
|
||||
block_count -= d;
|
||||
len -= d;
|
||||
dst += d;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int itsex_decompress16(HIO_HANDLE *src, int16 *dst, int len, int it215)
|
||||
{
|
||||
/* uint32 size = 0; */
|
||||
uint32 block_count = 0;
|
||||
uint32 bitbuf = 0;
|
||||
int bitnum = 0;
|
||||
uint8 left = 0;
|
||||
int16 temp = 0, temp2 = 0;
|
||||
uint32 d, pos;
|
||||
|
||||
while (len) {
|
||||
if (!block_count) {
|
||||
block_count = 0x4000;
|
||||
/*size =*/ hio_read16l(src);
|
||||
left = 17;
|
||||
temp = temp2 = 0;
|
||||
bitbuf = bitnum = 0;
|
||||
}
|
||||
|
||||
d = block_count;
|
||||
if (d > len)
|
||||
d = len;
|
||||
|
||||
/* Unpacking */
|
||||
pos = 0;
|
||||
do {
|
||||
uint32 bits = read_bits(src, &bitbuf, &bitnum, left);
|
||||
if (hio_eof(src))
|
||||
return -1;
|
||||
|
||||
if (left < 7) {
|
||||
uint32 i = 1 << (left - 1);
|
||||
uint32 j = bits;
|
||||
|
||||
if (i != j)
|
||||
goto unpack_byte;
|
||||
|
||||
bits = read_bits(src, &bitbuf, &bitnum, 4) + 1;
|
||||
|
||||
if (hio_eof(src))
|
||||
return -1;
|
||||
|
||||
left = ((uint8)(bits & 0xff) < left) ?
|
||||
(uint8)(bits & 0xff) :
|
||||
(uint8)((bits + 1) & 0xff);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (left < 17) {
|
||||
uint32 i = (0xffff >> (17 - left)) + 8;
|
||||
uint32 j = (i - 16) & 0xffff;
|
||||
|
||||
if ((bits <= j) || (bits > (i & 0xffff)))
|
||||
goto unpack_byte;
|
||||
|
||||
bits -= j;
|
||||
left = ((uint8)(bits & 0xff) < left) ?
|
||||
(uint8)(bits & 0xff) :
|
||||
(uint8)((bits + 1) & 0xff);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (left >= 18)
|
||||
goto skip_byte;
|
||||
|
||||
if (bits >= 0x10000) {
|
||||
left = (uint8)(bits + 1) & 0xff;
|
||||
goto next;
|
||||
}
|
||||
|
||||
unpack_byte:
|
||||
if (left < 16) {
|
||||
uint8 shift = 16 - left;
|
||||
int16 c = (int16)(bits << shift);
|
||||
c >>= shift;
|
||||
bits = (uint32) c;
|
||||
}
|
||||
bits += temp;
|
||||
temp = (int16)bits;
|
||||
temp2 += temp;
|
||||
dst[pos] = (it215) ? temp2 : temp;
|
||||
|
||||
skip_byte:
|
||||
pos++;
|
||||
|
||||
next:
|
||||
/* if (slen <= 0)
|
||||
return -1 */;
|
||||
} while (pos < d);
|
||||
|
||||
/* Move On */
|
||||
block_count -= d;
|
||||
len -= d;
|
||||
dst += d;
|
||||
if (len <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* LIBXMP_CORE_DISABLE_IT */
|
|
@ -1,164 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "lfo.h"
|
||||
|
||||
#define WAVEFORM_SIZE 64
|
||||
|
||||
static const int sine_wave[WAVEFORM_SIZE] = {
|
||||
0, 24, 49, 74, 97, 120, 141, 161, 180, 197, 212, 224,
|
||||
235, 244, 250, 253, 255, 253, 250, 244, 235, 224, 212, 197,
|
||||
180, 161, 141, 120, 97, 74, 49, 24, 0, -24, -49, -74,
|
||||
-97,-120,-141,-161,-180,-197,-212,-224,-235,-244,-250,-253,
|
||||
-255,-253,-250,-244,-235,-224,-212,-197,-180,-161,-141,-120,
|
||||
-97, -74, -49, -24
|
||||
};
|
||||
|
||||
/* LFO */
|
||||
|
||||
static int get_lfo_mod(struct lfo *lfo)
|
||||
{
|
||||
int val;
|
||||
|
||||
if (lfo->rate == 0)
|
||||
return 0;
|
||||
|
||||
switch (lfo->type) {
|
||||
case 0: /* sine */
|
||||
val = sine_wave[lfo->phase];
|
||||
break;
|
||||
case 1: /* ramp down */
|
||||
val = 255 - (lfo->phase << 3);
|
||||
break;
|
||||
case 2: /* square */
|
||||
val = lfo->phase < WAVEFORM_SIZE / 2 ? 255 : -255;
|
||||
break;
|
||||
case 3: /* random */
|
||||
val = ((rand() & 0x1ff) - 256);
|
||||
break;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
case 669: /* 669 vibrato */
|
||||
val = lfo->phase & 1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return val * lfo->depth;
|
||||
}
|
||||
|
||||
static int get_lfo_st3(struct lfo *lfo)
|
||||
{
|
||||
if (lfo->rate == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* S3M square */
|
||||
if (lfo->type == 2) {
|
||||
int val = lfo->phase < WAVEFORM_SIZE / 2 ? 255 : 0;
|
||||
return val * lfo->depth;
|
||||
}
|
||||
|
||||
return get_lfo_mod(lfo);
|
||||
}
|
||||
|
||||
/* From OpenMPT VibratoWaveforms.xm:
|
||||
* "Generally the vibrato and tremolo tables are identical to those that
|
||||
* ProTracker uses, but the vibrato’s “ramp down” table is upside down."
|
||||
*/
|
||||
static int get_lfo_ft2(struct lfo *lfo)
|
||||
{
|
||||
if (lfo->rate == 0)
|
||||
return 0;
|
||||
|
||||
/* FT2 ramp */
|
||||
if (lfo->type == 1) {
|
||||
int phase = (lfo->phase + (WAVEFORM_SIZE >> 1)) % WAVEFORM_SIZE;
|
||||
int val = (phase << 3) - 255;
|
||||
return val * lfo->depth;
|
||||
}
|
||||
|
||||
return get_lfo_mod(lfo);
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
|
||||
static int get_lfo_it(struct lfo *lfo)
|
||||
{
|
||||
if (lfo->rate == 0)
|
||||
return 0;
|
||||
|
||||
return get_lfo_st3(lfo);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int libxmp_lfo_get(struct context_data *ctx, struct lfo *lfo, int is_vibrato)
|
||||
{
|
||||
struct module_data *m = &ctx->m;
|
||||
|
||||
switch (m->read_event_type) {
|
||||
case READ_EVENT_ST3:
|
||||
return get_lfo_st3(lfo);
|
||||
case READ_EVENT_FT2:
|
||||
if (is_vibrato) {
|
||||
return get_lfo_ft2(lfo);
|
||||
} else {
|
||||
return get_lfo_mod(lfo);
|
||||
}
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
case READ_EVENT_IT:
|
||||
return get_lfo_it(lfo);
|
||||
#endif
|
||||
default:
|
||||
return get_lfo_mod(lfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void libxmp_lfo_update(struct lfo *lfo)
|
||||
{
|
||||
lfo->phase += lfo->rate;
|
||||
lfo->phase %= WAVEFORM_SIZE;
|
||||
}
|
||||
|
||||
void libxmp_lfo_set_phase(struct lfo *lfo, int phase)
|
||||
{
|
||||
lfo->phase = phase;
|
||||
}
|
||||
|
||||
void libxmp_lfo_set_depth(struct lfo *lfo, int depth)
|
||||
{
|
||||
lfo->depth = depth;
|
||||
}
|
||||
|
||||
void libxmp_lfo_set_rate(struct lfo *lfo, int rate)
|
||||
{
|
||||
lfo->rate = rate;
|
||||
}
|
||||
|
||||
void libxmp_lfo_set_waveform(struct lfo *lfo, int type)
|
||||
{
|
||||
lfo->type = type;
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef LIBXMP_LFO_H
|
||||
#define LIBXMP_LFO_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct lfo {
|
||||
int type;
|
||||
int rate;
|
||||
int depth;
|
||||
int phase;
|
||||
};
|
||||
|
||||
int libxmp_lfo_get(struct context_data *, struct lfo *, int);
|
||||
void libxmp_lfo_update(struct lfo *);
|
||||
void libxmp_lfo_set_phase(struct lfo *, int);
|
||||
void libxmp_lfo_set_depth(struct lfo *, int);
|
||||
void libxmp_lfo_set_rate(struct lfo *, int);
|
||||
void libxmp_lfo_set_waveform(struct lfo *, int);
|
||||
|
||||
#endif
|
|
@ -1,146 +0,0 @@
|
|||
#ifndef LIBXMP_LIST_H
|
||||
#define LIBXMP_LIST_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define __inline__ __inline
|
||||
#endif
|
||||
#ifdef __WATCOMC__
|
||||
#define __inline__ inline
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
#define INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static __inline__ void __list_add(struct list_head *_new,
|
||||
struct list_head * prev,
|
||||
struct list_head * next)
|
||||
{
|
||||
next->prev = _new;
|
||||
_new->next = next;
|
||||
_new->prev = prev;
|
||||
prev->next = _new;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @_new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static __inline__ void list_add(struct list_head *_new, struct list_head *head)
|
||||
{
|
||||
__list_add(_new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @_new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static __inline__ void list_add_tail(struct list_head *_new, struct list_head *head)
|
||||
{
|
||||
__list_add(_new, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static __inline__ void __list_del(struct list_head * prev,
|
||||
struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static __inline__ void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static __inline__ int list_empty(struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static __inline__ void list_splice(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
|
||||
if (first != list) {
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(size_t)(&((type *)0)->member)))
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
#endif
|
|
@ -1,695 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#ifdef __native_client__
|
||||
#include <sys/syslimits.h>
|
||||
#else
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
#include "format.h"
|
||||
#include "list.h"
|
||||
#include "hio.h"
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
#if !defined(HAVE_POPEN) && defined(WIN32)
|
||||
#include "win32/ptpopen.h"
|
||||
#define HAVE_POPEN 1
|
||||
#endif
|
||||
#if defined(__WATCOMC__)
|
||||
#define popen _popen
|
||||
#define pclose _pclose
|
||||
#define HAVE_POPEN 1
|
||||
#endif
|
||||
#include "md5.h"
|
||||
#include "extras.h"
|
||||
#endif
|
||||
|
||||
|
||||
extern const struct format_loader *const format_loader[];
|
||||
|
||||
void libxmp_load_prologue(struct context_data *);
|
||||
void libxmp_load_epilogue(struct context_data *);
|
||||
int libxmp_prepare_scan(struct context_data *);
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
|
||||
#include "depacker.h"
|
||||
|
||||
static struct depacker *depacker_list[] = {
|
||||
#if defined __AMIGA__ && !defined __AROS__
|
||||
&libxmp_depacker_xfd,
|
||||
#endif
|
||||
&libxmp_depacker_zip,
|
||||
&libxmp_depacker_lha,
|
||||
&libxmp_depacker_gzip,
|
||||
&libxmp_depacker_bzip2,
|
||||
&libxmp_depacker_xz,
|
||||
&libxmp_depacker_compress,
|
||||
&libxmp_depacker_pp,
|
||||
&libxmp_depacker_sqsh,
|
||||
&libxmp_depacker_arcfs,
|
||||
&libxmp_depacker_mmcmp,
|
||||
&libxmp_depacker_muse,
|
||||
&libxmp_depacker_lzx,
|
||||
&libxmp_depacker_s404,
|
||||
&libxmp_depacker_arc,
|
||||
NULL
|
||||
};
|
||||
|
||||
int test_oxm (FILE *);
|
||||
|
||||
#define BUFLEN 16384
|
||||
|
||||
#ifndef HAVE_POPEN
|
||||
static int execute_command(const char *cmd, const char *filename, FILE *t) {
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
static int execute_command(const char *cmd, const char *filename, FILE *t)
|
||||
{
|
||||
char line[1024], buf[BUFLEN];
|
||||
FILE *p;
|
||||
int n;
|
||||
|
||||
snprintf(line, 1024, cmd, filename);
|
||||
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__EMX__)
|
||||
/* Note: The _popen function returns an invalid file opaque, if
|
||||
* used in a Windows program, that will cause the program to hang
|
||||
* indefinitely. _popen works properly in a Console application.
|
||||
* To create a Windows application that redirects input and output,
|
||||
* read the section "Creating a Child Process with Redirected Input
|
||||
* and Output" in the Win32 SDK. -- Mirko
|
||||
*/
|
||||
p = popen(line, "rb");
|
||||
#else
|
||||
/* Linux popen fails with "rb" */
|
||||
p = popen(line, "r");
|
||||
#endif
|
||||
|
||||
if (p == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((n = fread(buf, 1, BUFLEN, p)) > 0) {
|
||||
fwrite(buf, 1, n, t);
|
||||
}
|
||||
|
||||
pclose (p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int decrunch(HIO_HANDLE **h, const char *filename, char **temp)
|
||||
{
|
||||
unsigned char b[1024];
|
||||
const char *cmd;
|
||||
FILE *f, *t;
|
||||
int res;
|
||||
int headersize;
|
||||
int i;
|
||||
struct depacker *depacker = NULL;
|
||||
|
||||
cmd = NULL;
|
||||
res = 0;
|
||||
*temp = NULL;
|
||||
f = (*h)->handle.file;
|
||||
|
||||
headersize = fread(b, 1, 1024, f);
|
||||
if (headersize < 100) { /* minimum valid file size */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check built-in depackers */
|
||||
for (i = 0; depacker_list[i] != NULL; i++) {
|
||||
if (depacker_list[i]->test(b)) {
|
||||
depacker = depacker_list[i];
|
||||
D_(D_INFO "Use depacker %d", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check external commands */
|
||||
if (depacker == NULL) {
|
||||
if (b[0] == 'M' && b[1] == 'O' && b[2] == '3') {
|
||||
/* MO3 */
|
||||
D_(D_INFO "mo3");
|
||||
cmd = "unmo3 -s \"%s\" STDOUT";
|
||||
} else if (memcmp(b, "Rar", 3) == 0) {
|
||||
/* rar */
|
||||
D_(D_INFO "rar");
|
||||
cmd = "unrar p -inul -xreadme -x*.diz -x*.nfo -x*.txt "
|
||||
"-x*.exe -x*.com \"%s\"";
|
||||
} else if (test_oxm(f) == 0) {
|
||||
/* oggmod */
|
||||
D_(D_INFO "oggmod");
|
||||
depacker = &libxmp_depacker_oxm;
|
||||
}
|
||||
}
|
||||
|
||||
if (fseek(f, 0, SEEK_SET) < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (depacker == NULL && cmd == NULL) {
|
||||
D_(D_INFO "Not packed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined __ANDROID__ || defined __native_client__
|
||||
/* Don't use external helpers in android */
|
||||
if (cmd) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
D_(D_WARN "Depacking file... ");
|
||||
|
||||
if ((t = make_temp_file(temp)) == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Depack file */
|
||||
if (cmd) {
|
||||
D_(D_INFO "External depacker: %s", cmd);
|
||||
if (execute_command(cmd, filename, t) < 0) {
|
||||
D_(D_CRIT "failed");
|
||||
goto err2;
|
||||
}
|
||||
} else if (depacker) {
|
||||
D_(D_INFO "Internal depacker");
|
||||
if (depacker->depack(f, t) < 0) {
|
||||
D_(D_CRIT "failed");
|
||||
goto err2;
|
||||
}
|
||||
}
|
||||
|
||||
D_(D_INFO "done");
|
||||
|
||||
if (fseek(t, 0, SEEK_SET) < 0) {
|
||||
D_(D_CRIT "fseek error");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
hio_close(*h);
|
||||
*h = hio_open_file(t);
|
||||
|
||||
return res;
|
||||
|
||||
err2:
|
||||
fclose(t);
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void set_md5sum(HIO_HANDLE *f, unsigned char *digest)
|
||||
{
|
||||
unsigned char buf[BUFLEN];
|
||||
MD5_CTX ctx;
|
||||
int bytes_read;
|
||||
|
||||
if (hio_size(f) <= 0) {
|
||||
memset(digest, 0, 16);
|
||||
return;
|
||||
}
|
||||
|
||||
hio_seek(f, 0, SEEK_SET);
|
||||
|
||||
MD5Init(&ctx);
|
||||
while ((bytes_read = hio_read(buf, 1, BUFLEN, f)) > 0) {
|
||||
MD5Update(&ctx, buf, bytes_read);
|
||||
}
|
||||
MD5Final(digest, &ctx);
|
||||
}
|
||||
|
||||
static char *get_dirname(char *name)
|
||||
{
|
||||
char *div, *dirname;
|
||||
int len;
|
||||
|
||||
if ((div = strrchr(name, '/'))) {
|
||||
len = div - name + 1;
|
||||
dirname = malloc(len + 1);
|
||||
if (dirname != NULL) {
|
||||
memcpy(dirname, name, len);
|
||||
dirname[len] = 0;
|
||||
}
|
||||
} else {
|
||||
dirname = strdup("");
|
||||
}
|
||||
|
||||
return dirname;
|
||||
}
|
||||
|
||||
static char *get_basename(char *name)
|
||||
{
|
||||
char *div, *basename;
|
||||
|
||||
if ((div = strrchr(name, '/'))) {
|
||||
basename = strdup(div + 1);
|
||||
} else {
|
||||
basename = strdup(name);
|
||||
}
|
||||
|
||||
return basename;
|
||||
}
|
||||
#endif /* LIBXMP_CORE_PLAYER */
|
||||
|
||||
#ifdef EDUKE32_DISABLED
|
||||
int xmp_test_module(char *path, struct xmp_test_info *info)
|
||||
{
|
||||
HIO_HANDLE *h;
|
||||
struct stat st;
|
||||
char buf[XMP_NAME_SIZE];
|
||||
int i;
|
||||
int ret = -XMP_ERROR_FORMAT;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
char *temp = NULL;
|
||||
#endif
|
||||
|
||||
if (stat(path, &st) < 0)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
errno = EISDIR;
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((h = hio_open(path, "rb")) == NULL)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (decrunch(&h, path, &temp) < 0) {
|
||||
ret = -XMP_ERROR_DEPACK;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* get size after decrunch */
|
||||
if (hio_size(h) < 256) { /* set minimum valid module size */
|
||||
ret = -XMP_ERROR_FORMAT;
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (info != NULL) {
|
||||
*info->name = 0; /* reset name prior to testing */
|
||||
*info->type = 0; /* reset type prior to testing */
|
||||
}
|
||||
|
||||
for (i = 0; format_loader[i] != NULL; i++) {
|
||||
hio_seek(h, 0, SEEK_SET);
|
||||
if (format_loader[i]->test(h, buf, 0) == 0) {
|
||||
int is_prowizard = 0;
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (strcmp(format_loader[i]->name, "prowizard") == 0) {
|
||||
hio_seek(h, 0, SEEK_SET);
|
||||
pw_test_format(h, buf, 0, info);
|
||||
is_prowizard = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
fclose(h->handle.file);
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
unlink_temp_file(temp);
|
||||
#endif
|
||||
|
||||
if (info != NULL && !is_prowizard) {
|
||||
strncpy(info->name, buf, XMP_NAME_SIZE - 1);
|
||||
strncpy(info->type, format_loader[i]->name,
|
||||
XMP_NAME_SIZE - 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
err:
|
||||
hio_close(h);
|
||||
unlink_temp_file(temp);
|
||||
#else
|
||||
hio_close(h);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int load_module(xmp_context opaque, HIO_HANDLE *h)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, j, ret;
|
||||
int test_result, load_result;
|
||||
|
||||
libxmp_load_prologue(ctx);
|
||||
|
||||
D_(D_WARN "load");
|
||||
test_result = load_result = -1;
|
||||
for (i = 0; format_loader[i] != NULL; i++) {
|
||||
hio_seek(h, 0, SEEK_SET);
|
||||
|
||||
if (hio_error(h)) {
|
||||
/* reset error flag */
|
||||
}
|
||||
|
||||
D_(D_WARN "test %s", format_loader[i]->name);
|
||||
test_result = format_loader[i]->test(h, NULL, 0);
|
||||
if (test_result == 0) {
|
||||
hio_seek(h, 0, SEEK_SET);
|
||||
D_(D_WARN "load format: %s", format_loader[i]->name);
|
||||
load_result = format_loader[i]->loader(m, h, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (test_result == 0 && load_result == 0)
|
||||
set_md5sum(h, m->md5);
|
||||
#endif
|
||||
|
||||
if (test_result < 0) {
|
||||
free(m->basename);
|
||||
free(m->dirname);
|
||||
return -XMP_ERROR_FORMAT;
|
||||
}
|
||||
|
||||
if (load_result < 0) {
|
||||
goto err_load;
|
||||
}
|
||||
|
||||
/* Sanity check: number of channels, module length */
|
||||
if (mod->chn > XMP_MAX_CHANNELS || mod->len > XMP_MAX_MOD_LENGTH) {
|
||||
goto err_load;
|
||||
}
|
||||
|
||||
/* Sanity check: channel pan */
|
||||
for (i = 0; i < mod->chn; i++) {
|
||||
if (mod->xxc[i].vol < 0 || mod->xxc[i].vol > 0xff) {
|
||||
goto err_load;
|
||||
}
|
||||
if (mod->xxc[i].pan < 0 || mod->xxc[i].pan > 0xff) {
|
||||
goto err_load;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sanity check: patterns */
|
||||
if (mod->xxp == NULL) {
|
||||
goto err_load;
|
||||
}
|
||||
for (i = 0; i < mod->pat; i++) {
|
||||
if (mod->xxp[i] == NULL) {
|
||||
goto err_load;
|
||||
}
|
||||
for (j = 0; j < mod->chn; j++) {
|
||||
int t = mod->xxp[i]->index[j];
|
||||
if (t < 0 || t >= mod->trk || mod->xxt[t] == NULL) {
|
||||
goto err_load;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libxmp_adjust_string(mod->name);
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
libxmp_adjust_string(mod->xxi[i].name);
|
||||
}
|
||||
for (i = 0; i < mod->smp; i++) {
|
||||
libxmp_adjust_string(mod->xxs[i].name);
|
||||
}
|
||||
|
||||
libxmp_load_epilogue(ctx);
|
||||
|
||||
ret = libxmp_prepare_scan(ctx);
|
||||
if (ret < 0) {
|
||||
xmp_release_module(opaque);
|
||||
return ret;
|
||||
}
|
||||
|
||||
libxmp_scan_sequences(ctx);
|
||||
|
||||
ctx->state = XMP_STATE_LOADED;
|
||||
|
||||
return 0;
|
||||
|
||||
err_load:
|
||||
xmp_release_module(opaque);
|
||||
return -XMP_ERROR_LOAD;
|
||||
}
|
||||
|
||||
#ifdef EDUKE32_DISABLED
|
||||
int xmp_load_module(xmp_context opaque, char *path)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
struct module_data *m = &ctx->m;
|
||||
long size;
|
||||
char *temp_name;
|
||||
#endif
|
||||
HIO_HANDLE *h;
|
||||
struct stat st;
|
||||
int ret;
|
||||
|
||||
D_(D_WARN "path = %s", path);
|
||||
|
||||
if (stat(path, &st) < 0) {
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
errno = EISDIR;
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((h = hio_open(path, "rb")) == NULL) {
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
D_(D_INFO "decrunch");
|
||||
if (decrunch(&h, path, &temp_name) < 0) {
|
||||
ret = -XMP_ERROR_DEPACK;
|
||||
goto err;
|
||||
}
|
||||
|
||||
size = hio_size(h);
|
||||
if (size < 256) { /* get size after decrunch */
|
||||
ret = -XMP_ERROR_FORMAT;
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ctx->state > XMP_STATE_UNLOADED)
|
||||
xmp_release_module(opaque);
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
m->dirname = get_dirname(path);
|
||||
if (m->dirname == NULL) {
|
||||
ret = -XMP_ERROR_SYSTEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
m->basename = get_basename(path);
|
||||
if (m->basename == NULL) {
|
||||
ret = -XMP_ERROR_SYSTEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
m->filename = path; /* For ALM, SSMT, etc */
|
||||
m->size = size;
|
||||
#endif
|
||||
|
||||
ret = load_module(opaque, h);
|
||||
hio_close(h);
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
unlink_temp_file(temp_name);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
err:
|
||||
hio_close(h);
|
||||
unlink_temp_file(temp_name);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int xmp_load_module_from_memory(xmp_context opaque, void *mem, long size)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct module_data *m = &ctx->m;
|
||||
HIO_HANDLE *h;
|
||||
int ret;
|
||||
|
||||
/* Use size < 0 for unknown/undetermined size */
|
||||
if (size == 0)
|
||||
size--;
|
||||
|
||||
if ((h = hio_open_mem(mem, size)) == NULL)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
|
||||
if (ctx->state > XMP_STATE_UNLOADED)
|
||||
xmp_release_module(opaque);
|
||||
|
||||
m->filename = NULL;
|
||||
m->basename = NULL;
|
||||
m->dirname = NULL;
|
||||
m->size = size;
|
||||
|
||||
ret = load_module(opaque, h);
|
||||
|
||||
hio_close(h);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef EDUKE32_DISABLED
|
||||
int xmp_load_module_from_file(xmp_context opaque, void *file, long size)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct module_data *m = &ctx->m;
|
||||
HIO_HANDLE *h;
|
||||
FILE *f = fdopen(fileno((FILE *)file), "rb");
|
||||
int ret;
|
||||
|
||||
if ((h = hio_open_file(f)) == NULL)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
|
||||
if (ctx->state > XMP_STATE_UNLOADED)
|
||||
xmp_release_module(opaque);
|
||||
|
||||
m->filename = NULL;
|
||||
m->basename = NULL;
|
||||
m->dirname = NULL;
|
||||
m->size = hio_size(h);
|
||||
|
||||
ret = load_module(opaque, h);
|
||||
|
||||
hio_close(h);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
void xmp_release_module(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i;
|
||||
|
||||
/* can't test this here, we must call release_module to clean up
|
||||
* load errors
|
||||
if (ctx->state < XMP_STATE_LOADED)
|
||||
return;
|
||||
*/
|
||||
|
||||
if (ctx->state > XMP_STATE_LOADED)
|
||||
xmp_end_player(opaque);
|
||||
|
||||
ctx->state = XMP_STATE_UNLOADED;
|
||||
|
||||
D_(D_INFO "Freeing memory");
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
libxmp_release_module_extras(ctx);
|
||||
#endif
|
||||
|
||||
if (mod->xxt != NULL) {
|
||||
for (i = 0; i < mod->trk; i++) {
|
||||
free(mod->xxt[i]);
|
||||
}
|
||||
free(mod->xxt);
|
||||
}
|
||||
|
||||
if (mod->xxp != NULL) {
|
||||
for (i = 0; i < mod->pat; i++) {
|
||||
free(mod->xxp[i]);
|
||||
}
|
||||
free(mod->xxp);
|
||||
}
|
||||
|
||||
if (mod->xxi != NULL) {
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
free(mod->xxi[i].sub);
|
||||
free(mod->xxi[i].extra);
|
||||
}
|
||||
free(mod->xxi);
|
||||
}
|
||||
|
||||
if (mod->xxs != NULL) {
|
||||
for (i = 0; i < mod->smp; i++) {
|
||||
if (mod->xxs[i].data != NULL) {
|
||||
free(mod->xxs[i].data - 4);
|
||||
}
|
||||
}
|
||||
free(mod->xxs);
|
||||
free(m->xtra);
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
if (m->xsmp != NULL) {
|
||||
for (i = 0; i < mod->smp; i++) {
|
||||
if (m->xsmp[i].data != NULL) {
|
||||
free(m->xsmp[i].data - 4);
|
||||
}
|
||||
}
|
||||
free(m->xsmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m->scan_cnt) {
|
||||
for (i = 0; i < mod->len; i++)
|
||||
free(m->scan_cnt[i]);
|
||||
free(m->scan_cnt);
|
||||
}
|
||||
|
||||
free(m->comment);
|
||||
|
||||
D_("free dirname/basename");
|
||||
free(m->dirname);
|
||||
free(m->basename);
|
||||
}
|
||||
|
||||
void xmp_scan_module(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
|
||||
if (ctx->state < XMP_STATE_LOADED)
|
||||
return;
|
||||
|
||||
libxmp_scan_sequences(ctx);
|
||||
}
|
|
@ -1,425 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "common.h"
|
||||
#include "loader.h"
|
||||
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <fnmatch.h>
|
||||
|
||||
/*
|
||||
* Handle special "module quirks" that can't be detected automatically
|
||||
* such as Protracker 2.x compatibility, vblank timing, etc.
|
||||
*/
|
||||
|
||||
struct module_quirk {
|
||||
uint8 md5[16];
|
||||
int flags;
|
||||
int mode;
|
||||
};
|
||||
|
||||
const struct module_quirk mq[] = {
|
||||
/* "No Mercy" by Alf/VTL (added by Martin Willers) */
|
||||
{
|
||||
{ 0x36, 0x6e, 0xc0, 0xfa, 0x96, 0x2a, 0xeb, 0xee,
|
||||
0x03, 0x4a, 0xa2, 0xdb, 0xaa, 0x49, 0xaa, 0xea },
|
||||
0, XMP_MODE_PROTRACKER
|
||||
},
|
||||
|
||||
/* mod.souvenir of china */
|
||||
{
|
||||
{ 0x93, 0xf1, 0x46, 0xae, 0xb7, 0x58, 0xc3, 0x9d,
|
||||
0x8b, 0x5f, 0xbc, 0x98, 0xbf, 0x23, 0x7a, 0x43 },
|
||||
XMP_FLAGS_FIXLOOP, XMP_MODE_AUTO
|
||||
},
|
||||
|
||||
/* "siedler ii" (added by Daniel Åkerud) */
|
||||
{
|
||||
{ 0x70, 0xaa, 0x03, 0x4d, 0xfb, 0x2f, 0x1f, 0x73,
|
||||
0xd9, 0xfd, 0xba, 0xfe, 0x13, 0x1b, 0xb7, 0x01 },
|
||||
XMP_FLAGS_VBLANK, XMP_MODE_AUTO
|
||||
},
|
||||
|
||||
/* "Klisje paa klisje" (added by Kjetil Torgrim Homme) */
|
||||
{
|
||||
{ 0xe9, 0x98, 0x01, 0x2c, 0x70, 0x0e, 0xb4, 0x3a,
|
||||
0xf0, 0x32, 0x17, 0x11, 0x30, 0x58, 0x29, 0xb2 },
|
||||
0, XMP_MODE_NOISETRACKER
|
||||
},
|
||||
|
||||
#if 0
|
||||
/* -- Already covered by Noisetracker fingerprinting -- */
|
||||
|
||||
/* Another version of Klisje paa klisje sent by Steve Fernandez */
|
||||
{
|
||||
{ 0x12, 0x19, 0x1c, 0x90, 0x41, 0xe3, 0xfd, 0x70,
|
||||
0xb7, 0xe6, 0xb3, 0x94, 0x8b, 0x21, 0x07, 0x63 },
|
||||
XMP_FLAGS_VBLANK
|
||||
},
|
||||
#endif
|
||||
|
||||
/* "((((( nebulos )))))" sent by Tero Auvinen (AMP version) */
|
||||
{
|
||||
{ 0x51, 0x6e, 0x8d, 0xcc, 0x35, 0x7d, 0x50, 0xde,
|
||||
0xa9, 0x85, 0xbe, 0xbf, 0x90, 0x2e, 0x42, 0xdc },
|
||||
0, XMP_MODE_NOISETRACKER
|
||||
},
|
||||
|
||||
/* Purple Motion's Sundance.mod, Music Channel BBS edit */
|
||||
{
|
||||
{ 0x5d, 0x3e, 0x1e, 0x08, 0x28, 0x52, 0x12, 0xc7,
|
||||
0x17, 0x64, 0x95, 0x75, 0x98, 0xe6, 0x95, 0xc1 },
|
||||
0, XMP_MODE_ST3
|
||||
},
|
||||
|
||||
/* Asle's Ode to Protracker */
|
||||
{
|
||||
{ 0x97, 0xa3, 0x7d, 0x30, 0xd7, 0xae, 0x6d, 0x50,
|
||||
0xc9, 0x62, 0xe9, 0xd8, 0x87, 0x1b, 0x7e, 0x8a },
|
||||
0, XMP_MODE_PROTRACKER
|
||||
},
|
||||
|
||||
{
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
0, 0
|
||||
}
|
||||
};
|
||||
|
||||
static void module_quirks(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
int i;
|
||||
|
||||
for (i = 0; mq[i].flags != 0 || mq[i].mode != 0; i++) {
|
||||
if (!memcmp(m->md5, mq[i].md5, 16)) {
|
||||
p->flags |= mq[i].flags;
|
||||
p->mode = mq[i].mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the given string matches one of the blacklisted glob
|
||||
* patterns. Used to filter file names stored in archive files.
|
||||
*/
|
||||
int libxmp_exclude_match(const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
static const char *const exclude[] = {
|
||||
"README", "readme",
|
||||
"*.DIZ", "*.diz",
|
||||
"*.NFO", "*.nfo",
|
||||
"*.DOC", "*.Doc", "*.doc",
|
||||
"*.INFO", "*.info", "*.Info",
|
||||
"*.TXT", "*.txt",
|
||||
"*.EXE", "*.exe",
|
||||
"*.COM", "*.com",
|
||||
"*.README", "*.readme", "*.Readme", "*.ReadMe",
|
||||
NULL
|
||||
};
|
||||
|
||||
for (i = 0; exclude[i] != NULL; i++) {
|
||||
if (fnmatch(exclude[i], name, 0) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* LIBXMP_CORE_PLAYER */
|
||||
|
||||
char *libxmp_adjust_string(char *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < strlen(s); i++) {
|
||||
if (!isprint((int)s[i]) || ((uint8) s[i] > 127))
|
||||
s[i] = ' ';
|
||||
}
|
||||
|
||||
while (*s && (s[strlen(s) - 1] == ' ')) {
|
||||
s[strlen(s) - 1] = 0;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static void check_envelope(struct xmp_envelope *env)
|
||||
{
|
||||
/* Disable envelope if invalid number of points */
|
||||
if (env->npt <= 0 || env->npt > XMP_MAX_ENV_POINTS) {
|
||||
env->flg &= ~XMP_ENVELOPE_ON;
|
||||
}
|
||||
|
||||
/* Disable envelope loop if invalid loop parameters */
|
||||
if (env->lps >= env->npt || env->lpe >= env->npt) {
|
||||
env->flg &= ~XMP_ENVELOPE_LOOP;
|
||||
}
|
||||
|
||||
/* Disable envelope loop if invalid sustain */
|
||||
if (env->sus >= env->npt) {
|
||||
env->flg &= ~XMP_ENVELOPE_ON;
|
||||
}
|
||||
}
|
||||
|
||||
void libxmp_load_prologue(struct context_data *ctx)
|
||||
{
|
||||
struct module_data *m = &ctx->m;
|
||||
int i;
|
||||
|
||||
/* Reset variables */
|
||||
memset(&m->mod, 0, sizeof (struct xmp_module));
|
||||
m->rrate = PAL_RATE;
|
||||
m->c4rate = C4_PAL_RATE;
|
||||
m->volbase = 0x40;
|
||||
m->gvol = m->gvolbase = 0x40;
|
||||
m->vol_table = NULL;
|
||||
m->quirk = 0;
|
||||
m->read_event_type = READ_EVENT_MOD;
|
||||
m->period_type = PERIOD_AMIGA;
|
||||
m->comment = NULL;
|
||||
m->scan_cnt = NULL;
|
||||
|
||||
/* Set defaults */
|
||||
m->mod.pat = 0;
|
||||
m->mod.trk = 0;
|
||||
m->mod.chn = 4;
|
||||
m->mod.ins = 0;
|
||||
m->mod.smp = 0;
|
||||
m->mod.spd = 6;
|
||||
m->mod.bpm = 125;
|
||||
m->mod.len = 0;
|
||||
m->mod.rst = 0;
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
m->extra = NULL;
|
||||
#endif
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
m->xsmp = NULL;
|
||||
#endif
|
||||
|
||||
m->time_factor = DEFAULT_TIME_FACTOR;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
int pan = (((i + 1) / 2) % 2) * 0xff;
|
||||
m->mod.xxc[i].pan = 0x80 + (pan - 0x80) * m->defpan / 100;
|
||||
m->mod.xxc[i].vol = 0x40;
|
||||
m->mod.xxc[i].flg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void libxmp_load_epilogue(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, j;
|
||||
|
||||
mod->gvl = m->gvol;
|
||||
|
||||
/* Sanity check for module parameters */
|
||||
CLAMP(mod->len, 0, XMP_MAX_MOD_LENGTH);
|
||||
CLAMP(mod->pat, 0, 257); /* some formats have an extra pattern */
|
||||
CLAMP(mod->ins, 0, 255);
|
||||
CLAMP(mod->smp, 0, MAX_SAMPLES);
|
||||
CLAMP(mod->chn, 0, XMP_MAX_CHANNELS);
|
||||
|
||||
/* Fix cases where the restart value is invalid e.g. kc_fall8.xm
|
||||
* from http://aminet.net/mods/mvp/mvp_0002.lha (reported by
|
||||
* Ralf Hoffmann <ralf@boomerangsworld.de>)
|
||||
*/
|
||||
if (mod->rst >= mod->len) {
|
||||
mod->rst = 0;
|
||||
}
|
||||
|
||||
/* Sanity check for tempo and BPM */
|
||||
if (mod->spd <= 0 || mod->spd > 255) {
|
||||
mod->spd = 6;
|
||||
}
|
||||
CLAMP(mod->bpm, XMP_MIN_BPM, 255);
|
||||
|
||||
/* Set appropriate values for instrument volumes and subinstrument
|
||||
* global volumes when QUIRK_INSVOL is not set, to keep volume values
|
||||
* consistent if the user inspects struct xmp_module. We can later
|
||||
* set volumes in the loaders and eliminate the quirk.
|
||||
*/
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
if (~m->quirk & QUIRK_INSVOL) {
|
||||
mod->xxi[i].vol = m->volbase;
|
||||
}
|
||||
for (j = 0; j < mod->xxi[i].nsm; j++) {
|
||||
if (~m->quirk & QUIRK_INSVOL) {
|
||||
mod->xxi[i].sub[j].gvl = m->volbase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sanity check for envelopes
|
||||
*/
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
check_envelope(&mod->xxi[i].aei);
|
||||
check_envelope(&mod->xxi[i].fei);
|
||||
check_envelope(&mod->xxi[i].pei);
|
||||
}
|
||||
|
||||
p->filter = 0;
|
||||
p->mode = XMP_MODE_AUTO;
|
||||
p->flags = p->player_flags;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
module_quirks(ctx);
|
||||
#endif
|
||||
libxmp_set_player_mode(ctx);
|
||||
}
|
||||
|
||||
int libxmp_prepare_scan(struct context_data *ctx)
|
||||
{
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, ord;
|
||||
|
||||
if (mod->xxp == NULL || mod->xxt == NULL)
|
||||
return -XMP_ERROR_LOAD;
|
||||
ord = 0;
|
||||
while (ord < mod->len && mod->xxo[ord] >= mod->pat) {
|
||||
ord++;
|
||||
}
|
||||
|
||||
if (ord >= mod->len) {
|
||||
mod->len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
m->scan_cnt = (char **)calloc(sizeof (char *), mod->len);
|
||||
if (m->scan_cnt == NULL)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
|
||||
for (i = 0; i < mod->len; i++) {
|
||||
int pat_idx = mod->xxo[i];
|
||||
struct xmp_pattern *pat;
|
||||
|
||||
/* Add pattern if referenced in orders */
|
||||
if (pat_idx < mod->pat && !mod->xxp[pat_idx]) {
|
||||
if (libxmp_alloc_pattern(mod, pat_idx) < 0) {
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
}
|
||||
}
|
||||
|
||||
pat = pat_idx >= mod->pat ? NULL : mod->xxp[pat_idx];
|
||||
m->scan_cnt[i] = (char *)calloc(1, pat && pat->rows ? pat->rows : 1);
|
||||
if (m->scan_cnt[i] == NULL)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Process player personality flags */
|
||||
int libxmp_set_player_mode(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
int q;
|
||||
|
||||
switch (p->mode) {
|
||||
case XMP_MODE_AUTO:
|
||||
break;
|
||||
case XMP_MODE_MOD:
|
||||
m->c4rate = C4_PAL_RATE;
|
||||
m->quirk = 0;
|
||||
m->read_event_type = READ_EVENT_MOD;
|
||||
m->period_type = PERIOD_AMIGA;
|
||||
break;
|
||||
case XMP_MODE_NOISETRACKER:
|
||||
m->c4rate = C4_PAL_RATE;
|
||||
m->quirk = QUIRK_NOBPM;
|
||||
m->read_event_type = READ_EVENT_MOD;
|
||||
m->period_type = PERIOD_MODRNG;
|
||||
break;
|
||||
case XMP_MODE_PROTRACKER:
|
||||
m->c4rate = C4_PAL_RATE;
|
||||
m->quirk = QUIRK_PROTRACK;
|
||||
m->read_event_type = READ_EVENT_MOD;
|
||||
m->period_type = PERIOD_MODRNG;
|
||||
break;
|
||||
case XMP_MODE_S3M:
|
||||
q = m->quirk & (QUIRK_VSALL | QUIRK_ARPMEM);
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->quirk = QUIRKS_ST3 | q;
|
||||
m->read_event_type = READ_EVENT_ST3;
|
||||
break;
|
||||
case XMP_MODE_ST3:
|
||||
q = m->quirk & (QUIRK_VSALL | QUIRK_ARPMEM);
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->quirk = QUIRKS_ST3 | QUIRK_ST3BUGS | q;
|
||||
m->read_event_type = READ_EVENT_ST3;
|
||||
break;
|
||||
case XMP_MODE_ST3GUS:
|
||||
q = m->quirk & (QUIRK_VSALL | QUIRK_ARPMEM);
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->quirk = QUIRKS_ST3 | QUIRK_ST3BUGS | q;
|
||||
m->quirk &= ~QUIRK_RSTCHN;
|
||||
m->read_event_type = READ_EVENT_ST3;
|
||||
break;
|
||||
case XMP_MODE_XM:
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->quirk = QUIRKS_FT2;
|
||||
m->read_event_type = READ_EVENT_FT2;
|
||||
break;
|
||||
case XMP_MODE_FT2:
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->quirk = QUIRKS_FT2 | QUIRK_FT2BUGS;
|
||||
m->read_event_type = READ_EVENT_FT2;
|
||||
break;
|
||||
case XMP_MODE_IT:
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->quirk = QUIRKS_IT | QUIRK_VIBHALF | QUIRK_VIBINV;
|
||||
m->read_event_type = READ_EVENT_IT;
|
||||
break;
|
||||
case XMP_MODE_ITSMP:
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->quirk = QUIRKS_IT | QUIRK_VIBHALF | QUIRK_VIBINV;
|
||||
m->quirk &= ~(QUIRK_VIRTUAL | QUIRK_RSTCHN);
|
||||
m->read_event_type = READ_EVENT_IT;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
#ifndef XMP_LOADER_H
|
||||
#define XMP_LOADER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
#include "effects.h"
|
||||
#include "format.h"
|
||||
#include "hio.h"
|
||||
|
||||
/* Sample flags */
|
||||
#define SAMPLE_FLAG_DIFF 0x0001 /* Differential */
|
||||
#define SAMPLE_FLAG_UNS 0x0002 /* Unsigned */
|
||||
#define SAMPLE_FLAG_8BDIFF 0x0004
|
||||
#define SAMPLE_FLAG_7BIT 0x0008
|
||||
#define SAMPLE_FLAG_NOLOAD 0x0010 /* Get from buffer, don't load */
|
||||
#define SAMPLE_FLAG_BIGEND 0x0040 /* Big-endian */
|
||||
#define SAMPLE_FLAG_VIDC 0x0080 /* Archimedes VIDC logarithmic */
|
||||
/*#define SAMPLE_FLAG_STEREO 0x0100 Interleaved stereo sample */
|
||||
#define SAMPLE_FLAG_FULLREP 0x0200 /* Play full sample before looping */
|
||||
#define SAMPLE_FLAG_ADLIB 0x1000 /* Adlib synth instrument */
|
||||
#define SAMPLE_FLAG_HSC 0x2000 /* HSC Adlib synth instrument */
|
||||
#define SAMPLE_FLAG_ADPCM 0x4000 /* ADPCM4 encoded samples */
|
||||
|
||||
#define DEFPAN(x) (0x80 + ((x) - 0x80) * m->defpan / 100)
|
||||
|
||||
int libxmp_init_instrument (struct module_data *);
|
||||
int libxmp_alloc_subinstrument (struct xmp_module *, int, int);
|
||||
int libxmp_init_pattern (struct xmp_module *);
|
||||
int libxmp_alloc_pattern (struct xmp_module *, int);
|
||||
int libxmp_alloc_track (struct xmp_module *, int, int);
|
||||
int libxmp_alloc_tracks_in_pattern (struct xmp_module *, int);
|
||||
int libxmp_alloc_pattern_tracks (struct xmp_module *, int, int);
|
||||
char *libxmp_instrument_name (struct xmp_module *, int, uint8 *, int);
|
||||
struct xmp_sample* libxmp_realloc_samples(struct xmp_sample *, int *, int);
|
||||
|
||||
char *libxmp_copy_adjust (char *, uint8 *, int);
|
||||
int libxmp_test_name (uint8 *, int);
|
||||
void libxmp_read_title (HIO_HANDLE *, char *, int);
|
||||
void libxmp_set_xxh_defaults (struct xmp_module *);
|
||||
void libxmp_decode_protracker_event (struct xmp_event *, uint8 *);
|
||||
void libxmp_decode_noisetracker_event(struct xmp_event *, uint8 *);
|
||||
void libxmp_disable_continue_fx (struct xmp_event *);
|
||||
int libxmp_check_filename_case (char *, char *, char *, int);
|
||||
void libxmp_get_instrument_path (struct module_data *, char *, int);
|
||||
void libxmp_set_type (struct module_data *, const char *, ...);
|
||||
int libxmp_load_sample (struct module_data *, HIO_HANDLE *, int,
|
||||
struct xmp_sample *, const void *);
|
||||
|
||||
extern uint8 libxmp_ord_xlat[];
|
||||
extern const int libxmp_arch_vol_table[];
|
||||
|
||||
#define MAGIC4(a,b,c,d) \
|
||||
(((uint32)(a)<<24)|((uint32)(b)<<16)|((uint32)(c)<<8)|(d))
|
||||
|
||||
#define LOAD_INIT()
|
||||
|
||||
#define MODULE_INFO() do { \
|
||||
D_(D_WARN "Module title: \"%s\"", m->mod.name); \
|
||||
D_(D_WARN "Module type: %s", m->mod.type); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
|
@ -1,105 +0,0 @@
|
|||
#ifndef LIBXMP_MDATAIO_H
|
||||
#define LIBXMP_MDATAIO_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "common.h"
|
||||
|
||||
static inline ptrdiff_t CAN_READ(MFILE *m)
|
||||
{
|
||||
if (m->size >= 0)
|
||||
return m->pos >= 0 ? m->size - m->pos : 0;
|
||||
|
||||
return INT_MAX;
|
||||
}
|
||||
|
||||
static inline uint8 mread8(MFILE *m)
|
||||
{
|
||||
uint8 x = 0xff;
|
||||
mread(&x, 1, 1, m);
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline int8 mread8s(MFILE *m)
|
||||
{
|
||||
return (int8)mgetc(m);
|
||||
}
|
||||
|
||||
static inline uint16 mread16l(MFILE *m)
|
||||
{
|
||||
ptrdiff_t can_read = CAN_READ(m);
|
||||
if (can_read >= 2) {
|
||||
uint16 n = readmem16l(m->start + m->pos);
|
||||
m->pos += 2;
|
||||
return n;
|
||||
} else {
|
||||
m->pos += can_read;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint16 mread16b(MFILE *m)
|
||||
{
|
||||
ptrdiff_t can_read = CAN_READ(m);
|
||||
if (can_read >= 2) {
|
||||
uint16 n = readmem16b(m->start + m->pos);
|
||||
m->pos += 2;
|
||||
return n;
|
||||
} else {
|
||||
m->pos += can_read;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32 mread24l(MFILE *m)
|
||||
{
|
||||
ptrdiff_t can_read = CAN_READ(m);
|
||||
if (can_read >= 3) {
|
||||
uint32 n = readmem24l(m->start + m->pos);
|
||||
m->pos += 3;
|
||||
return n;
|
||||
} else {
|
||||
m->pos += can_read;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32 mread24b(MFILE *m)
|
||||
{
|
||||
ptrdiff_t can_read = CAN_READ(m);
|
||||
if (can_read >= 3) {
|
||||
uint32 n = readmem24b(m->start + m->pos);
|
||||
m->pos += 3;
|
||||
return n;
|
||||
} else {
|
||||
m->pos += can_read;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32 mread32l(MFILE *m)
|
||||
{
|
||||
ptrdiff_t can_read = CAN_READ(m);
|
||||
if (can_read >= 4) {
|
||||
uint32 n = readmem32l(m->start + m->pos);
|
||||
m->pos += 4;
|
||||
return n;
|
||||
} else {
|
||||
m->pos += can_read;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32 mread32b(MFILE *m)
|
||||
{
|
||||
ptrdiff_t can_read = CAN_READ(m);
|
||||
if (can_read >= 4) {
|
||||
uint32 n = readmem32b(m->start + m->pos);
|
||||
m->pos += 4;
|
||||
return n;
|
||||
} else {
|
||||
m->pos += can_read;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,136 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include "common.h"
|
||||
#include "memio.h"
|
||||
|
||||
static inline ptrdiff_t CAN_READ(MFILE *m)
|
||||
{
|
||||
if (m->size >= 0)
|
||||
return m->pos >= 0 ? m->size - m->pos : 0;
|
||||
|
||||
return INT_MAX;
|
||||
}
|
||||
|
||||
|
||||
int mgetc(MFILE *m)
|
||||
{
|
||||
if (CAN_READ(m) >= 1)
|
||||
return *(const uint8 *)(m->start + m->pos++);
|
||||
else
|
||||
return EOF;
|
||||
}
|
||||
|
||||
size_t mread(void *buf, size_t size, size_t num, MFILE *m)
|
||||
{
|
||||
size_t should_read = size * num;
|
||||
ptrdiff_t can_read = CAN_READ(m);
|
||||
|
||||
if (!size || !num || can_read <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (should_read > can_read) {
|
||||
should_read = can_read;
|
||||
}
|
||||
|
||||
memcpy(buf, m->start + m->pos, should_read);
|
||||
m->pos += should_read;
|
||||
|
||||
return should_read / size;
|
||||
}
|
||||
|
||||
|
||||
int mseek(MFILE *m, long offset, int whence)
|
||||
{
|
||||
switch (whence) {
|
||||
default:
|
||||
case SEEK_SET:
|
||||
if (m->size >= 0 && (offset > m->size || offset < 0))
|
||||
return -1;
|
||||
m->pos = offset;
|
||||
return 0;
|
||||
case SEEK_CUR:
|
||||
if (m->size >= 0 && (offset > CAN_READ(m) || offset < -m->pos))
|
||||
return -1;
|
||||
m->pos += offset;
|
||||
return 0;
|
||||
case SEEK_END:
|
||||
if (m->size < 0)
|
||||
return -1;
|
||||
m->pos = m->size + offset;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
long mtell(MFILE *m)
|
||||
{
|
||||
return (long)m->pos;
|
||||
}
|
||||
|
||||
int meof(MFILE *m)
|
||||
{
|
||||
if (m->size <= 0)
|
||||
return 0;
|
||||
else
|
||||
return CAN_READ(m) <= 0;
|
||||
}
|
||||
|
||||
MFILE *mopen(const void *ptr, long size)
|
||||
{
|
||||
MFILE *m;
|
||||
|
||||
m = (MFILE *)malloc(sizeof (MFILE));
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
|
||||
m->start = (const unsigned char *)ptr;
|
||||
m->pos = 0;
|
||||
m->size = size;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
int mclose(MFILE *m)
|
||||
{
|
||||
free(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
|
||||
int mstat(MFILE *m, struct stat *st)
|
||||
{
|
||||
memset(st, 0, sizeof (struct stat));
|
||||
st->st_size = m->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
#ifndef LIBXMP_MEMIO_H
|
||||
#define LIBXMP_MEMIO_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
const unsigned char *start;
|
||||
ptrdiff_t pos;
|
||||
ptrdiff_t size;
|
||||
} MFILE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
MFILE *mopen(const void *, long);
|
||||
int mgetc(MFILE *stream);
|
||||
size_t mread(void *, size_t, size_t, MFILE *);
|
||||
int mseek(MFILE *, long, int);
|
||||
long mtell(MFILE *);
|
||||
int mclose(MFILE *);
|
||||
int meof(MFILE *);
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
int mstat(MFILE *, struct stat *);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,439 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "virtual.h"
|
||||
#include "mixer.h"
|
||||
#include "precomp_lut.h"
|
||||
|
||||
/* Mixers
|
||||
*
|
||||
* To increase performance eight mixers are defined, one for each
|
||||
* combination of the following parameters: interpolation, resolution
|
||||
* and number of channels.
|
||||
*/
|
||||
#define NEAREST_NEIGHBOR() do { \
|
||||
smp_in = ((int16)sptr[pos] << 8); \
|
||||
} while (0)
|
||||
|
||||
#define NEAREST_NEIGHBOR_16BIT() do { \
|
||||
smp_in = sptr[pos]; \
|
||||
} while (0)
|
||||
|
||||
#define LINEAR_INTERP() do { \
|
||||
smp_l1 = ((int16)sptr[pos] << 8); \
|
||||
smp_dt = ((int16)sptr[pos + 1] << 8) - smp_l1; \
|
||||
smp_in = smp_l1 + (((frac >> 1) * smp_dt) >> (SMIX_SHIFT - 1)); \
|
||||
} while (0)
|
||||
|
||||
#define LINEAR_INTERP_16BIT() do { \
|
||||
smp_l1 = sptr[pos]; \
|
||||
smp_dt = sptr[pos + 1] - smp_l1; \
|
||||
smp_in = smp_l1 + (((frac >> 1) * smp_dt) >> (SMIX_SHIFT - 1)); \
|
||||
} while (0)
|
||||
|
||||
/* The following lut settings are PRECOMPUTED. If you plan on changing these
|
||||
* settings, you MUST also regenerate the arrays.
|
||||
*/
|
||||
/* number of bits used to scale spline coefs */
|
||||
#define SPLINE_QUANTBITS 14
|
||||
#define SPLINE_SHIFT (SPLINE_QUANTBITS)
|
||||
|
||||
/* log2(number) of precalculated splines (range is [4..14]) */
|
||||
#define SPLINE_FRACBITS 10
|
||||
#define SPLINE_LUTLEN (1L<<SPLINE_FRACBITS)
|
||||
|
||||
#define SPLINE_FRACSHIFT ((16 - SPLINE_FRACBITS) - 2)
|
||||
#define SPLINE_FRACMASK (((1L << (16 - SPLINE_FRACSHIFT)) - 1) & ~3)
|
||||
|
||||
#define SPLINE_INTERP() do { \
|
||||
int f = frac >> 6; \
|
||||
smp_in = (cubic_spline_lut0[f] * sptr[(int)pos - 1] + \
|
||||
cubic_spline_lut1[f] * sptr[pos ] + \
|
||||
cubic_spline_lut3[f] * sptr[pos + 2] + \
|
||||
cubic_spline_lut2[f] * sptr[pos + 1]) >> (SPLINE_SHIFT - 8); \
|
||||
} while (0)
|
||||
|
||||
#define SPLINE_INTERP_16BIT() do { \
|
||||
int f = frac >> 6; \
|
||||
smp_in = (cubic_spline_lut0[f] * sptr[(int)pos - 1] + \
|
||||
cubic_spline_lut1[f] * sptr[pos ] + \
|
||||
cubic_spline_lut3[f] * sptr[pos + 2] + \
|
||||
cubic_spline_lut2[f] * sptr[pos + 1]) >> SPLINE_SHIFT; \
|
||||
} while (0)
|
||||
|
||||
#define LOOP_AC for (; count > ramp; count--)
|
||||
|
||||
#define LOOP for (; count; count--)
|
||||
|
||||
#define UPDATE_POS() do { \
|
||||
frac += step; \
|
||||
pos += frac >> SMIX_SHIFT; \
|
||||
frac &= SMIX_MASK; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_MONO() do { \
|
||||
*(buffer++) += smp_in * vl; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_MONO_AC() do { \
|
||||
*(buffer++) += smp_in * (old_vl >> 8); old_vl += delta_l; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_MONO_FILTER() do { \
|
||||
sl = (a0 * smp_in * vl + b0 * fl1 + b1 * fl2) >> FILTER_SHIFT; \
|
||||
fl2 = fl1; fl1 = sl; \
|
||||
*(buffer++) += sl; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_MONO_FILTER_AC() do { \
|
||||
int vl = old_vl >> 8; \
|
||||
MIX_MONO_FILTER(); \
|
||||
old_vl += delta_l; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_STEREO() do { \
|
||||
*(buffer++) += smp_in * vr; \
|
||||
*(buffer++) += smp_in * vl; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_STEREO_AC() do { \
|
||||
*(buffer++) += smp_in * (old_vr >> 8); old_vr += delta_r; \
|
||||
*(buffer++) += smp_in * (old_vl >> 8); old_vl += delta_l; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_STEREO_FILTER() do { \
|
||||
sr = (a0 * smp_in * vr + b0 * fr1 + b1 * fr2) >> FILTER_SHIFT; \
|
||||
fr2 = fr1; fr1 = sr; \
|
||||
sl = (a0 * smp_in * vl + b0 * fl1 + b1 * fl2) >> FILTER_SHIFT; \
|
||||
fl2 = fl1; fl1 = sl; \
|
||||
*(buffer++) += sr; \
|
||||
*(buffer++) += sl; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_STEREO_FILTER_AC() do { \
|
||||
int vr = old_vr >> 8; \
|
||||
int vl = old_vl >> 8; \
|
||||
MIX_STEREO_FILTER(); \
|
||||
old_vr += delta_r; \
|
||||
old_vl += delta_l; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_STEREO_FILTER_AC() do { \
|
||||
int vr = old_vr >> 8; \
|
||||
int vl = old_vl >> 8; \
|
||||
MIX_STEREO_FILTER(); \
|
||||
old_vr += delta_r; \
|
||||
old_vl += delta_l; \
|
||||
} while (0)
|
||||
|
||||
#define VAR_NORM(x) \
|
||||
int smp_in; \
|
||||
x *sptr = (x *)vi->sptr; \
|
||||
unsigned int pos = (unsigned int)vi->pos; \
|
||||
int frac = (int)((1 << SMIX_SHIFT) * (vi->pos - (int)vi->pos))
|
||||
|
||||
#define VAR_LINEAR_MONO(x) \
|
||||
VAR_NORM(x); \
|
||||
int old_vl = vi->old_vl; \
|
||||
int smp_l1, smp_dt
|
||||
|
||||
#define VAR_LINEAR_STEREO(x) \
|
||||
VAR_LINEAR_MONO(x); \
|
||||
int old_vr = vi->old_vr
|
||||
|
||||
#define VAR_SPLINE_MONO(x) \
|
||||
int old_vl = vi->old_vl; \
|
||||
VAR_NORM(x)
|
||||
|
||||
#define VAR_SPLINE_STEREO(x) \
|
||||
VAR_SPLINE_MONO(x); \
|
||||
int old_vr = vi->old_vr
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
|
||||
#define VAR_FILTER_MONO \
|
||||
int fl1 = vi->filter.l1, fl2 = vi->filter.l2; \
|
||||
int64 a0 = vi->filter.a0, b0 = vi->filter.b0, b1 = vi->filter.b1; \
|
||||
int sl
|
||||
|
||||
#define VAR_FILTER_STEREO \
|
||||
VAR_FILTER_MONO; \
|
||||
int fr1 = vi->filter.r1, fr2 = vi->filter.r2; \
|
||||
int sr
|
||||
|
||||
#define SAVE_FILTER_MONO() do { \
|
||||
vi->filter.l1 = fl1; \
|
||||
vi->filter.l2 = fl2; \
|
||||
} while (0)
|
||||
|
||||
#define SAVE_FILTER_STEREO() do { \
|
||||
SAVE_FILTER_MONO(); \
|
||||
vi->filter.r1 = fr1; \
|
||||
vi->filter.r2 = fr2; \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Nearest neighbor mixers
|
||||
*/
|
||||
|
||||
/* Handler for 8 bit samples, nearest neighbor mono output
|
||||
*/
|
||||
MIXER(mono_8bit_nearest)
|
||||
{
|
||||
VAR_NORM(int8);
|
||||
|
||||
LOOP { NEAREST_NEIGHBOR(); MIX_MONO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
|
||||
/* Handler for 16 bit samples, nearest neighbor mono output
|
||||
*/
|
||||
MIXER(mono_16bit_nearest)
|
||||
{
|
||||
VAR_NORM(int16);
|
||||
|
||||
LOOP { NEAREST_NEIGHBOR_16BIT(); MIX_MONO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 8 bit samples, nearest neighbor stereo output
|
||||
*/
|
||||
MIXER(stereo_8bit_nearest)
|
||||
{
|
||||
VAR_NORM(int8);
|
||||
|
||||
LOOP { NEAREST_NEIGHBOR(); MIX_STEREO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, nearest neighbor stereo output
|
||||
*/
|
||||
MIXER(stereo_16bit_nearest)
|
||||
{
|
||||
VAR_NORM(int16);
|
||||
|
||||
LOOP { NEAREST_NEIGHBOR_16BIT(); MIX_STEREO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Linear mixers
|
||||
*/
|
||||
|
||||
/* Handler for 8 bit samples, linear interpolated mono output
|
||||
*/
|
||||
MIXER(mono_8bit_linear)
|
||||
{
|
||||
VAR_LINEAR_MONO(int8);
|
||||
|
||||
LOOP_AC { LINEAR_INTERP(); MIX_MONO_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP(); MIX_MONO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, linear interpolated mono output
|
||||
*/
|
||||
MIXER(mono_16bit_linear)
|
||||
{
|
||||
VAR_LINEAR_MONO(int16);
|
||||
|
||||
LOOP_AC { LINEAR_INTERP_16BIT(); MIX_MONO_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP_16BIT(); MIX_MONO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 8 bit samples, linear interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_8bit_linear)
|
||||
{
|
||||
VAR_LINEAR_STEREO(int8);
|
||||
|
||||
LOOP_AC { LINEAR_INTERP(); MIX_STEREO_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP(); MIX_STEREO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, linear interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_16bit_linear)
|
||||
{
|
||||
VAR_LINEAR_STEREO(int16);
|
||||
|
||||
LOOP_AC { LINEAR_INTERP_16BIT(); MIX_STEREO_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP_16BIT(); MIX_STEREO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
|
||||
/* Handler for 8 bit samples, filtered linear interpolated mono output
|
||||
*/
|
||||
MIXER(mono_8bit_linear_filter)
|
||||
{
|
||||
VAR_LINEAR_MONO(int8);
|
||||
VAR_FILTER_MONO;
|
||||
|
||||
LOOP_AC { LINEAR_INTERP(); MIX_MONO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP(); MIX_MONO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_MONO();
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, filtered linear interpolated mono output
|
||||
*/
|
||||
MIXER(mono_16bit_linear_filter)
|
||||
{
|
||||
VAR_LINEAR_MONO(int16);
|
||||
VAR_FILTER_MONO;
|
||||
|
||||
LOOP_AC { LINEAR_INTERP_16BIT(); MIX_MONO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP_16BIT(); MIX_MONO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_MONO();
|
||||
}
|
||||
|
||||
/* Handler for 8 bit samples, filtered linear interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_8bit_linear_filter)
|
||||
{
|
||||
VAR_LINEAR_STEREO(int8);
|
||||
VAR_FILTER_STEREO;
|
||||
|
||||
LOOP_AC { LINEAR_INTERP(); MIX_STEREO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP(); MIX_STEREO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_STEREO();
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, filtered linear interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_16bit_linear_filter)
|
||||
{
|
||||
VAR_LINEAR_STEREO(int16);
|
||||
VAR_FILTER_STEREO;
|
||||
|
||||
LOOP_AC { LINEAR_INTERP_16BIT(); MIX_STEREO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP_16BIT(); MIX_STEREO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_STEREO();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Spline mixers
|
||||
*/
|
||||
|
||||
/* Handler for 8 bit samples, spline interpolated mono output
|
||||
*/
|
||||
MIXER(mono_8bit_spline)
|
||||
{
|
||||
VAR_SPLINE_MONO(int8);
|
||||
|
||||
LOOP_AC { SPLINE_INTERP(); MIX_MONO_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP(); MIX_MONO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, spline interpolated mono output
|
||||
*/
|
||||
MIXER(mono_16bit_spline)
|
||||
{
|
||||
VAR_SPLINE_MONO(int16);
|
||||
|
||||
LOOP_AC { SPLINE_INTERP_16BIT(); MIX_MONO_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP_16BIT(); MIX_MONO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 8 bit samples, spline interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_8bit_spline)
|
||||
{
|
||||
VAR_SPLINE_STEREO(int8);
|
||||
|
||||
LOOP_AC { SPLINE_INTERP(); MIX_STEREO_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP(); MIX_STEREO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, spline interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_16bit_spline)
|
||||
{
|
||||
VAR_SPLINE_STEREO(int16);
|
||||
|
||||
LOOP_AC { SPLINE_INTERP_16BIT(); MIX_STEREO_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP_16BIT(); MIX_STEREO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
|
||||
/* Handler for 8 bit samples, filtered spline interpolated mono output
|
||||
*/
|
||||
MIXER(mono_8bit_spline_filter)
|
||||
{
|
||||
VAR_SPLINE_MONO(int8);
|
||||
VAR_FILTER_MONO;
|
||||
|
||||
LOOP_AC { SPLINE_INTERP(); MIX_MONO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP(); MIX_MONO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_MONO();
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, filtered spline interpolated mono output
|
||||
*/
|
||||
MIXER(mono_16bit_spline_filter)
|
||||
{
|
||||
VAR_SPLINE_MONO(int16);
|
||||
VAR_FILTER_MONO;
|
||||
|
||||
LOOP_AC { SPLINE_INTERP_16BIT(); MIX_MONO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP_16BIT(); MIX_MONO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_MONO();
|
||||
}
|
||||
|
||||
/* Handler for 8 bit samples, filtered spline interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_8bit_spline_filter)
|
||||
{
|
||||
VAR_SPLINE_STEREO(int8);
|
||||
VAR_FILTER_STEREO;
|
||||
|
||||
LOOP_AC { SPLINE_INTERP(); MIX_STEREO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP(); MIX_STEREO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_STEREO();
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, filtered spline interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_16bit_spline_filter)
|
||||
{
|
||||
VAR_SPLINE_STEREO(int16);
|
||||
VAR_FILTER_STEREO;
|
||||
|
||||
LOOP_AC { SPLINE_INTERP_16BIT(); MIX_STEREO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP_16BIT(); MIX_STEREO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_STEREO();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,840 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "common.h"
|
||||
#include "virtual.h"
|
||||
#include "mixer.h"
|
||||
#include "period.h"
|
||||
#include "player.h" /* for set_sample_end() */
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
#include "paula.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define FLAG_16_BITS 0x01
|
||||
#define FLAG_STEREO 0x02
|
||||
#define FLAG_FILTER 0x04
|
||||
#define FLAG_ACTIVE 0x10
|
||||
/* #define FLAG_SYNTH 0x20 */
|
||||
#define FIDX_FLAGMASK (FLAG_16_BITS | FLAG_STEREO | FLAG_FILTER)
|
||||
|
||||
#define DOWNMIX_SHIFT 12
|
||||
#define LIM8_HI 127
|
||||
#define LIM8_LO -128
|
||||
#define LIM16_HI 32767
|
||||
#define LIM16_LO -32768
|
||||
|
||||
#define MIX_FN(x) void libxmp_mix_##x(struct mixer_voice *, int32 *, int, int, int, int, int, int, int)
|
||||
|
||||
MIX_FN(mono_8bit_nearest);
|
||||
MIX_FN(mono_8bit_linear);
|
||||
MIX_FN(mono_16bit_nearest);
|
||||
MIX_FN(mono_16bit_linear);
|
||||
MIX_FN(stereo_8bit_nearest);
|
||||
MIX_FN(stereo_8bit_linear);
|
||||
MIX_FN(stereo_16bit_nearest);
|
||||
MIX_FN(stereo_16bit_linear);
|
||||
MIX_FN(mono_8bit_spline);
|
||||
MIX_FN(mono_16bit_spline);
|
||||
MIX_FN(stereo_8bit_spline);
|
||||
MIX_FN(stereo_16bit_spline);
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
MIX_FN(mono_8bit_linear_filter);
|
||||
MIX_FN(mono_16bit_linear_filter);
|
||||
MIX_FN(stereo_8bit_linear_filter);
|
||||
MIX_FN(stereo_16bit_linear_filter);
|
||||
MIX_FN(mono_8bit_spline_filter);
|
||||
MIX_FN(mono_16bit_spline_filter);
|
||||
MIX_FN(stereo_8bit_spline_filter);
|
||||
MIX_FN(stereo_16bit_spline_filter);
|
||||
#endif
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
MIX_FN(mono_a500);
|
||||
MIX_FN(mono_a500_filter);
|
||||
MIX_FN(stereo_a500);
|
||||
MIX_FN(stereo_a500_filter);
|
||||
#endif
|
||||
|
||||
/* Mixers array index:
|
||||
*
|
||||
* bit 0: 0=8 bit sample, 1=16 bit sample
|
||||
* bit 1: 0=mono output, 1=stereo output
|
||||
* bit 2: 0=unfiltered, 1=filtered
|
||||
*/
|
||||
|
||||
typedef void (*mixer_set[])(struct mixer_voice *, int32 *, int, int, int, int, int, int, int);
|
||||
|
||||
static mixer_set nearest_mixers = {
|
||||
libxmp_mix_mono_8bit_nearest,
|
||||
libxmp_mix_mono_16bit_nearest,
|
||||
libxmp_mix_stereo_8bit_nearest,
|
||||
libxmp_mix_stereo_16bit_nearest,
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
libxmp_mix_mono_8bit_nearest,
|
||||
libxmp_mix_mono_16bit_nearest,
|
||||
libxmp_mix_stereo_8bit_nearest,
|
||||
libxmp_mix_stereo_16bit_nearest,
|
||||
#endif
|
||||
};
|
||||
|
||||
static mixer_set linear_mixers = {
|
||||
libxmp_mix_mono_8bit_linear,
|
||||
libxmp_mix_mono_16bit_linear,
|
||||
libxmp_mix_stereo_8bit_linear,
|
||||
libxmp_mix_stereo_16bit_linear,
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
libxmp_mix_mono_8bit_linear_filter,
|
||||
libxmp_mix_mono_16bit_linear_filter,
|
||||
libxmp_mix_stereo_8bit_linear_filter,
|
||||
libxmp_mix_stereo_16bit_linear_filter
|
||||
#endif
|
||||
};
|
||||
|
||||
static mixer_set spline_mixers = {
|
||||
libxmp_mix_mono_8bit_spline,
|
||||
libxmp_mix_mono_16bit_spline,
|
||||
libxmp_mix_stereo_8bit_spline,
|
||||
libxmp_mix_stereo_16bit_spline,
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
libxmp_mix_mono_8bit_spline_filter,
|
||||
libxmp_mix_mono_16bit_spline_filter,
|
||||
libxmp_mix_stereo_8bit_spline_filter,
|
||||
libxmp_mix_stereo_16bit_spline_filter
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
static mixer_set a500_mixers = {
|
||||
libxmp_mix_mono_a500,
|
||||
NULL,
|
||||
libxmp_mix_stereo_a500,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static mixer_set a500led_mixers = {
|
||||
libxmp_mix_mono_a500_filter,
|
||||
NULL,
|
||||
libxmp_mix_stereo_a500_filter,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/* Downmix 32bit samples to 8bit, signed or unsigned, mono or stereo output */
|
||||
static void downmix_int_8bit(int8 *dest, int32 *src, int num, int amp, int offs)
|
||||
{
|
||||
int smp;
|
||||
int shift = DOWNMIX_SHIFT + 8 - amp;
|
||||
|
||||
for (; num--; src++, dest++) {
|
||||
smp = *src >> shift;
|
||||
if (smp > LIM8_HI) {
|
||||
*dest = LIM8_HI;
|
||||
} else if (smp < LIM8_LO) {
|
||||
*dest = LIM8_LO;
|
||||
} else {
|
||||
*dest = smp;
|
||||
}
|
||||
|
||||
if (offs) *dest += offs;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Downmix 32bit samples to 16bit, signed or unsigned, mono or stereo output */
|
||||
static void downmix_int_16bit(int16 *dest, int32 *src, int num, int amp, int offs)
|
||||
{
|
||||
int smp;
|
||||
int shift = DOWNMIX_SHIFT - amp;
|
||||
|
||||
for (; num--; src++, dest++) {
|
||||
smp = *src >> shift;
|
||||
if (smp > LIM16_HI) {
|
||||
*dest = LIM16_HI;
|
||||
} else if (smp < LIM16_LO) {
|
||||
*dest = LIM16_LO;
|
||||
} else {
|
||||
*dest = smp;
|
||||
}
|
||||
|
||||
if (offs) *dest += offs;
|
||||
}
|
||||
}
|
||||
|
||||
static void anticlick(struct mixer_voice *vi)
|
||||
{
|
||||
vi->flags |= ANTICLICK;
|
||||
vi->old_vl = 0;
|
||||
vi->old_vr = 0;
|
||||
}
|
||||
|
||||
/* Ok, it's messy, but it works :-) Hipolito */
|
||||
static void do_anticlick(struct context_data *ctx, int voc, int32 *buf, int count)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_data *s = &ctx->s;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
int smp_l, smp_r, max_x2;
|
||||
int discharge = s->ticksize >> ANTICLICK_SHIFT;
|
||||
|
||||
smp_r = vi->sright;
|
||||
smp_l = vi->sleft;
|
||||
vi->sright = vi->sleft = 0;
|
||||
|
||||
if (smp_l == 0 && smp_r == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buf == NULL) {
|
||||
buf = s->buf32;
|
||||
count = discharge;
|
||||
} else if (count > discharge) {
|
||||
count = discharge;
|
||||
}
|
||||
|
||||
if (count <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
max_x2 = count * count;
|
||||
|
||||
while (count--) {
|
||||
if (~s->format & XMP_FORMAT_MONO) {
|
||||
*buf++ += (count * (smp_r >> 10) / max_x2 * count) << 10;
|
||||
}
|
||||
|
||||
*buf++ += (count * (smp_l >> 10) / max_x2 * count) << 10;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_sample_end(struct context_data *ctx, int voc, int end)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
struct channel_data *xc;
|
||||
|
||||
if ((uint32)voc >= p->virt.maxvoc)
|
||||
return;
|
||||
|
||||
xc = &p->xc_data[vi->chn];
|
||||
|
||||
if (end) {
|
||||
SET_NOTE(NOTE_SAMPLE_END);
|
||||
if (HAS_QUIRK(QUIRK_RSTCHN)) {
|
||||
libxmp_virt_resetvoice(ctx, voc, 0);
|
||||
}
|
||||
} else {
|
||||
RESET_NOTE(NOTE_SAMPLE_END);
|
||||
}
|
||||
}
|
||||
|
||||
static void adjust_voice_end(struct mixer_voice *vi, struct xmp_sample *xxs)
|
||||
{
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP) {
|
||||
if ((xxs->flg & XMP_SAMPLE_LOOP_FULL) && (~vi->flags & SAMPLE_LOOP)) {
|
||||
vi->end = xxs->len;
|
||||
} else {
|
||||
vi->end = xxs->lpe;
|
||||
}
|
||||
} else {
|
||||
vi->end = xxs->len;
|
||||
}
|
||||
}
|
||||
|
||||
static void loop_reposition(struct context_data *ctx, struct mixer_voice *vi, struct xmp_sample *xxs)
|
||||
{
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
struct module_data *m = &ctx->m;
|
||||
#endif
|
||||
int loop_size = xxs->lpe - xxs->lps;
|
||||
|
||||
/* Reposition for next loop */
|
||||
vi->pos -= loop_size; /* forward loop */
|
||||
vi->end = xxs->lpe;
|
||||
vi->flags |= SAMPLE_LOOP;
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
vi->end += loop_size; /* unrolled loop */
|
||||
vi->pos -= loop_size; /* forward loop */
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
/* OpenMPT Bidi-Loops.it: "In Impulse Tracker’s software mixer,
|
||||
* ping-pong loops are shortened by one sample.
|
||||
*/
|
||||
if (IS_PLAYER_MODE_IT()) {
|
||||
vi->end--;
|
||||
vi->pos++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Prepare the mixer for the next tick */
|
||||
void libxmp_mixer_prepare(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct mixer_data *s = &ctx->s;
|
||||
int bytelen;
|
||||
|
||||
s->ticksize = (int)(s->freq * m->time_factor * m->rrate / p->bpm / 1000);
|
||||
|
||||
bytelen = s->ticksize * sizeof(int);
|
||||
if (~s->format & XMP_FORMAT_MONO) {
|
||||
bytelen *= 2;
|
||||
}
|
||||
memset(s->buf32, 0, bytelen);
|
||||
}
|
||||
/* Fill the output buffer calling one of the handlers. The buffer contains
|
||||
* sound for one tick (a PAL frame or 1/50s for standard vblank-timed mods)
|
||||
*/
|
||||
void libxmp_mixer_softmixer(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_data *s = &ctx->s;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xmp_sample *xxs;
|
||||
struct mixer_voice *vi;
|
||||
double step;
|
||||
int samples, size;
|
||||
int vol_l, vol_r, voc, usmp;
|
||||
int prev_l, prev_r = 0;
|
||||
int lps, lpe;
|
||||
int32 *buf_pos;
|
||||
void (*mix_fn)(struct mixer_voice *, int32 *, int, int, int, int, int, int, int);
|
||||
mixer_set *mixers;
|
||||
|
||||
switch (s->interp) {
|
||||
case XMP_INTERP_NEAREST:
|
||||
mixers = (mixer_set *)&nearest_mixers;
|
||||
break;
|
||||
case XMP_INTERP_LINEAR:
|
||||
mixers = (mixer_set *)&linear_mixers;
|
||||
break;
|
||||
case XMP_INTERP_SPLINE:
|
||||
mixers = (mixer_set *)&spline_mixers;
|
||||
break;
|
||||
default:
|
||||
mixers = (mixer_set *)&linear_mixers;
|
||||
}
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
if (p->flags & XMP_FLAGS_A500) {
|
||||
if (IS_AMIGA_MOD()) {
|
||||
if (p->filter) {
|
||||
mixers = (mixer_set *)&a500led_mixers;
|
||||
} else {
|
||||
mixers = (mixer_set *)&a500_mixers;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
libxmp_mixer_prepare(ctx);
|
||||
|
||||
for (voc = 0; voc < p->virt.maxvoc; voc++) {
|
||||
int c5spd, rampsize, delta_l, delta_r;
|
||||
|
||||
vi = &p->virt.voice_array[voc];
|
||||
|
||||
if (vi->flags & ANTICLICK) {
|
||||
if (s->interp > XMP_INTERP_NEAREST) {
|
||||
do_anticlick(ctx, voc, NULL, 0);
|
||||
}
|
||||
vi->flags &= ~ANTICLICK;
|
||||
}
|
||||
|
||||
if (vi->chn < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vi->period < 1) {
|
||||
libxmp_virt_resetvoice(ctx, voc, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
vi->pos0 = (int)vi->pos;
|
||||
|
||||
buf_pos = s->buf32;
|
||||
if (vi->pan == PAN_SURROUND) {
|
||||
vol_r = vi->vol * 0x80;
|
||||
vol_l = -vi->vol * 0x80;
|
||||
} else {
|
||||
vol_r = vi->vol * (0x80 - vi->pan);
|
||||
vol_l = vi->vol * (0x80 + vi->pan);
|
||||
}
|
||||
|
||||
if (vi->smp < mod->smp) {
|
||||
xxs = &mod->xxs[vi->smp];
|
||||
c5spd = (int) m->xtra[vi->smp].c5spd;
|
||||
} else {
|
||||
xxs = &ctx->smix.xxs[vi->smp - mod->smp];
|
||||
c5spd = m->c4rate;
|
||||
}
|
||||
|
||||
step = C4_PERIOD * c5spd / s->freq / vi->period;
|
||||
|
||||
if (step < 0.001) { /* otherwise m5v-nwlf.it crashes */
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
if (xxs->flg & XMP_SAMPLE_SLOOP && vi->smp < mod->smp) {
|
||||
if (~vi->flags & VOICE_RELEASE) {
|
||||
if (vi->pos < m->xsmp[vi->smp].lpe) {
|
||||
xxs = &m->xsmp[vi->smp];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adjust_voice_end(vi, xxs);
|
||||
#endif
|
||||
|
||||
lps = xxs->lps;
|
||||
lpe = xxs->lpe;
|
||||
|
||||
if (p->flags & XMP_FLAGS_FIXLOOP) {
|
||||
lps >>= 1;
|
||||
}
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
vi->end += lpe - lps;
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
if (IS_PLAYER_MODE_IT()) {
|
||||
vi->end--;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
rampsize = s->ticksize >> ANTICLICK_SHIFT;
|
||||
delta_l = (vol_l - vi->old_vl) / rampsize;
|
||||
delta_r = (vol_r - vi->old_vr) / rampsize;
|
||||
|
||||
usmp = 0;
|
||||
for (size = s->ticksize; size > 0; ) {
|
||||
int split_noloop = 0;
|
||||
|
||||
if (p->xc_data[vi->chn].split) {
|
||||
split_noloop = 1;
|
||||
}
|
||||
|
||||
/* How many samples we can write before the loop break
|
||||
* or sample end... */
|
||||
if (vi->pos >= vi->end) {
|
||||
samples = 0;
|
||||
usmp = 1;
|
||||
} else {
|
||||
int s = (int) ceil(((double)vi->end - vi->pos) / step);
|
||||
/* ...inside the tick boundaries */
|
||||
if (s > size) {
|
||||
s = size;
|
||||
}
|
||||
|
||||
samples = s;
|
||||
if (samples > 0) {
|
||||
usmp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (vi->vol) {
|
||||
int mix_size = samples;
|
||||
int mixer = vi->fidx & FIDX_FLAGMASK;
|
||||
|
||||
if (~s->format & XMP_FORMAT_MONO) {
|
||||
mix_size *= 2;
|
||||
}
|
||||
|
||||
/* For Hipolito's anticlick routine */
|
||||
if (samples > 0) {
|
||||
if (~s->format & XMP_FORMAT_MONO) {
|
||||
prev_r = buf_pos[mix_size - 2];
|
||||
}
|
||||
prev_l = buf_pos[mix_size - 1];
|
||||
} else {
|
||||
prev_r = prev_l = 0;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
/* See OpenMPT env-flt-max.it */
|
||||
if (vi->filter.cutoff >= 0xfe &&
|
||||
vi->filter.resonance == 0) {
|
||||
mixer &= ~FLAG_FILTER;
|
||||
}
|
||||
#endif
|
||||
|
||||
mix_fn = (*mixers)[mixer];
|
||||
|
||||
/* Call the output handler */
|
||||
if (samples > 0 && vi->sptr != NULL) {
|
||||
int rsize = 0;
|
||||
|
||||
if (rampsize > samples) {
|
||||
rampsize -= samples;
|
||||
} else {
|
||||
rsize = samples - rampsize;
|
||||
rampsize = 0;
|
||||
}
|
||||
|
||||
if (delta_l == 0 && delta_r == 0) {
|
||||
/* no need to ramp */
|
||||
rsize = samples;
|
||||
}
|
||||
|
||||
if (mix_fn != NULL) {
|
||||
mix_fn(vi, buf_pos, samples,
|
||||
vol_l >> 8, vol_r >> 8, (int) (step * (1 << SMIX_SHIFT)), rsize, delta_l, delta_r);
|
||||
}
|
||||
|
||||
buf_pos += mix_size;
|
||||
vi->old_vl += samples * delta_l;
|
||||
vi->old_vr += samples * delta_r;
|
||||
|
||||
|
||||
/* For Hipolito's anticlick routine */
|
||||
if (~s->format & XMP_FORMAT_MONO) {
|
||||
vi->sright = buf_pos[-2] - prev_r;
|
||||
}
|
||||
vi->sleft = buf_pos[-1] - prev_l;
|
||||
}
|
||||
}
|
||||
|
||||
vi->pos += step * samples;
|
||||
|
||||
/* No more samples in this tick */
|
||||
size -= samples + usmp;
|
||||
if (size <= 0) {
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP) {
|
||||
if (vi->pos + step > vi->end) {
|
||||
vi->pos += step;
|
||||
loop_reposition(ctx, vi, xxs);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* First sample loop run */
|
||||
if ((~xxs->flg & XMP_SAMPLE_LOOP) || split_noloop) {
|
||||
do_anticlick(ctx, voc, buf_pos, size);
|
||||
set_sample_end(ctx, voc, 1);
|
||||
size = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
loop_reposition(ctx, vi, xxs);
|
||||
}
|
||||
|
||||
vi->old_vl = vol_l;
|
||||
vi->old_vr = vol_r;
|
||||
}
|
||||
|
||||
/* Render final frame */
|
||||
|
||||
size = s->ticksize;
|
||||
if (~s->format & XMP_FORMAT_MONO) {
|
||||
size *= 2;
|
||||
}
|
||||
|
||||
if (size > XMP_MAX_FRAMESIZE) {
|
||||
size = XMP_MAX_FRAMESIZE;
|
||||
}
|
||||
|
||||
if (s->format & XMP_FORMAT_8BIT) {
|
||||
downmix_int_8bit((int8 *)s->buffer, s->buf32, size, s->amplify,
|
||||
s->format & XMP_FORMAT_UNSIGNED ? 0x80 : 0);
|
||||
} else {
|
||||
downmix_int_16bit((int16 *)s->buffer, s->buf32, size,s->amplify,
|
||||
s->format & XMP_FORMAT_UNSIGNED ? 0x8000 : 0);
|
||||
}
|
||||
|
||||
s->dtright = s->dtleft = 0;
|
||||
}
|
||||
|
||||
void libxmp_mixer_voicepos(struct context_data *ctx, int voc, double pos, int ac)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
struct xmp_sample *xxs;
|
||||
int lps;
|
||||
|
||||
if (vi->smp < m->mod.smp) {
|
||||
xxs = &m->mod.xxs[vi->smp];
|
||||
} else {
|
||||
xxs = &ctx->smix.xxs[vi->smp - m->mod.smp];
|
||||
}
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_SYNTH) {
|
||||
return;
|
||||
}
|
||||
|
||||
vi->pos = pos;
|
||||
|
||||
adjust_voice_end(vi, xxs);
|
||||
|
||||
if (vi->pos >= vi->end) {
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP) {
|
||||
vi->pos = xxs->lps;
|
||||
} else {
|
||||
vi->pos = xxs->len;
|
||||
}
|
||||
}
|
||||
|
||||
lps = xxs->lps;
|
||||
if (p->flags & XMP_FLAGS_FIXLOOP) {
|
||||
lps >>= 1;
|
||||
}
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
vi->end += (xxs->lpe - lps);
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
if (IS_PLAYER_MODE_IT()) {
|
||||
vi->end--;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ac) {
|
||||
anticlick(vi);
|
||||
}
|
||||
}
|
||||
|
||||
double libxmp_mixer_getvoicepos(struct context_data *ctx, int voc)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
struct xmp_sample *xxs;
|
||||
|
||||
xxs = libxmp_get_sample(ctx, vi->smp);
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_SYNTH) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
if (vi->pos >= xxs->lpe) {
|
||||
return xxs->lpe - (vi->pos - xxs->lpe) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return vi->pos;
|
||||
}
|
||||
|
||||
void libxmp_mixer_setpatch(struct context_data *ctx, int voc, int smp, int ac)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
struct module_data *m = &ctx->m;
|
||||
#endif
|
||||
struct mixer_data *s = &ctx->s;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
struct xmp_sample *xxs;
|
||||
|
||||
xxs = libxmp_get_sample(ctx, smp);
|
||||
|
||||
vi->smp = smp;
|
||||
vi->vol = 0;
|
||||
vi->pan = 0;
|
||||
vi->flags &= ~SAMPLE_LOOP;
|
||||
|
||||
vi->fidx = 0;
|
||||
|
||||
if (~s->format & XMP_FORMAT_MONO) {
|
||||
vi->fidx |= FLAG_STEREO;
|
||||
}
|
||||
|
||||
set_sample_end(ctx, voc, 0);
|
||||
|
||||
/*mixer_setvol(ctx, voc, 0);*/
|
||||
|
||||
vi->sptr = xxs->data;
|
||||
vi->fidx |= FLAG_ACTIVE;
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
if (HAS_QUIRK(QUIRK_FILTER) && s->dsp & XMP_DSP_LOWPASS) {
|
||||
vi->fidx |= FLAG_FILTER;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
vi->fidx |= FLAG_16_BITS;
|
||||
}
|
||||
|
||||
libxmp_mixer_voicepos(ctx, voc, 0, ac);
|
||||
}
|
||||
|
||||
void libxmp_mixer_setnote(struct context_data *ctx, int voc, int note)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
|
||||
/* FIXME: Workaround for crash on notes that are too high
|
||||
* see 6nations.it (+114 transposition on instrument 16)
|
||||
*/
|
||||
if (note > 149) {
|
||||
note = 149;
|
||||
}
|
||||
|
||||
vi->note = note;
|
||||
vi->period = libxmp_note_to_period_mix(note, 0);
|
||||
|
||||
anticlick(vi);
|
||||
}
|
||||
|
||||
void libxmp_mixer_setperiod(struct context_data *ctx, int voc, double period)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
|
||||
vi->period = period;
|
||||
}
|
||||
|
||||
void libxmp_mixer_setvol(struct context_data *ctx, int voc, int vol)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
|
||||
if (vol == 0) {
|
||||
anticlick(vi);
|
||||
}
|
||||
|
||||
vi->vol = vol;
|
||||
}
|
||||
|
||||
void libxmp_mixer_release(struct context_data *ctx, int voc, int rel)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
|
||||
if (rel) {
|
||||
vi->flags |= VOICE_RELEASE;
|
||||
} else {
|
||||
vi->flags &= ~VOICE_RELEASE;
|
||||
}
|
||||
}
|
||||
|
||||
void libxmp_mixer_seteffect(struct context_data *ctx, int voc, int type, int val)
|
||||
{
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
|
||||
switch (type) {
|
||||
case DSP_EFFECT_CUTOFF:
|
||||
vi->filter.cutoff = val;
|
||||
break;
|
||||
case DSP_EFFECT_RESONANCE:
|
||||
vi->filter.resonance = val;
|
||||
break;
|
||||
case DSP_EFFECT_FILTER_A0:
|
||||
vi->filter.a0 = val;
|
||||
break;
|
||||
case DSP_EFFECT_FILTER_B0:
|
||||
vi->filter.b0 = val;
|
||||
break;
|
||||
case DSP_EFFECT_FILTER_B1:
|
||||
vi->filter.b1 = val;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void libxmp_mixer_setpan(struct context_data *ctx, int voc, int pan)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
|
||||
vi->pan = pan;
|
||||
}
|
||||
|
||||
int libxmp_mixer_numvoices(struct context_data *ctx, int num)
|
||||
{
|
||||
struct mixer_data *s = &ctx->s;
|
||||
|
||||
if (num > s->numvoc || num < 0) {
|
||||
return s->numvoc;
|
||||
} else {
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
int libxmp_mixer_on(struct context_data *ctx, int rate, int format, int c4rate)
|
||||
{
|
||||
struct mixer_data *s = &ctx->s;
|
||||
|
||||
s->buffer = (char *)calloc(2, XMP_MAX_FRAMESIZE);
|
||||
if (s->buffer == NULL)
|
||||
goto err;
|
||||
|
||||
s->buf32 = (int32 *)calloc(sizeof(int32), XMP_MAX_FRAMESIZE);
|
||||
if (s->buf32 == NULL)
|
||||
goto err1;
|
||||
|
||||
s->freq = rate;
|
||||
s->format = format;
|
||||
s->amplify = DEFAULT_AMPLIFY;
|
||||
s->mix = DEFAULT_MIX;
|
||||
/* s->pbase = C4_PERIOD * c4rate / s->freq; */
|
||||
s->interp = XMP_INTERP_LINEAR; /* default interpolation type */
|
||||
s->dsp = XMP_DSP_LOWPASS; /* enable filters by default */
|
||||
/* s->numvoc = SMIX_NUMVOC; */
|
||||
s->dtright = s->dtleft = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
free(s->buffer);
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void libxmp_mixer_off(struct context_data *ctx)
|
||||
{
|
||||
struct mixer_data *s = &ctx->s;
|
||||
|
||||
free(s->buffer);
|
||||
free(s->buf32);
|
||||
s->buf32 = NULL;
|
||||
s->buffer = NULL;
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
#ifndef LIBXMP_MIXER_H
|
||||
#define LIBXMP_MIXER_H
|
||||
|
||||
#define C4_PERIOD 428.0
|
||||
|
||||
#define SMIX_NUMVOC 128 /* default number of softmixer voices */
|
||||
#define SMIX_SHIFT 16
|
||||
#define SMIX_MASK 0xffff
|
||||
|
||||
#define FILTER_SHIFT 16
|
||||
#define ANTICLICK_SHIFT 3
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
#include "paula.h"
|
||||
#endif
|
||||
|
||||
#define MIXER(f) void libxmp_mix_##f(struct mixer_voice *vi, int *buffer, \
|
||||
int count, int vl, int vr, int step, int ramp, int delta_l, int delta_r)
|
||||
|
||||
struct mixer_voice {
|
||||
int chn; /* channel number */
|
||||
int root; /* */
|
||||
int note; /* */
|
||||
#define PAN_SURROUND 0x8000
|
||||
int pan; /* */
|
||||
int vol; /* */
|
||||
double period; /* current period */
|
||||
double pos; /* position in sample */
|
||||
int pos0; /* position in sample before mixing */
|
||||
int fidx; /* mixer function index */
|
||||
int ins; /* instrument number */
|
||||
int smp; /* sample number */
|
||||
int end; /* loop end */
|
||||
int act; /* nna info & status of voice */
|
||||
int old_vl; /* previous volume, left channel */
|
||||
int old_vr; /* previous volume, right channel */
|
||||
int sleft; /* last left sample output, in 32bit */
|
||||
int sright; /* last right sample output, in 32bit */
|
||||
#define VOICE_RELEASE (1 << 0)
|
||||
#define ANTICLICK (1 << 1)
|
||||
#define SAMPLE_LOOP (1 << 2)
|
||||
int flags; /* flags */
|
||||
void *sptr; /* sample pointer */
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
struct paula_state *paula; /* paula simulation state */
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
struct {
|
||||
int r1; /* filter variables */
|
||||
int r2;
|
||||
int l1;
|
||||
int l2;
|
||||
int a0;
|
||||
int b0;
|
||||
int b1;
|
||||
int cutoff;
|
||||
int resonance;
|
||||
} filter;
|
||||
#endif
|
||||
};
|
||||
|
||||
int libxmp_mixer_on (struct context_data *, int, int, int);
|
||||
void libxmp_mixer_off (struct context_data *);
|
||||
void libxmp_mixer_setvol (struct context_data *, int, int);
|
||||
void libxmp_mixer_seteffect (struct context_data *, int, int, int);
|
||||
void libxmp_mixer_setpan (struct context_data *, int, int);
|
||||
int libxmp_mixer_numvoices (struct context_data *, int);
|
||||
void libxmp_mixer_softmixer (struct context_data *);
|
||||
void libxmp_mixer_reset (struct context_data *);
|
||||
void libxmp_mixer_setpatch (struct context_data *, int, int, int);
|
||||
void libxmp_mixer_voicepos (struct context_data *, int, double, int);
|
||||
double libxmp_mixer_getvoicepos(struct context_data *, int);
|
||||
void libxmp_mixer_setnote (struct context_data *, int, int);
|
||||
void libxmp_mixer_setperiod (struct context_data *, int, double);
|
||||
void libxmp_mixer_release (struct context_data *, int, int);
|
||||
|
||||
#endif /* LIBXMP_MIXER_H */
|
|
@ -1,55 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
struct mod_instrument {
|
||||
uint8 name[22]; /* Instrument name */
|
||||
uint16 size; /* Sample length in 16-bit words */
|
||||
int8 finetune; /* Finetune (signed nibble) */
|
||||
int8 volume; /* Linear playback volume */
|
||||
uint16 loop_start; /* Loop start in 16-bit words */
|
||||
uint16 loop_size; /* Loop length in 16-bit words */
|
||||
};
|
||||
|
||||
struct mod_header {
|
||||
uint8 name[20];
|
||||
struct mod_instrument ins[31];
|
||||
uint8 len;
|
||||
uint8 restart; /* Number of patterns in Soundtracker,
|
||||
* Restart in Noisetracker/Startrekker,
|
||||
* 0x7F in Protracker
|
||||
*/
|
||||
uint8 order[128];
|
||||
uint8 magic[4];
|
||||
};
|
||||
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
/* Soundtracker 15-instrument module header */
|
||||
|
||||
struct st_header {
|
||||
uint8 name[20];
|
||||
struct mod_instrument ins[15];
|
||||
uint8 len;
|
||||
uint8 restart;
|
||||
uint8 order[128];
|
||||
};
|
||||
#endif
|
|
@ -1,233 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* This loader recognizes the following variants of the Protracker
|
||||
* module format:
|
||||
*
|
||||
* - Protracker M.K.
|
||||
* - Fasttracker ?CHN and ??CH
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include "loader.h"
|
||||
#include "mod.h"
|
||||
|
||||
static int mod_test(HIO_HANDLE *, char *, const int);
|
||||
static int mod_load(struct module_data *, HIO_HANDLE *, const int);
|
||||
|
||||
extern const struct format_loader libxmp_loader_mod;
|
||||
const struct format_loader libxmp_loader_mod = {
|
||||
"Protracker",
|
||||
mod_test,
|
||||
mod_load
|
||||
};
|
||||
|
||||
static int mod_test(HIO_HANDLE *f, char *t, const int start)
|
||||
{
|
||||
int i;
|
||||
char buf[4];
|
||||
|
||||
hio_seek(f, start + 1080, SEEK_SET);
|
||||
if (hio_read(buf, 1, 4, f) < 4)
|
||||
return -1;
|
||||
|
||||
if (!strncmp(buf + 2, "CH", 2) && isdigit((int)buf[0])
|
||||
&& isdigit((int)buf[1])) {
|
||||
i = (buf[0] - '0') * 10 + buf[1] - '0';
|
||||
if (i > 0 && i <= 32) {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strncmp(buf + 1, "CHN", 3) && isdigit((int)*buf)) {
|
||||
if (*buf >= '0' && *buf <= '9') {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(buf, "M.K.", 4))
|
||||
return -1;
|
||||
|
||||
found:
|
||||
hio_seek(f, start + 0, SEEK_SET);
|
||||
libxmp_read_title(f, t, 20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mod_load(struct module_data *m, HIO_HANDLE *f, const int start)
|
||||
{
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, j;
|
||||
struct xmp_event *event;
|
||||
struct mod_header mh;
|
||||
uint8 mod_event[4];
|
||||
char magic[8];
|
||||
int ptkloop = 0; /* Protracker loop */
|
||||
|
||||
LOAD_INIT();
|
||||
|
||||
mod->ins = 31;
|
||||
mod->smp = mod->ins;
|
||||
mod->chn = 0;
|
||||
|
||||
m->quirk |= QUIRK_PROTRACK;
|
||||
m->period_type = PERIOD_MODRNG;
|
||||
|
||||
hio_read(&mh.name, 20, 1, f);
|
||||
for (i = 0; i < 31; i++) {
|
||||
hio_read(&mh.ins[i].name, 22, 1, f); /* Instrument name */
|
||||
mh.ins[i].size = hio_read16b(f); /* Length in 16-bit words */
|
||||
mh.ins[i].finetune = hio_read8(f); /* Finetune (signed nibble) */
|
||||
mh.ins[i].volume = hio_read8(f); /* Linear playback volume */
|
||||
mh.ins[i].loop_start = hio_read16b(f); /* Loop start in 16-bit words */
|
||||
mh.ins[i].loop_size = hio_read16b(f); /* Loop size in 16-bit words */
|
||||
}
|
||||
mh.len = hio_read8(f);
|
||||
mh.restart = hio_read8(f);
|
||||
hio_read(&mh.order, 128, 1, f);
|
||||
memset(magic, 0, 8);
|
||||
hio_read(magic, 4, 1, f);
|
||||
|
||||
if (!memcmp(magic, "M.K.", 4)) {
|
||||
mod->chn = 4;
|
||||
} else if (!strncmp(magic + 2, "CH", 2) &&
|
||||
isdigit((int)magic[0]) && isdigit((int)magic[1])) {
|
||||
mod->chn = (*magic - '0') * 10 + magic[1] - '0';
|
||||
} else if (!strncmp(magic + 1, "CHN", 3) && isdigit((int)*magic)) {
|
||||
mod->chn = *magic - '0';
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(mod->name, (char *)mh.name, 20);
|
||||
|
||||
mod->len = mh.len;
|
||||
/* mod->rst = mh.restart; */
|
||||
|
||||
if (mod->rst >= mod->len)
|
||||
mod->rst = 0;
|
||||
memcpy(mod->xxo, mh.order, 128);
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
/* This fixes dragnet.mod (garbage in the order list) */
|
||||
if (mod->xxo[i] > 0x7f)
|
||||
break;
|
||||
if (mod->xxo[i] > mod->pat)
|
||||
mod->pat = mod->xxo[i];
|
||||
}
|
||||
mod->pat++;
|
||||
|
||||
if (libxmp_init_instrument(m) < 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
struct xmp_instrument *xxi;
|
||||
struct xmp_subinstrument *sub;
|
||||
struct xmp_sample *xxs;
|
||||
|
||||
if (libxmp_alloc_subinstrument(mod, i, 1) < 0)
|
||||
return -1;
|
||||
|
||||
xxi = &mod->xxi[i];
|
||||
sub = &xxi->sub[0];
|
||||
xxs = &mod->xxs[i];
|
||||
|
||||
xxs->len = 2 * mh.ins[i].size;
|
||||
xxs->lps = 2 * mh.ins[i].loop_start;
|
||||
xxs->lpe = xxs->lps + 2 * mh.ins[i].loop_size;
|
||||
if (xxs->lpe > xxs->len) {
|
||||
xxs->lpe = xxs->len;
|
||||
}
|
||||
xxs->flg = (mh.ins[i].loop_size > 1 && xxs->lpe >= 4) ?
|
||||
XMP_SAMPLE_LOOP : 0;
|
||||
sub->fin = (int8) (mh.ins[i].finetune << 4);
|
||||
sub->vol = mh.ins[i].volume;
|
||||
sub->pan = 0x80;
|
||||
sub->sid = i;
|
||||
libxmp_instrument_name(mod, i, mh.ins[i].name, 22);
|
||||
|
||||
if (xxs->len > 0) {
|
||||
xxi->nsm = 1;
|
||||
}
|
||||
}
|
||||
|
||||
mod->trk = mod->chn * mod->pat;
|
||||
|
||||
libxmp_set_type(m, mod->chn == 4 ? "Protracker" : "Fasttracker");
|
||||
|
||||
MODULE_INFO();
|
||||
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
D_(D_INFO "[%2X] %-22.22s %04x %04x %04x %c V%02x %+d %c\n",
|
||||
i, mod->xxi[i].name,
|
||||
mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe,
|
||||
(mh.ins[i].loop_size > 1 && mod->xxs[i].lpe > 8) ?
|
||||
'L' : ' ', mod->xxi[i].sub[0].vol,
|
||||
mod->xxi[i].sub[0].fin >> 4,
|
||||
ptkloop && mod->xxs[i].lps == 0 && mh.ins[i].loop_size > 1 &&
|
||||
mod->xxs[i].len > mod->xxs[i].lpe ? '!' : ' ');
|
||||
}
|
||||
|
||||
if (libxmp_init_pattern(mod) < 0)
|
||||
return -1;
|
||||
|
||||
/* Load and convert patterns */
|
||||
D_(D_INFO "Stored patterns: %d", mod->pat);
|
||||
|
||||
for (i = 0; i < mod->pat; i++) {
|
||||
if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0)
|
||||
return -1;
|
||||
|
||||
for (j = 0; j < (64 * mod->chn); j++) {
|
||||
event = &EVENT(i, j % mod->chn, j / mod->chn);
|
||||
hio_read(mod_event, 1, 4, f);
|
||||
libxmp_decode_protracker_event(event, mod_event);
|
||||
}
|
||||
}
|
||||
|
||||
/* Load samples */
|
||||
|
||||
D_(D_INFO "Stored samples: %d", mod->smp);
|
||||
|
||||
for (i = 0; i < mod->smp; i++) {
|
||||
int flags;
|
||||
|
||||
if (!mod->xxs[i].len)
|
||||
continue;
|
||||
|
||||
flags = ptkloop ? SAMPLE_FLAG_FULLREP : 0;
|
||||
|
||||
if (libxmp_load_sample(m, f, flags, &mod->xxs[i], NULL) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mod->chn > 4) {
|
||||
m->quirk &= ~QUIRK_PROTRACK;
|
||||
m->quirk |= QUIRKS_FT2 | QUIRK_FTMOD;
|
||||
m->read_event_type = READ_EVENT_FT2;
|
||||
m->period_type = PERIOD_AMIGA;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,265 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "loader.h"
|
||||
|
||||
struct mtm_file_header {
|
||||
uint8 magic[3]; /* "MTM" */
|
||||
uint8 version; /* MSN=major, LSN=minor */
|
||||
uint8 name[20]; /* ASCIIZ Module name */
|
||||
uint16 tracks; /* Number of tracks saved */
|
||||
uint8 patterns; /* Number of patterns saved */
|
||||
uint8 modlen; /* Module length */
|
||||
uint16 extralen; /* Length of the comment field */
|
||||
uint8 samples; /* Number of samples */
|
||||
uint8 attr; /* Always zero */
|
||||
uint8 rows; /* Number rows per track */
|
||||
uint8 channels; /* Number of tracks per pattern */
|
||||
uint8 pan[32]; /* Pan positions for each channel */
|
||||
};
|
||||
|
||||
struct mtm_instrument_header {
|
||||
uint8 name[22]; /* Instrument name */
|
||||
uint32 length; /* Instrument length in bytes */
|
||||
uint32 loop_start; /* Sample loop start */
|
||||
uint32 loopend; /* Sample loop end */
|
||||
uint8 finetune; /* Finetune */
|
||||
uint8 volume; /* Playback volume */
|
||||
uint8 attr; /* &0x01: 16bit sample */
|
||||
};
|
||||
|
||||
static int mtm_test(HIO_HANDLE *, char *, const int);
|
||||
static int mtm_load(struct module_data *, HIO_HANDLE *, const int);
|
||||
|
||||
extern const struct format_loader libxmp_loader_mtm;
|
||||
const struct format_loader libxmp_loader_mtm = {
|
||||
"Multitracker",
|
||||
mtm_test,
|
||||
mtm_load
|
||||
};
|
||||
|
||||
static int mtm_test(HIO_HANDLE *f, char *t, const int start)
|
||||
{
|
||||
uint8 buf[4];
|
||||
|
||||
if (hio_read(buf, 1, 4, f) < 4)
|
||||
return -1;
|
||||
if (memcmp(buf, "MTM", 3))
|
||||
return -1;
|
||||
if (buf[3] != 0x10)
|
||||
return -1;
|
||||
|
||||
libxmp_read_title(f, t, 20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtm_load(struct module_data *m, HIO_HANDLE *f, const int start)
|
||||
{
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, j;
|
||||
struct mtm_file_header mfh;
|
||||
struct mtm_instrument_header mih;
|
||||
uint8 mt[192];
|
||||
|
||||
LOAD_INIT();
|
||||
|
||||
hio_read(&mfh.magic, 3, 1, f); /* "MTM" */
|
||||
mfh.version = hio_read8(f); /* MSN=major, LSN=minor */
|
||||
hio_read(&mfh.name, 20, 1, f); /* ASCIIZ Module name */
|
||||
mfh.tracks = hio_read16l(f); /* Number of tracks saved */
|
||||
mfh.patterns = hio_read8(f); /* Number of patterns saved */
|
||||
mfh.modlen = hio_read8(f); /* Module length */
|
||||
mfh.extralen = hio_read16l(f); /* Length of the comment field */
|
||||
|
||||
mfh.samples = hio_read8(f); /* Number of samples */
|
||||
if (mfh.samples > 63) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mfh.attr = hio_read8(f); /* Always zero */
|
||||
|
||||
mfh.rows = hio_read8(f); /* Number rows per track */
|
||||
if (mfh.rows != 64)
|
||||
return -1;
|
||||
|
||||
mfh.channels = hio_read8(f); /* Number of tracks per pattern */
|
||||
if (mfh.channels > XMP_MAX_CHANNELS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
hio_read(&mfh.pan, 32, 1, f); /* Pan positions for each channel */
|
||||
|
||||
if (hio_error(f)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (strncmp((char *)mfh.magic, "MTM", 3))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
mod->trk = mfh.tracks + 1;
|
||||
mod->pat = mfh.patterns + 1;
|
||||
mod->len = mfh.modlen + 1;
|
||||
mod->ins = mfh.samples;
|
||||
mod->smp = mod->ins;
|
||||
mod->chn = mfh.channels;
|
||||
mod->spd = 6;
|
||||
mod->bpm = 125;
|
||||
|
||||
strncpy(mod->name, (char *)mfh.name, 20);
|
||||
libxmp_set_type(m, "MultiTracker %d.%02d MTM", MSN(mfh.version),
|
||||
LSN(mfh.version));
|
||||
|
||||
MODULE_INFO();
|
||||
|
||||
if (libxmp_init_instrument(m) < 0)
|
||||
return -1;
|
||||
|
||||
/* Read and convert instruments */
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
struct xmp_instrument *xxi = &mod->xxi[i];
|
||||
struct xmp_sample *xxs = &mod->xxs[i];
|
||||
struct xmp_subinstrument *sub;
|
||||
|
||||
if (libxmp_alloc_subinstrument(mod, i, 1) < 0)
|
||||
return -1;
|
||||
|
||||
sub = &xxi->sub[0];
|
||||
|
||||
hio_read(&mih.name, 22, 1, f); /* Instrument name */
|
||||
mih.length = hio_read32l(f); /* Instrument length in bytes */
|
||||
|
||||
if (mih.length > MAX_SAMPLE_SIZE)
|
||||
return -1;
|
||||
|
||||
mih.loop_start = hio_read32l(f); /* Sample loop start */
|
||||
mih.loopend = hio_read32l(f); /* Sample loop end */
|
||||
mih.finetune = hio_read8(f); /* Finetune */
|
||||
mih.volume = hio_read8(f); /* Playback volume */
|
||||
mih.attr = hio_read8(f); /* &0x01: 16bit sample */
|
||||
|
||||
xxs->len = mih.length;
|
||||
xxs->lps = mih.loop_start;
|
||||
xxs->lpe = mih.loopend;
|
||||
xxs->flg = xxs->lpe ? XMP_SAMPLE_LOOP : 0; /* 1 == Forward loop */
|
||||
if (mfh.attr & 1) {
|
||||
xxs->flg |= XMP_SAMPLE_16BIT;
|
||||
xxs->len >>= 1;
|
||||
xxs->lps >>= 1;
|
||||
xxs->lpe >>= 1;
|
||||
}
|
||||
|
||||
sub->vol = mih.volume;
|
||||
sub->fin = mih.finetune;
|
||||
sub->pan = 0x80;
|
||||
sub->sid = i;
|
||||
|
||||
libxmp_instrument_name(mod, i, mih.name, 22);
|
||||
|
||||
if (xxs->len > 0)
|
||||
mod->xxi[i].nsm = 1;
|
||||
|
||||
D_(D_INFO "[%2X] %-22.22s %04x%c%04x %04x %c V%02x F%+03d\n", i,
|
||||
xxi->name, xxs->len, xxs->flg & XMP_SAMPLE_16BIT ? '+' : ' ',
|
||||
xxs->lps, xxs->lpe, xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ',
|
||||
sub->vol, sub->fin - 0x80);
|
||||
}
|
||||
|
||||
hio_read(mod->xxo, 1, 128, f);
|
||||
|
||||
if (libxmp_init_pattern(mod) < 0)
|
||||
return -1;
|
||||
|
||||
D_(D_INFO "Stored tracks: %d", mod->trk - 1);
|
||||
|
||||
for (i = 0; i < mod->trk; i++) {
|
||||
|
||||
if (libxmp_alloc_track(mod, i, mfh.rows) < 0)
|
||||
return -1;
|
||||
|
||||
if (i == 0)
|
||||
continue;
|
||||
|
||||
if (hio_read(&mt, 3, 64, f) != 64)
|
||||
return -1;
|
||||
|
||||
for (j = 0; j < 64; j++) {
|
||||
struct xmp_event *e = &mod->xxt[i]->event[j];
|
||||
uint8 *d = mt + j * 3;
|
||||
|
||||
if ((e->note = d[0] >> 2)) {
|
||||
e->note += 37;
|
||||
}
|
||||
e->ins = ((d[0] & 0x3) << 4) + MSN(d[1]);
|
||||
e->fxt = LSN(d[1]);
|
||||
e->fxp = d[2];
|
||||
if (e->fxt > FX_SPEED) {
|
||||
e->fxt = e->fxp = 0;
|
||||
}
|
||||
|
||||
/* Set pan effect translation */
|
||||
if (e->fxt == FX_EXTENDED && MSN(e->fxp) == 0x8) {
|
||||
e->fxt = FX_SETPAN;
|
||||
e->fxp <<= 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Read patterns */
|
||||
D_(D_INFO "Stored patterns: %d", mod->pat - 1);
|
||||
|
||||
for (i = 0; i < mod->pat; i++) {
|
||||
if (libxmp_alloc_pattern(mod, i) < 0)
|
||||
return -1;
|
||||
|
||||
mod->xxp[i]->rows = 64;
|
||||
for (j = 0; j < 32; j++) {
|
||||
int track = hio_read16l(f);
|
||||
|
||||
if (track >= mod->trk) {
|
||||
track = 0;
|
||||
}
|
||||
|
||||
if (j < mod->chn) {
|
||||
mod->xxp[i]->index[j] = track;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Comments */
|
||||
hio_seek(f, mfh.extralen, SEEK_CUR);
|
||||
|
||||
/* Read samples */
|
||||
D_(D_INFO "Stored samples: %d", mod->smp);
|
||||
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
if (libxmp_load_sample(m, f, SAMPLE_FLAG_UNS, &mod->xxs[i], NULL) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < mod->chn; i++)
|
||||
mod->xxc[i].pan = mfh.pan[i] << 4;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,268 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
#include "period.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
/*
|
||||
* Period table from the Protracker V2.1A play routine
|
||||
*/
|
||||
static uint16 pt_period_table[16][36] = {
|
||||
/* Tuning 0, Normal */
|
||||
{
|
||||
856,808,762,720,678,640,604,570,538,508,480,453,
|
||||
428,404,381,360,339,320,302,285,269,254,240,226,
|
||||
214,202,190,180,170,160,151,143,135,127,120,113
|
||||
},
|
||||
/* Tuning 1 */
|
||||
{
|
||||
850,802,757,715,674,637,601,567,535,505,477,450,
|
||||
425,401,379,357,337,318,300,284,268,253,239,225,
|
||||
213,201,189,179,169,159,150,142,134,126,119,113
|
||||
},
|
||||
/* Tuning 2 */
|
||||
{
|
||||
844,796,752,709,670,632,597,563,532,502,474,447,
|
||||
422,398,376,355,335,316,298,282,266,251,237,224,
|
||||
211,199,188,177,167,158,149,141,133,125,118,112
|
||||
},
|
||||
/* Tuning 3 */
|
||||
{
|
||||
838,791,746,704,665,628,592,559,528,498,470,444,
|
||||
419,395,373,352,332,314,296,280,264,249,235,222,
|
||||
209,198,187,176,166,157,148,140,132,125,118,111
|
||||
},
|
||||
/* Tuning 4 */
|
||||
{
|
||||
832,785,741,699,660,623,588,555,524,495,467,441,
|
||||
416,392,370,350,330,312,294,278,262,247,233,220,
|
||||
208,196,185,175,165,156,147,139,131,124,117,110
|
||||
},
|
||||
/* Tuning 5 */
|
||||
{
|
||||
826,779,736,694,655,619,584,551,520,491,463,437,
|
||||
413,390,368,347,328,309,292,276,260,245,232,219,
|
||||
206,195,184,174,164,155,146,138,130,123,116,109
|
||||
},
|
||||
/* Tuning 6 */
|
||||
{
|
||||
820,774,730,689,651,614,580,547,516,487,460,434,
|
||||
410,387,365,345,325,307,290,274,258,244,230,217,
|
||||
205,193,183,172,163,154,145,137,129,122,115,109
|
||||
},
|
||||
/* Tuning 7 */
|
||||
{
|
||||
814,768,725,684,646,610,575,543,513,484,457,431,
|
||||
407,384,363,342,323,305,288,272,256,242,228,216,
|
||||
204,192,181,171,161,152,144,136,128,121,114,108
|
||||
},
|
||||
/* Tuning -8 */
|
||||
{
|
||||
907,856,808,762,720,678,640,604,570,538,508,480,
|
||||
453,428,404,381,360,339,320,302,285,269,254,240,
|
||||
226,214,202,190,180,170,160,151,143,135,127,120
|
||||
},
|
||||
/* Tuning -7 */
|
||||
{
|
||||
900,850,802,757,715,675,636,601,567,535,505,477,
|
||||
450,425,401,379,357,337,318,300,284,268,253,238,
|
||||
225,212,200,189,179,169,159,150,142,134,126,119
|
||||
},
|
||||
/* Tuning -6 */
|
||||
{
|
||||
894,844,796,752,709,670,632,597,563,532,502,474,
|
||||
447,422,398,376,355,335,316,298,282,266,251,237,
|
||||
223,211,199,188,177,167,158,149,141,133,125,118
|
||||
},
|
||||
/* Tuning -5 */
|
||||
{
|
||||
887,838,791,746,704,665,628,592,559,528,498,470,
|
||||
444,419,395,373,352,332,314,296,280,264,249,235,
|
||||
222,209,198,187,176,166,157,148,140,132,125,118
|
||||
},
|
||||
/* Tuning -4 */
|
||||
{
|
||||
881,832,785,741,699,660,623,588,555,524,494,467,
|
||||
441,416,392,370,350,330,312,294,278,262,247,233,
|
||||
220,208,196,185,175,165,156,147,139,131,123,117
|
||||
},
|
||||
/* Tuning -3 */
|
||||
{
|
||||
875,826,779,736,694,655,619,584,551,520,491,463,
|
||||
437,413,390,368,347,328,309,292,276,260,245,232,
|
||||
219,206,195,184,174,164,155,146,138,130,123,116
|
||||
},
|
||||
/* Tuning -2 */
|
||||
{
|
||||
868,820,774,730,689,651,614,580,547,516,487,460,
|
||||
434,410,387,365,345,325,307,290,274,258,244,230,
|
||||
217,205,193,183,172,163,154,145,137,129,122,115
|
||||
},
|
||||
/* Tuning -1 */
|
||||
{
|
||||
862,814,768,725,684,646,610,575,543,513,484,457,
|
||||
431,407,384,363,342,323,305,288,272,256,242,228,
|
||||
216,203,192,181,171,161,152,144,136,128,121,114
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef M_LN2
|
||||
#define M_LN2 0.69314718055994530942
|
||||
#endif
|
||||
#if !defined(HAVE_ROUND) || defined(_MSC_VER) || defined(__WATCOMC__)
|
||||
static inline double libxmp_round(double val)
|
||||
{
|
||||
return (val >= 0.0)? floor(val + 0.5) : ceil(val - 0.5);
|
||||
}
|
||||
#else
|
||||
#define libxmp_round round
|
||||
#endif
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
/* Get period from note using Protracker tuning */
|
||||
static inline int libxmp_note_to_period_pt(int n, int f)
|
||||
{
|
||||
if (n < MIN_NOTE_MOD || n > MAX_NOTE_MOD) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
n -= 48;
|
||||
f >>= 4;
|
||||
if (f < -8 || f > 7) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (f < 0) {
|
||||
f += 16;
|
||||
}
|
||||
|
||||
return (int)pt_period_table[f][n];
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get period from note */
|
||||
double libxmp_note_to_period(struct context_data *ctx, int n, int f, double adj)
|
||||
{
|
||||
double d, per;
|
||||
struct module_data *m = &ctx->m;
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
struct player_data *p = &ctx->p;
|
||||
|
||||
/* If mod replayer, modrng and Amiga mixing are active */
|
||||
if (p->flags & XMP_FLAGS_A500) {
|
||||
if (IS_AMIGA_MOD()) {
|
||||
return libxmp_note_to_period_pt(n, f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
d = (double)n + (double)f / 128;
|
||||
|
||||
switch (m->period_type) {
|
||||
case PERIOD_LINEAR:
|
||||
per = (240.0 - d) * 16; /* Linear */
|
||||
break;
|
||||
case PERIOD_CSPD:
|
||||
per = 8363.0 * pow(2, n / 12) / 32 + f; /* Hz */
|
||||
break;
|
||||
default:
|
||||
per = PERIOD_BASE / pow(2, d / 12); /* Amiga */
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (adj > 0.1) {
|
||||
per *= adj;
|
||||
}
|
||||
#endif
|
||||
|
||||
return per;
|
||||
}
|
||||
|
||||
/* For the software mixer */
|
||||
double libxmp_note_to_period_mix(int n, int b)
|
||||
{
|
||||
double d = (double)n + (double)b / 12800;
|
||||
return PERIOD_BASE / pow(2, d / 12);
|
||||
}
|
||||
|
||||
/* Get note from period */
|
||||
/* This function is used only by the MOD loader */
|
||||
int libxmp_period_to_note(int p)
|
||||
{
|
||||
if (p <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return libxmp_round(12.0 * log(PERIOD_BASE / p) / M_LN2) + 1;
|
||||
}
|
||||
|
||||
/* Get pitchbend from base note and amiga period */
|
||||
int libxmp_period_to_bend(struct context_data *ctx, double p, int n, double adj)
|
||||
{
|
||||
struct module_data *m = &ctx->m;
|
||||
double d;
|
||||
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (m->period_type) {
|
||||
case PERIOD_LINEAR:
|
||||
return (int) (100 * (8 * (((240 - n) << 4) - p)));
|
||||
case PERIOD_CSPD:
|
||||
d = libxmp_note_to_period(ctx, n, 0, adj);
|
||||
return libxmp_round(100.0 * (1536.0 / M_LN2) * log(p / d));
|
||||
default:
|
||||
/* Amiga */
|
||||
d = libxmp_note_to_period(ctx, n, 0, adj);
|
||||
return libxmp_round(100.0 * (1536.0 / M_LN2) * log(d / p));
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert finetune = 1200 * log2(C2SPD/8363))
|
||||
*
|
||||
* c = (1200.0 * log(c2spd) - 1200.0 * log(c4_rate)) / M_LN2;
|
||||
* xpo = c/100;
|
||||
* fin = 128 * (c%100) / 100;
|
||||
*/
|
||||
void libxmp_c2spd_to_note(int c2spd, int *n, int *f)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (c2spd == 0) {
|
||||
*n = *f = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
c = (int)(1536.0 * log((double)c2spd / 8363) / M_LN2);
|
||||
*n = c / 128;
|
||||
*f = c % 128;
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
#ifndef LIBXMP_PERIOD_H
|
||||
#define LIBXMP_PERIOD_H
|
||||
|
||||
#define PERIOD_BASE 13696.0 /* C0 period */
|
||||
|
||||
/* Macros for period conversion */
|
||||
#define NOTE_B0 11
|
||||
#define NOTE_Bb0 (NOTE_B0 + 1)
|
||||
#define MAX_NOTE (NOTE_B0 * 8)
|
||||
#define MAX_PERIOD 0x1c56
|
||||
#define MIN_PERIOD_A 0x0071
|
||||
#define MAX_PERIOD_A 0x0358
|
||||
#define MIN_PERIOD_L 0x0000
|
||||
#define MAX_PERIOD_L 0x1e00
|
||||
#define MIN_NOTE_MOD 48
|
||||
#define MAX_NOTE_MOD 83
|
||||
|
||||
double libxmp_note_to_period (struct context_data *, int, int, double);
|
||||
double libxmp_note_to_period_mix (int, int);
|
||||
int libxmp_period_to_note (int);
|
||||
int libxmp_period_to_bend (struct context_data *, double, int, double);
|
||||
void libxmp_c2spd_to_note (int, int *, int *);
|
||||
|
||||
#endif /* LIBXMP_PERIOD_H */
|
File diff suppressed because it is too large
Load diff
|
@ -1,258 +0,0 @@
|
|||
#ifndef LIBXMP_PLAYER_H
|
||||
#define LIBXMP_PLAYER_H
|
||||
|
||||
#include "lfo.h"
|
||||
|
||||
/* Quirk control */
|
||||
#define HAS_QUIRK(x) (m->quirk & (x))
|
||||
|
||||
/* Channel flag control */
|
||||
#define SET(f) SET_FLAG(xc->flags,(f))
|
||||
#define RESET(f) RESET_FLAG(xc->flags,(f))
|
||||
#define TEST(f) TEST_FLAG(xc->flags,(f))
|
||||
|
||||
/* Persistent effect flag control */
|
||||
#define SET_PER(f) SET_FLAG(xc->per_flags,(f))
|
||||
#define RESET_PER(f) RESET_FLAG(xc->per_flags,(f))
|
||||
#define TEST_PER(f) TEST_FLAG(xc->per_flags,(f))
|
||||
|
||||
/* Note flag control */
|
||||
#define SET_NOTE(f) SET_FLAG(xc->note_flags,(f))
|
||||
#define RESET_NOTE(f) RESET_FLAG(xc->note_flags,(f))
|
||||
#define TEST_NOTE(f) TEST_FLAG(xc->note_flags,(f))
|
||||
|
||||
struct retrig_control {
|
||||
int s;
|
||||
int m;
|
||||
int d;
|
||||
};
|
||||
|
||||
/* The following macros are used to set the flags for each channel */
|
||||
#define VOL_SLIDE (1 << 0)
|
||||
#define PAN_SLIDE (1 << 1)
|
||||
#define TONEPORTA (1 << 2)
|
||||
#define PITCHBEND (1 << 3)
|
||||
#define VIBRATO (1 << 4)
|
||||
#define TREMOLO (1 << 5)
|
||||
#define FINE_VOLS (1 << 6)
|
||||
#define FINE_BEND (1 << 7)
|
||||
#define OFFSET (1 << 8)
|
||||
#define TRK_VSLIDE (1 << 9)
|
||||
#define TRK_FVSLIDE (1 << 10)
|
||||
#define NEW_INS (1 << 11)
|
||||
#define NEW_VOL (1 << 12)
|
||||
#define VOL_SLIDE_2 (1 << 13)
|
||||
#define NOTE_SLIDE (1 << 14)
|
||||
#define FINE_NSLIDE (1 << 15)
|
||||
#define NEW_NOTE (1 << 16)
|
||||
#define FINE_TPORTA (1 << 17)
|
||||
#define RETRIG (1 << 18)
|
||||
#define PANBRELLO (1 << 19)
|
||||
#define GVOL_SLIDE (1 << 20)
|
||||
#define TEMPO_SLIDE (1 << 21)
|
||||
#define VENV_PAUSE (1 << 22)
|
||||
#define PENV_PAUSE (1 << 23)
|
||||
#define FENV_PAUSE (1 << 24)
|
||||
#define FINE_VOLS_2 (1 << 25)
|
||||
#define KEY_OFF (1 << 26) /* for IT release on envloop end */
|
||||
#define TREMOR (1 << 27) /* for XM tremor */
|
||||
|
||||
#define NOTE_FADEOUT (1 << 0)
|
||||
#define NOTE_RELEASE (1 << 1)
|
||||
#define NOTE_END (1 << 2)
|
||||
#define NOTE_CUT (1 << 3)
|
||||
#define NOTE_ENV_END (1 << 4)
|
||||
#define NOTE_SAMPLE_END (1 << 5)
|
||||
#define NOTE_SET (1 << 6) /* for IT portamento after keyoff */
|
||||
#define NOTE_SUSEXIT (1 << 7) /* for delayed note release */
|
||||
#define NOTE_KEY_CUT (1 << 8) /* note cut with XMP_KEY_CUT event */
|
||||
#define NOTE_GLISSANDO (1 << 9)
|
||||
|
||||
#define IS_VALID_INSTRUMENT(x) ((uint32)(x) < mod->ins && mod->xxi[(x)].nsm > 0)
|
||||
#define IS_VALID_INSTRUMENT_OR_SFX(x) (((uint32)(x) < mod->ins && mod->xxi[(x)].nsm > 0) || (smix->ins > 0 && (uint32)(x) < mod->ins + smix->ins))
|
||||
|
||||
struct instrument_vibrato {
|
||||
int phase;
|
||||
int sweep;
|
||||
};
|
||||
|
||||
struct channel_data {
|
||||
int flags; /* Channel flags */
|
||||
int per_flags; /* Persistent effect channel flags */
|
||||
int note_flags; /* Note release, fadeout or end */
|
||||
int note; /* Note number */
|
||||
int key; /* Key number */
|
||||
double period; /* Amiga or linear period */
|
||||
double per_adj; /* MED period/pitch adjustment factor hack */
|
||||
int finetune; /* Guess what */
|
||||
int ins; /* Instrument number */
|
||||
int old_ins; /* Last instruemnt */
|
||||
int smp; /* Sample number */
|
||||
int mastervol; /* Master vol -- for IT track vol effect */
|
||||
int delay; /* Note delay in frames */
|
||||
int keyoff; /* Key off counter */
|
||||
int fadeout; /* Current fadeout (release) value */
|
||||
int ins_fade; /* Instrument fadeout value */
|
||||
int volume; /* Current volume */
|
||||
int gvl; /* Global volume for instrument for IT */
|
||||
|
||||
int rvv; /* Random volume variation */
|
||||
int rpv; /* Random pan variation */
|
||||
|
||||
uint8 split; /* Split channel */
|
||||
uint8 pair; /* Split channel pair */
|
||||
|
||||
int v_idx; /* Volume envelope index */
|
||||
int p_idx; /* Pan envelope index */
|
||||
int f_idx; /* Freq envelope index */
|
||||
|
||||
int key_porta; /* Key number for portamento target
|
||||
* -- needed to handle IT portamento xpo */
|
||||
struct {
|
||||
struct lfo lfo;
|
||||
int memory;
|
||||
} vibrato;
|
||||
|
||||
struct {
|
||||
struct lfo lfo;
|
||||
int memory;
|
||||
} tremolo;
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
struct {
|
||||
struct lfo lfo;
|
||||
int memory;
|
||||
} panbrello;
|
||||
#endif
|
||||
|
||||
struct {
|
||||
int8 val[16]; /* 16 for Smaksak MegaArps */
|
||||
int size;
|
||||
int count;
|
||||
int memory;
|
||||
} arpeggio;
|
||||
|
||||
struct {
|
||||
struct lfo lfo;
|
||||
int sweep;
|
||||
} insvib;
|
||||
|
||||
struct {
|
||||
int val;
|
||||
int val2; /* For fx9 bug emulation */
|
||||
int memory;
|
||||
} offset;
|
||||
|
||||
struct {
|
||||
int val; /* Retrig value */
|
||||
int count; /* Retrig counter */
|
||||
int type; /* Retrig type */
|
||||
} retrig;
|
||||
|
||||
struct {
|
||||
uint8 up,down; /* Tremor value */
|
||||
uint8 count; /* Tremor counter */
|
||||
uint8 memory; /* Tremor memory */
|
||||
} tremor;
|
||||
|
||||
struct {
|
||||
int slide; /* Volume slide value */
|
||||
int fslide; /* Fine volume slide value */
|
||||
int slide2; /* Volume slide value */
|
||||
int memory; /* Volume slide effect memory */
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
int fslide2;
|
||||
int memory2; /* Volume slide effect memory */
|
||||
#endif
|
||||
} vol;
|
||||
|
||||
struct {
|
||||
int up_memory; /* Fine volume slide up memory (XM) */
|
||||
int down_memory;/* Fine volume slide up memory (XM) */
|
||||
} fine_vol;
|
||||
|
||||
struct {
|
||||
int slide; /* Global volume slide value */
|
||||
int fslide; /* Fine global volume slide value */
|
||||
int memory; /* Global volume memory is saved per channel */
|
||||
} gvol;
|
||||
|
||||
struct {
|
||||
int slide; /* Track volume slide value */
|
||||
int fslide; /* Track fine volume slide value */
|
||||
int memory; /* Track volume slide effect memory */
|
||||
} trackvol;
|
||||
|
||||
struct {
|
||||
int slide; /* Frequency slide value */
|
||||
double fslide; /* Fine frequency slide value */
|
||||
int memory; /* Portamento effect memory */
|
||||
} freq;
|
||||
|
||||
struct {
|
||||
double target; /* Target period for tone portamento */
|
||||
int dir; /* Tone portamento up/down directionh */
|
||||
int slide; /* Delta for tone portamento */
|
||||
int memory; /* Tone portamento effect memory */
|
||||
} porta;
|
||||
|
||||
struct {
|
||||
int up_memory; /* FT2 has separate memories for these */
|
||||
int down_memory;/* cases (see Porta-LinkMem.xm) */
|
||||
} fine_porta;
|
||||
|
||||
struct {
|
||||
int val; /* Current pan value */
|
||||
int slide; /* Pan slide value */
|
||||
int fslide; /* Pan fine slide value */
|
||||
int memory; /* Pan slide effect memory */
|
||||
int surround; /* Surround channel flag */
|
||||
} pan;
|
||||
|
||||
struct {
|
||||
int speed;
|
||||
int count;
|
||||
int pos;
|
||||
} invloop;
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
struct {
|
||||
int slide; /* IT tempo slide */
|
||||
} tempo;
|
||||
|
||||
struct {
|
||||
int cutoff; /* IT filter cutoff frequency */
|
||||
int resonance; /* IT filter resonance */
|
||||
int envelope; /* IT filter envelope */
|
||||
} filter;
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
struct {
|
||||
int slide; /* PTM note slide amount */
|
||||
int fslide; /* OKT fine note slide amount */
|
||||
int speed; /* PTM note slide speed */
|
||||
int count; /* PTM note slide counter */
|
||||
} noteslide;
|
||||
|
||||
void *extra;
|
||||
#endif
|
||||
|
||||
struct xmp_event delayed_event;
|
||||
int delayed_ins; /* IT save instrument emulation */
|
||||
|
||||
int info_period; /* Period */
|
||||
int info_pitchbend; /* Linear pitchbend */
|
||||
int info_position; /* Position before mixing */
|
||||
int info_finalvol; /* Final volume including envelopes */
|
||||
int info_finalpan; /* Final pan including envelopes */
|
||||
};
|
||||
|
||||
|
||||
void libxmp_process_fx (struct context_data *, struct channel_data *,
|
||||
int, struct xmp_event *, int);
|
||||
void libxmp_filter_setup (int, int, int, int*, int*, int *);
|
||||
int libxmp_read_event (struct context_data *, struct xmp_event *, int);
|
||||
|
||||
#endif /* LIBXMP_PLAYER_H */
|
|
@ -1,524 +0,0 @@
|
|||
static int16 cubic_spline_lut0[1024] = {
|
||||
0, -8, -16, -24, -32, -40, -47, -55,
|
||||
-63, -71, -78, -86, -94, -101, -109, -117,
|
||||
-124, -132, -139, -146, -154, -161, -169, -176,
|
||||
-183, -190, -198, -205, -212, -219, -226, -233,
|
||||
-240, -247, -254, -261, -268, -275, -282, -289,
|
||||
-295, -302, -309, -316, -322, -329, -336, -342,
|
||||
-349, -355, -362, -368, -375, -381, -388, -394,
|
||||
-400, -407, -413, -419, -425, -432, -438, -444,
|
||||
-450, -456, -462, -468, -474, -480, -486, -492,
|
||||
-498, -504, -510, -515, -521, -527, -533, -538,
|
||||
-544, -550, -555, -561, -566, -572, -577, -583,
|
||||
-588, -594, -599, -604, -610, -615, -620, -626,
|
||||
-631, -636, -641, -646, -651, -656, -662, -667,
|
||||
-672, -677, -682, -686, -691, -696, -701, -706,
|
||||
-711, -715, -720, -725, -730, -734, -739, -744,
|
||||
-748, -753, -757, -762, -766, -771, -775, -780,
|
||||
-784, -788, -793, -797, -801, -806, -810, -814,
|
||||
-818, -822, -826, -831, -835, -839, -843, -847,
|
||||
-851, -855, -859, -863, -866, -870, -874, -878,
|
||||
-882, -886, -889, -893, -897, -900, -904, -908,
|
||||
-911, -915, -918, -922, -925, -929, -932, -936,
|
||||
-939, -943, -946, -949, -953, -956, -959, -962,
|
||||
-966, -969, -972, -975, -978, -981, -984, -987,
|
||||
-991, -994, -997, -999, -1002, -1005, -1008, -1011,
|
||||
-1014, -1017, -1020, -1022, -1025, -1028, -1031, -1033,
|
||||
-1036, -1039, -1041, -1044, -1047, -1049, -1052, -1054,
|
||||
-1057, -1059, -1062, -1064, -1066, -1069, -1071, -1074,
|
||||
-1076, -1078, -1080, -1083, -1085, -1087, -1089, -1092,
|
||||
-1094, -1096, -1098, -1100, -1102, -1104, -1106, -1108,
|
||||
-1110, -1112, -1114, -1116, -1118, -1120, -1122, -1124,
|
||||
-1125, -1127, -1129, -1131, -1133, -1134, -1136, -1138,
|
||||
-1139, -1141, -1143, -1144, -1146, -1147, -1149, -1150,
|
||||
-1152, -1153, -1155, -1156, -1158, -1159, -1161, -1162,
|
||||
-1163, -1165, -1166, -1167, -1169, -1170, -1171, -1172,
|
||||
-1174, -1175, -1176, -1177, -1178, -1179, -1180, -1181,
|
||||
-1182, -1184, -1185, -1186, -1187, -1187, -1188, -1189,
|
||||
-1190, -1191, -1192, -1193, -1194, -1195, -1195, -1196,
|
||||
-1197, -1198, -1198, -1199, -1200, -1200, -1201, -1202,
|
||||
-1202, -1203, -1204, -1204, -1205, -1205, -1206, -1206,
|
||||
-1207, -1207, -1208, -1208, -1208, -1209, -1209, -1210,
|
||||
-1210, -1210, -1211, -1211, -1211, -1212, -1212, -1212,
|
||||
-1212, -1212, -1213, -1213, -1213, -1213, -1213, -1213,
|
||||
-1213, -1213, -1214, -1214, -1214, -1214, -1214, -1214,
|
||||
-1214, -1214, -1213, -1213, -1213, -1213, -1213, -1213,
|
||||
-1213, -1213, -1212, -1212, -1212, -1212, -1211, -1211,
|
||||
-1211, -1211, -1210, -1210, -1210, -1209, -1209, -1209,
|
||||
-1208, -1208, -1207, -1207, -1207, -1206, -1206, -1205,
|
||||
-1205, -1204, -1204, -1203, -1202, -1202, -1201, -1201,
|
||||
-1200, -1199, -1199, -1198, -1197, -1197, -1196, -1195,
|
||||
-1195, -1194, -1193, -1192, -1192, -1191, -1190, -1189,
|
||||
-1188, -1187, -1187, -1186, -1185, -1184, -1183, -1182,
|
||||
-1181, -1180, -1179, -1178, -1177, -1176, -1175, -1174,
|
||||
-1173, -1172, -1171, -1170, -1169, -1168, -1167, -1166,
|
||||
-1165, -1163, -1162, -1161, -1160, -1159, -1158, -1156,
|
||||
-1155, -1154, -1153, -1151, -1150, -1149, -1148, -1146,
|
||||
-1145, -1144, -1142, -1141, -1140, -1138, -1137, -1135,
|
||||
-1134, -1133, -1131, -1130, -1128, -1127, -1125, -1124,
|
||||
-1122, -1121, -1119, -1118, -1116, -1115, -1113, -1112,
|
||||
-1110, -1109, -1107, -1105, -1104, -1102, -1101, -1099,
|
||||
-1097, -1096, -1094, -1092, -1091, -1089, -1087, -1085,
|
||||
-1084, -1082, -1080, -1079, -1077, -1075, -1073, -1071,
|
||||
-1070, -1068, -1066, -1064, -1062, -1061, -1059, -1057,
|
||||
-1055, -1053, -1051, -1049, -1047, -1046, -1044, -1042,
|
||||
-1040, -1038, -1036, -1034, -1032, -1030, -1028, -1026,
|
||||
-1024, -1022, -1020, -1018, -1016, -1014, -1012, -1010,
|
||||
-1008, -1006, -1004, -1002, -999, -997, -995, -993,
|
||||
-991, -989, -987, -985, -982, -980, -978, -976,
|
||||
-974, -972, -969, -967, -965, -963, -961, -958,
|
||||
-956, -954, -952, -950, -947, -945, -943, -941,
|
||||
-938, -936, -934, -931, -929, -927, -924, -922,
|
||||
-920, -918, -915, -913, -911, -908, -906, -903,
|
||||
-901, -899, -896, -894, -892, -889, -887, -884,
|
||||
-882, -880, -877, -875, -872, -870, -867, -865,
|
||||
-863, -860, -858, -855, -853, -850, -848, -845,
|
||||
-843, -840, -838, -835, -833, -830, -828, -825,
|
||||
-823, -820, -818, -815, -813, -810, -808, -805,
|
||||
-803, -800, -798, -795, -793, -790, -787, -785,
|
||||
-782, -780, -777, -775, -772, -769, -767, -764,
|
||||
-762, -759, -757, -754, -751, -749, -746, -744,
|
||||
-741, -738, -736, -733, -730, -728, -725, -723,
|
||||
-720, -717, -715, -712, -709, -707, -704, -702,
|
||||
-699, -696, -694, -691, -688, -686, -683, -680,
|
||||
-678, -675, -672, -670, -667, -665, -662, -659,
|
||||
-657, -654, -651, -649, -646, -643, -641, -638,
|
||||
-635, -633, -630, -627, -625, -622, -619, -617,
|
||||
-614, -611, -609, -606, -603, -601, -598, -595,
|
||||
-593, -590, -587, -585, -582, -579, -577, -574,
|
||||
-571, -569, -566, -563, -561, -558, -555, -553,
|
||||
-550, -547, -545, -542, -539, -537, -534, -531,
|
||||
-529, -526, -523, -521, -518, -516, -513, -510,
|
||||
-508, -505, -502, -500, -497, -495, -492, -489,
|
||||
-487, -484, -481, -479, -476, -474, -471, -468,
|
||||
-466, -463, -461, -458, -455, -453, -450, -448,
|
||||
-445, -442, -440, -437, -435, -432, -430, -427,
|
||||
-424, -422, -419, -417, -414, -412, -409, -407,
|
||||
-404, -402, -399, -397, -394, -392, -389, -387,
|
||||
-384, -382, -379, -377, -374, -372, -369, -367,
|
||||
-364, -362, -359, -357, -354, -352, -349, -347,
|
||||
-345, -342, -340, -337, -335, -332, -330, -328,
|
||||
-325, -323, -320, -318, -316, -313, -311, -309,
|
||||
-306, -304, -302, -299, -297, -295, -292, -290,
|
||||
-288, -285, -283, -281, -278, -276, -274, -272,
|
||||
-269, -267, -265, -263, -260, -258, -256, -254,
|
||||
-251, -249, -247, -245, -243, -240, -238, -236,
|
||||
-234, -232, -230, -228, -225, -223, -221, -219,
|
||||
-217, -215, -213, -211, -209, -207, -205, -202,
|
||||
-200, -198, -196, -194, -192, -190, -188, -186,
|
||||
-184, -182, -180, -178, -176, -175, -173, -171,
|
||||
-169, -167, -165, -163, -161, -159, -157, -156,
|
||||
-154, -152, -150, -148, -146, -145, -143, -141,
|
||||
-139, -137, -136, -134, -132, -130, -129, -127,
|
||||
-125, -124, -122, -120, -119, -117, -115, -114,
|
||||
-112, -110, -109, -107, -106, -104, -102, -101,
|
||||
-99, -98, -96, -95, -93, -92, -90, -89,
|
||||
-87, -86, -84, -83, -82, -80, -79, -77,
|
||||
-76, -75, -73, -72, -70, -69, -68, -67,
|
||||
-65, -64, -63, -61, -60, -59, -58, -57,
|
||||
-55, -54, -53, -52, -51, -49, -48, -47,
|
||||
-46, -45, -44, -43, -42, -41, -40, -39,
|
||||
-38, -37, -36, -35, -34, -33, -32, -31,
|
||||
-30, -29, -28, -27, -26, -26, -25, -24,
|
||||
-23, -22, -22, -21, -20, -19, -19, -18,
|
||||
-17, -16, -16, -15, -14, -14, -13, -13,
|
||||
-12, -11, -11, -10, -10, -9, -9, -8,
|
||||
-8, -7, -7, -6, -6, -6, -5, -5,
|
||||
-4, -4, -4, -3, -3, -3, -2, -2,
|
||||
-2, -2, -2, -1, -1, -1, -1, -1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static int16 cubic_spline_lut1[1024] = {
|
||||
16384, 16384, 16384, 16384, 16384, 16383, 16382, 16381,
|
||||
16381, 16381, 16380, 16379, 16379, 16377, 16377, 16376,
|
||||
16374, 16373, 16371, 16370, 16369, 16366, 16366, 16364,
|
||||
16361, 16360, 16358, 16357, 16354, 16351, 16349, 16347,
|
||||
16345, 16342, 16340, 16337, 16335, 16331, 16329, 16326,
|
||||
16322, 16320, 16317, 16314, 16309, 16307, 16304, 16299,
|
||||
16297, 16293, 16290, 16285, 16282, 16278, 16274, 16269,
|
||||
16265, 16262, 16257, 16253, 16247, 16244, 16239, 16235,
|
||||
16230, 16225, 16220, 16216, 16211, 16206, 16201, 16196,
|
||||
16191, 16185, 16180, 16174, 16169, 16163, 16158, 16151,
|
||||
16146, 16140, 16133, 16128, 16122, 16116, 16109, 16104,
|
||||
16097, 16092, 16085, 16077, 16071, 16064, 16058, 16052,
|
||||
16044, 16038, 16030, 16023, 16015, 16009, 16002, 15995,
|
||||
15988, 15980, 15973, 15964, 15957, 15949, 15941, 15934,
|
||||
15926, 15918, 15910, 15903, 15894, 15886, 15877, 15870,
|
||||
15861, 15853, 15843, 15836, 15827, 15818, 15810, 15801,
|
||||
15792, 15783, 15774, 15765, 15756, 15747, 15738, 15729,
|
||||
15719, 15709, 15700, 15691, 15681, 15672, 15662, 15652,
|
||||
15642, 15633, 15623, 15613, 15602, 15592, 15582, 15572,
|
||||
15562, 15552, 15540, 15530, 15520, 15509, 15499, 15489,
|
||||
15478, 15467, 15456, 15446, 15433, 15423, 15412, 15401,
|
||||
15390, 15379, 15367, 15356, 15345, 15333, 15321, 15310,
|
||||
15299, 15287, 15276, 15264, 15252, 15240, 15228, 15216,
|
||||
15205, 15192, 15180, 15167, 15155, 15143, 15131, 15118,
|
||||
15106, 15094, 15081, 15067, 15056, 15043, 15031, 15017,
|
||||
15004, 14992, 14979, 14966, 14953, 14940, 14927, 14913,
|
||||
14900, 14887, 14874, 14860, 14846, 14833, 14819, 14806,
|
||||
14793, 14778, 14764, 14752, 14737, 14723, 14709, 14696,
|
||||
14681, 14668, 14653, 14638, 14625, 14610, 14595, 14582,
|
||||
14567, 14553, 14538, 14523, 14509, 14494, 14480, 14465,
|
||||
14450, 14435, 14420, 14406, 14391, 14376, 14361, 14346,
|
||||
14330, 14316, 14301, 14285, 14270, 14254, 14239, 14223,
|
||||
14208, 14192, 14177, 14161, 14146, 14130, 14115, 14099,
|
||||
14082, 14067, 14051, 14035, 14019, 14003, 13986, 13971,
|
||||
13955, 13939, 13923, 13906, 13890, 13873, 13857, 13840,
|
||||
13823, 13808, 13791, 13775, 13758, 13741, 13724, 13707,
|
||||
13691, 13673, 13657, 13641, 13623, 13607, 13589, 13572,
|
||||
13556, 13538, 13521, 13504, 13486, 13469, 13451, 13435,
|
||||
13417, 13399, 13383, 13365, 13347, 13330, 13312, 13294,
|
||||
13277, 13258, 13241, 13224, 13205, 13188, 13170, 13152,
|
||||
13134, 13116, 13098, 13080, 13062, 13044, 13026, 13008,
|
||||
12989, 12971, 12953, 12934, 12916, 12898, 12879, 12860,
|
||||
12842, 12823, 12806, 12787, 12768, 12750, 12731, 12712,
|
||||
12694, 12675, 12655, 12637, 12618, 12599, 12580, 12562,
|
||||
12542, 12524, 12504, 12485, 12466, 12448, 12427, 12408,
|
||||
12390, 12370, 12351, 12332, 12312, 12293, 12273, 12254,
|
||||
12235, 12215, 12195, 12176, 12157, 12137, 12118, 12097,
|
||||
12079, 12059, 12039, 12019, 11998, 11980, 11960, 11940,
|
||||
11920, 11900, 11880, 11860, 11839, 11821, 11801, 11780,
|
||||
11761, 11741, 11720, 11700, 11680, 11660, 11640, 11619,
|
||||
11599, 11578, 11559, 11538, 11518, 11498, 11477, 11457,
|
||||
11436, 11415, 11394, 11374, 11354, 11333, 11313, 11292,
|
||||
11272, 11251, 11231, 11209, 11189, 11168, 11148, 11127,
|
||||
11107, 11084, 11064, 11043, 11023, 11002, 10982, 10959,
|
||||
10939, 10918, 10898, 10876, 10856, 10834, 10814, 10792,
|
||||
10772, 10750, 10728, 10708, 10687, 10666, 10644, 10623,
|
||||
10602, 10581, 10560, 10538, 10517, 10496, 10474, 10453,
|
||||
10431, 10410, 10389, 10368, 10346, 10325, 10303, 10283,
|
||||
10260, 10239, 10217, 10196, 10175, 10152, 10132, 10110,
|
||||
10088, 10068, 10045, 10023, 10002, 9981, 9959, 9936,
|
||||
9915, 9893, 9872, 9851, 9829, 9806, 9784, 9763,
|
||||
9742, 9720, 9698, 9676, 9653, 9633, 9611, 9589,
|
||||
9567, 9545, 9523, 9501, 9479, 9458, 9436, 9414,
|
||||
9392, 9370, 9348, 9326, 9304, 9282, 9260, 9238,
|
||||
9216, 9194, 9172, 9150, 9128, 9106, 9084, 9062,
|
||||
9040, 9018, 8996, 8974, 8951, 8929, 8907, 8885,
|
||||
8863, 8841, 8819, 8797, 8775, 8752, 8730, 8708,
|
||||
8686, 8664, 8642, 8620, 8597, 8575, 8553, 8531,
|
||||
8509, 8487, 8464, 8442, 8420, 8398, 8376, 8353,
|
||||
8331, 8309, 8287, 8265, 8242, 8220, 8198, 8176,
|
||||
8154, 8131, 8109, 8087, 8065, 8042, 8020, 7998,
|
||||
7976, 7954, 7931, 7909, 7887, 7865, 7842, 7820,
|
||||
7798, 7776, 7754, 7731, 7709, 7687, 7665, 7643,
|
||||
7620, 7598, 7576, 7554, 7531, 7509, 7487, 7465,
|
||||
7443, 7421, 7398, 7376, 7354, 7332, 7310, 7288,
|
||||
7265, 7243, 7221, 7199, 7177, 7155, 7132, 7110,
|
||||
7088, 7066, 7044, 7022, 7000, 6978, 6956, 6934,
|
||||
6911, 6889, 6867, 6845, 6823, 6801, 6779, 6757,
|
||||
6735, 6713, 6691, 6669, 6647, 6625, 6603, 6581,
|
||||
6559, 6537, 6515, 6493, 6472, 6450, 6428, 6406,
|
||||
6384, 6362, 6340, 6318, 6297, 6275, 6253, 6231,
|
||||
6209, 6188, 6166, 6144, 6122, 6101, 6079, 6057,
|
||||
6035, 6014, 5992, 5970, 5949, 5927, 5905, 5884,
|
||||
5862, 5841, 5819, 5797, 5776, 5754, 5733, 5711,
|
||||
5690, 5668, 5647, 5625, 5604, 5582, 5561, 5540,
|
||||
5518, 5497, 5476, 5454, 5433, 5412, 5390, 5369,
|
||||
5348, 5327, 5305, 5284, 5263, 5242, 5221, 5199,
|
||||
5178, 5157, 5136, 5115, 5094, 5073, 5052, 5031,
|
||||
5010, 4989, 4968, 4947, 4926, 4905, 4885, 4864,
|
||||
4843, 4822, 4801, 4780, 4760, 4739, 4718, 4698,
|
||||
4677, 4656, 4636, 4615, 4595, 4574, 4553, 4533,
|
||||
4512, 4492, 4471, 4451, 4431, 4410, 4390, 4370,
|
||||
4349, 4329, 4309, 4288, 4268, 4248, 4228, 4208,
|
||||
4188, 4167, 4147, 4127, 4107, 4087, 4067, 4047,
|
||||
4027, 4007, 3988, 3968, 3948, 3928, 3908, 3889,
|
||||
3869, 3849, 3829, 3810, 3790, 3771, 3751, 3732,
|
||||
3712, 3693, 3673, 3654, 3634, 3615, 3595, 3576,
|
||||
3557, 3538, 3518, 3499, 3480, 3461, 3442, 3423,
|
||||
3404, 3385, 3366, 3347, 3328, 3309, 3290, 3271,
|
||||
3252, 3233, 3215, 3196, 3177, 3159, 3140, 3121,
|
||||
3103, 3084, 3066, 3047, 3029, 3010, 2992, 2974,
|
||||
2955, 2937, 2919, 2901, 2882, 2864, 2846, 2828,
|
||||
2810, 2792, 2774, 2756, 2738, 2720, 2702, 2685,
|
||||
2667, 2649, 2631, 2614, 2596, 2579, 2561, 2543,
|
||||
2526, 2509, 2491, 2474, 2456, 2439, 2422, 2405,
|
||||
2387, 2370, 2353, 2336, 2319, 2302, 2285, 2268,
|
||||
2251, 2234, 2218, 2201, 2184, 2167, 2151, 2134,
|
||||
2117, 2101, 2084, 2068, 2052, 2035, 2019, 2003,
|
||||
1986, 1970, 1954, 1938, 1922, 1906, 1890, 1874,
|
||||
1858, 1842, 1826, 1810, 1794, 1779, 1763, 1747,
|
||||
1732, 1716, 1701, 1685, 1670, 1654, 1639, 1624,
|
||||
1608, 1593, 1578, 1563, 1548, 1533, 1518, 1503,
|
||||
1488, 1473, 1458, 1444, 1429, 1414, 1400, 1385,
|
||||
1370, 1356, 1342, 1327, 1313, 1298, 1284, 1270,
|
||||
1256, 1242, 1228, 1214, 1200, 1186, 1172, 1158,
|
||||
1144, 1131, 1117, 1103, 1090, 1076, 1063, 1049,
|
||||
1036, 1022, 1009, 996, 983, 970, 956, 943,
|
||||
930, 917, 905, 892, 879, 866, 854, 841,
|
||||
828, 816, 803, 791, 778, 766, 754, 742,
|
||||
729, 717, 705, 693, 681, 669, 658, 646,
|
||||
634, 622, 611, 599, 588, 576, 565, 553,
|
||||
542, 531, 520, 508, 497, 486, 475, 464,
|
||||
453, 443, 432, 421, 411, 400, 389, 379,
|
||||
369, 358, 348, 338, 327, 317, 307, 297,
|
||||
287, 277, 268, 258, 248, 238, 229, 219,
|
||||
210, 200, 191, 182, 172, 163, 154, 145,
|
||||
136, 127, 118, 109, 100, 92, 83, 75,
|
||||
66, 58, 49, 41, 32, 24, 16, 8,
|
||||
};
|
||||
|
||||
static int16 cubic_spline_lut2[1024] = {
|
||||
0, 8, 16, 24, 32, 41, 49, 58,
|
||||
66, 75, 83, 92, 100, 109, 118, 127,
|
||||
136, 145, 154, 163, 172, 182, 191, 200,
|
||||
210, 219, 229, 238, 248, 258, 268, 277,
|
||||
287, 297, 307, 317, 327, 338, 348, 358,
|
||||
369, 379, 389, 400, 411, 421, 432, 443,
|
||||
453, 464, 475, 486, 497, 508, 520, 531,
|
||||
542, 553, 565, 576, 588, 599, 611, 622,
|
||||
634, 646, 658, 669, 681, 693, 705, 717,
|
||||
729, 742, 754, 766, 778, 791, 803, 816,
|
||||
828, 841, 854, 866, 879, 892, 905, 917,
|
||||
930, 943, 956, 970, 983, 996, 1009, 1022,
|
||||
1036, 1049, 1063, 1076, 1090, 1103, 1117, 1131,
|
||||
1144, 1158, 1172, 1186, 1200, 1214, 1228, 1242,
|
||||
1256, 1270, 1284, 1298, 1313, 1327, 1342, 1356,
|
||||
1370, 1385, 1400, 1414, 1429, 1444, 1458, 1473,
|
||||
1488, 1503, 1518, 1533, 1548, 1563, 1578, 1593,
|
||||
1608, 1624, 1639, 1654, 1670, 1685, 1701, 1716,
|
||||
1732, 1747, 1763, 1779, 1794, 1810, 1826, 1842,
|
||||
1858, 1874, 1890, 1906, 1922, 1938, 1954, 1970,
|
||||
1986, 2003, 2019, 2035, 2052, 2068, 2084, 2101,
|
||||
2117, 2134, 2151, 2167, 2184, 2201, 2218, 2234,
|
||||
2251, 2268, 2285, 2302, 2319, 2336, 2353, 2370,
|
||||
2387, 2405, 2422, 2439, 2456, 2474, 2491, 2509,
|
||||
2526, 2543, 2561, 2579, 2596, 2614, 2631, 2649,
|
||||
2667, 2685, 2702, 2720, 2738, 2756, 2774, 2792,
|
||||
2810, 2828, 2846, 2864, 2882, 2901, 2919, 2937,
|
||||
2955, 2974, 2992, 3010, 3029, 3047, 3066, 3084,
|
||||
3103, 3121, 3140, 3159, 3177, 3196, 3215, 3233,
|
||||
3252, 3271, 3290, 3309, 3328, 3347, 3366, 3385,
|
||||
3404, 3423, 3442, 3461, 3480, 3499, 3518, 3538,
|
||||
3557, 3576, 3595, 3615, 3634, 3654, 3673, 3693,
|
||||
3712, 3732, 3751, 3771, 3790, 3810, 3829, 3849,
|
||||
3869, 3889, 3908, 3928, 3948, 3968, 3988, 4007,
|
||||
4027, 4047, 4067, 4087, 4107, 4127, 4147, 4167,
|
||||
4188, 4208, 4228, 4248, 4268, 4288, 4309, 4329,
|
||||
4349, 4370, 4390, 4410, 4431, 4451, 4471, 4492,
|
||||
4512, 4533, 4553, 4574, 4595, 4615, 4636, 4656,
|
||||
4677, 4698, 4718, 4739, 4760, 4780, 4801, 4822,
|
||||
4843, 4864, 4885, 4905, 4926, 4947, 4968, 4989,
|
||||
5010, 5031, 5052, 5073, 5094, 5115, 5136, 5157,
|
||||
5178, 5199, 5221, 5242, 5263, 5284, 5305, 5327,
|
||||
5348, 5369, 5390, 5412, 5433, 5454, 5476, 5497,
|
||||
5518, 5540, 5561, 5582, 5604, 5625, 5647, 5668,
|
||||
5690, 5711, 5733, 5754, 5776, 5797, 5819, 5841,
|
||||
5862, 5884, 5905, 5927, 5949, 5970, 5992, 6014,
|
||||
6035, 6057, 6079, 6101, 6122, 6144, 6166, 6188,
|
||||
6209, 6231, 6253, 6275, 6297, 6318, 6340, 6362,
|
||||
6384, 6406, 6428, 6450, 6472, 6493, 6515, 6537,
|
||||
6559, 6581, 6603, 6625, 6647, 6669, 6691, 6713,
|
||||
6735, 6757, 6779, 6801, 6823, 6845, 6867, 6889,
|
||||
6911, 6934, 6956, 6978, 7000, 7022, 7044, 7066,
|
||||
7088, 7110, 7132, 7155, 7177, 7199, 7221, 7243,
|
||||
7265, 7288, 7310, 7332, 7354, 7376, 7398, 7421,
|
||||
7443, 7465, 7487, 7509, 7531, 7554, 7576, 7598,
|
||||
7620, 7643, 7665, 7687, 7709, 7731, 7754, 7776,
|
||||
7798, 7820, 7842, 7865, 7887, 7909, 7931, 7954,
|
||||
7976, 7998, 8020, 8042, 8065, 8087, 8109, 8131,
|
||||
8154, 8176, 8198, 8220, 8242, 8265, 8287, 8309,
|
||||
8331, 8353, 8376, 8398, 8420, 8442, 8464, 8487,
|
||||
8509, 8531, 8553, 8575, 8597, 8620, 8642, 8664,
|
||||
8686, 8708, 8730, 8752, 8775, 8797, 8819, 8841,
|
||||
8863, 8885, 8907, 8929, 8951, 8974, 8996, 9018,
|
||||
9040, 9062, 9084, 9106, 9128, 9150, 9172, 9194,
|
||||
9216, 9238, 9260, 9282, 9304, 9326, 9348, 9370,
|
||||
9392, 9414, 9436, 9458, 9479, 9501, 9523, 9545,
|
||||
9567, 9589, 9611, 9633, 9653, 9676, 9698, 9720,
|
||||
9742, 9763, 9784, 9806, 9829, 9851, 9872, 9893,
|
||||
9915, 9936, 9959, 9981, 10002, 10023, 10045, 10068,
|
||||
10088, 10110, 10132, 10152, 10175, 10196, 10217, 10239,
|
||||
10260, 10283, 10303, 10325, 10346, 10368, 10389, 10410,
|
||||
10431, 10453, 10474, 10496, 10517, 10538, 10560, 10581,
|
||||
10602, 10623, 10644, 10666, 10687, 10708, 10728, 10750,
|
||||
10772, 10792, 10814, 10834, 10856, 10876, 10898, 10918,
|
||||
10939, 10959, 10982, 11002, 11023, 11043, 11064, 11084,
|
||||
11107, 11127, 11148, 11168, 11189, 11209, 11231, 11251,
|
||||
11272, 11292, 11313, 11333, 11354, 11374, 11394, 11415,
|
||||
11436, 11457, 11477, 11498, 11518, 11538, 11559, 11578,
|
||||
11599, 11619, 11640, 11660, 11680, 11700, 11720, 11741,
|
||||
11761, 11780, 11801, 11821, 11839, 11860, 11880, 11900,
|
||||
11920, 11940, 11960, 11980, 11998, 12019, 12039, 12059,
|
||||
12079, 12097, 12118, 12137, 12157, 12176, 12195, 12215,
|
||||
12235, 12254, 12273, 12293, 12312, 12332, 12351, 12370,
|
||||
12390, 12408, 12427, 12448, 12466, 12485, 12504, 12524,
|
||||
12542, 12562, 12580, 12599, 12618, 12637, 12655, 12675,
|
||||
12694, 12712, 12731, 12750, 12768, 12787, 12806, 12823,
|
||||
12842, 12860, 12879, 12898, 12916, 12934, 12953, 12971,
|
||||
12989, 13008, 13026, 13044, 13062, 13080, 13098, 13116,
|
||||
13134, 13152, 13170, 13188, 13205, 13224, 13241, 13258,
|
||||
13277, 13294, 13312, 13330, 13347, 13365, 13383, 13399,
|
||||
13417, 13435, 13451, 13469, 13486, 13504, 13521, 13538,
|
||||
13556, 13572, 13589, 13607, 13623, 13641, 13657, 13673,
|
||||
13691, 13707, 13724, 13741, 13758, 13775, 13791, 13808,
|
||||
13823, 13840, 13857, 13873, 13890, 13906, 13923, 13939,
|
||||
13955, 13971, 13986, 14003, 14019, 14035, 14051, 14067,
|
||||
14082, 14099, 14115, 14130, 14146, 14161, 14177, 14192,
|
||||
14208, 14223, 14239, 14254, 14270, 14285, 14301, 14316,
|
||||
14330, 14346, 14361, 14376, 14391, 14406, 14420, 14435,
|
||||
14450, 14465, 14480, 14494, 14509, 14523, 14538, 14553,
|
||||
14567, 14582, 14595, 14610, 14625, 14638, 14653, 14668,
|
||||
14681, 14696, 14709, 14723, 14737, 14752, 14764, 14778,
|
||||
14793, 14806, 14819, 14833, 14846, 14860, 14874, 14887,
|
||||
14900, 14913, 14927, 14940, 14953, 14966, 14979, 14992,
|
||||
15004, 15017, 15031, 15043, 15056, 15067, 15081, 15094,
|
||||
15106, 15118, 15131, 15143, 15155, 15167, 15180, 15192,
|
||||
15205, 15216, 15228, 15240, 15252, 15264, 15276, 15287,
|
||||
15299, 15310, 15321, 15333, 15345, 15356, 15367, 15379,
|
||||
15390, 15401, 15412, 15423, 15433, 15446, 15456, 15467,
|
||||
15478, 15489, 15499, 15509, 15520, 15530, 15540, 15552,
|
||||
15562, 15572, 15582, 15592, 15602, 15613, 15623, 15633,
|
||||
15642, 15652, 15662, 15672, 15681, 15691, 15700, 15709,
|
||||
15719, 15729, 15738, 15747, 15756, 15765, 15774, 15783,
|
||||
15792, 15801, 15810, 15818, 15827, 15836, 15843, 15853,
|
||||
15861, 15870, 15877, 15886, 15894, 15903, 15910, 15918,
|
||||
15926, 15934, 15941, 15949, 15957, 15964, 15973, 15980,
|
||||
15988, 15995, 16002, 16009, 16015, 16023, 16030, 16038,
|
||||
16044, 16052, 16058, 16064, 16071, 16077, 16085, 16092,
|
||||
16097, 16104, 16109, 16116, 16122, 16128, 16133, 16140,
|
||||
16146, 16151, 16158, 16163, 16169, 16174, 16180, 16185,
|
||||
16191, 16196, 16201, 16206, 16211, 16216, 16220, 16225,
|
||||
16230, 16235, 16239, 16244, 16247, 16253, 16257, 16262,
|
||||
16265, 16269, 16274, 16278, 16282, 16285, 16290, 16293,
|
||||
16297, 16299, 16304, 16307, 16309, 16314, 16317, 16320,
|
||||
16322, 16326, 16329, 16331, 16335, 16337, 16340, 16342,
|
||||
16345, 16347, 16349, 16351, 16354, 16357, 16358, 16360,
|
||||
16361, 16364, 16366, 16366, 16369, 16370, 16371, 16373,
|
||||
16374, 16376, 16377, 16377, 16379, 16379, 16380, 16381,
|
||||
16381, 16381, 16382, 16383, 16384, 16384, 16384, 16384,
|
||||
};
|
||||
|
||||
static int16 cubic_spline_lut3[1024] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, -1, -1, -1, -1, -1, -2, -2,
|
||||
-2, -2, -2, -3, -3, -3, -4, -4,
|
||||
-4, -5, -5, -6, -6, -6, -7, -7,
|
||||
-8, -8, -9, -9, -10, -10, -11, -11,
|
||||
-12, -13, -13, -14, -14, -15, -16, -16,
|
||||
-17, -18, -19, -19, -20, -21, -22, -22,
|
||||
-23, -24, -25, -26, -26, -27, -28, -29,
|
||||
-30, -31, -32, -33, -34, -35, -36, -37,
|
||||
-38, -39, -40, -41, -42, -43, -44, -45,
|
||||
-46, -47, -48, -49, -51, -52, -53, -54,
|
||||
-55, -57, -58, -59, -60, -61, -63, -64,
|
||||
-65, -67, -68, -69, -70, -72, -73, -75,
|
||||
-76, -77, -79, -80, -82, -83, -84, -86,
|
||||
-87, -89, -90, -92, -93, -95, -96, -98,
|
||||
-99, -101, -102, -104, -106, -107, -109, -110,
|
||||
-112, -114, -115, -117, -119, -120, -122, -124,
|
||||
-125, -127, -129, -130, -132, -134, -136, -137,
|
||||
-139, -141, -143, -145, -146, -148, -150, -152,
|
||||
-154, -156, -157, -159, -161, -163, -165, -167,
|
||||
-169, -171, -173, -175, -176, -178, -180, -182,
|
||||
-184, -186, -188, -190, -192, -194, -196, -198,
|
||||
-200, -202, -205, -207, -209, -211, -213, -215,
|
||||
-217, -219, -221, -223, -225, -228, -230, -232,
|
||||
-234, -236, -238, -240, -243, -245, -247, -249,
|
||||
-251, -254, -256, -258, -260, -263, -265, -267,
|
||||
-269, -272, -274, -276, -278, -281, -283, -285,
|
||||
-288, -290, -292, -295, -297, -299, -302, -304,
|
||||
-306, -309, -311, -313, -316, -318, -320, -323,
|
||||
-325, -328, -330, -332, -335, -337, -340, -342,
|
||||
-345, -347, -349, -352, -354, -357, -359, -362,
|
||||
-364, -367, -369, -372, -374, -377, -379, -382,
|
||||
-384, -387, -389, -392, -394, -397, -399, -402,
|
||||
-404, -407, -409, -412, -414, -417, -419, -422,
|
||||
-424, -427, -430, -432, -435, -437, -440, -442,
|
||||
-445, -448, -450, -453, -455, -458, -461, -463,
|
||||
-466, -468, -471, -474, -476, -479, -481, -484,
|
||||
-487, -489, -492, -495, -497, -500, -502, -505,
|
||||
-508, -510, -513, -516, -518, -521, -523, -526,
|
||||
-529, -531, -534, -537, -539, -542, -545, -547,
|
||||
-550, -553, -555, -558, -561, -563, -566, -569,
|
||||
-571, -574, -577, -579, -582, -585, -587, -590,
|
||||
-593, -595, -598, -601, -603, -606, -609, -611,
|
||||
-614, -617, -619, -622, -625, -627, -630, -633,
|
||||
-635, -638, -641, -643, -646, -649, -651, -654,
|
||||
-657, -659, -662, -665, -667, -670, -672, -675,
|
||||
-678, -680, -683, -686, -688, -691, -694, -696,
|
||||
-699, -702, -704, -707, -709, -712, -715, -717,
|
||||
-720, -723, -725, -728, -730, -733, -736, -738,
|
||||
-741, -744, -746, -749, -751, -754, -757, -759,
|
||||
-762, -764, -767, -769, -772, -775, -777, -780,
|
||||
-782, -785, -787, -790, -793, -795, -798, -800,
|
||||
-803, -805, -808, -810, -813, -815, -818, -820,
|
||||
-823, -825, -828, -830, -833, -835, -838, -840,
|
||||
-843, -845, -848, -850, -853, -855, -858, -860,
|
||||
-863, -865, -867, -870, -872, -875, -877, -880,
|
||||
-882, -884, -887, -889, -892, -894, -896, -899,
|
||||
-901, -903, -906, -908, -911, -913, -915, -918,
|
||||
-920, -922, -924, -927, -929, -931, -934, -936,
|
||||
-938, -941, -943, -945, -947, -950, -952, -954,
|
||||
-956, -958, -961, -963, -965, -967, -969, -972,
|
||||
-974, -976, -978, -980, -982, -985, -987, -989,
|
||||
-991, -993, -995, -997, -999, -1002, -1004, -1006,
|
||||
-1008, -1010, -1012, -1014, -1016, -1018, -1020, -1022,
|
||||
-1024, -1026, -1028, -1030, -1032, -1034, -1036, -1038,
|
||||
-1040, -1042, -1044, -1046, -1047, -1049, -1051, -1053,
|
||||
-1055, -1057, -1059, -1061, -1062, -1064, -1066, -1068,
|
||||
-1070, -1071, -1073, -1075, -1077, -1079, -1080, -1082,
|
||||
-1084, -1085, -1087, -1089, -1091, -1092, -1094, -1096,
|
||||
-1097, -1099, -1101, -1102, -1104, -1105, -1107, -1109,
|
||||
-1110, -1112, -1113, -1115, -1116, -1118, -1119, -1121,
|
||||
-1122, -1124, -1125, -1127, -1128, -1130, -1131, -1133,
|
||||
-1134, -1135, -1137, -1138, -1140, -1141, -1142, -1144,
|
||||
-1145, -1146, -1148, -1149, -1150, -1151, -1153, -1154,
|
||||
-1155, -1156, -1158, -1159, -1160, -1161, -1162, -1163,
|
||||
-1165, -1166, -1167, -1168, -1169, -1170, -1171, -1172,
|
||||
-1173, -1174, -1175, -1176, -1177, -1178, -1179, -1180,
|
||||
-1181, -1182, -1183, -1184, -1185, -1186, -1187, -1187,
|
||||
-1188, -1189, -1190, -1191, -1192, -1192, -1193, -1194,
|
||||
-1195, -1195, -1196, -1197, -1197, -1198, -1199, -1199,
|
||||
-1200, -1201, -1201, -1202, -1202, -1203, -1204, -1204,
|
||||
-1205, -1205, -1206, -1206, -1207, -1207, -1207, -1208,
|
||||
-1208, -1209, -1209, -1209, -1210, -1210, -1210, -1211,
|
||||
-1211, -1211, -1211, -1212, -1212, -1212, -1212, -1213,
|
||||
-1213, -1213, -1213, -1213, -1213, -1213, -1213, -1214,
|
||||
-1214, -1214, -1214, -1214, -1214, -1214, -1214, -1213,
|
||||
-1213, -1213, -1213, -1213, -1213, -1213, -1213, -1212,
|
||||
-1212, -1212, -1212, -1212, -1211, -1211, -1211, -1210,
|
||||
-1210, -1210, -1209, -1209, -1208, -1208, -1208, -1207,
|
||||
-1207, -1206, -1206, -1205, -1205, -1204, -1204, -1203,
|
||||
-1202, -1202, -1201, -1200, -1200, -1199, -1198, -1198,
|
||||
-1197, -1196, -1195, -1195, -1194, -1193, -1192, -1191,
|
||||
-1190, -1189, -1188, -1187, -1187, -1186, -1185, -1184,
|
||||
-1182, -1181, -1180, -1179, -1178, -1177, -1176, -1175,
|
||||
-1174, -1172, -1171, -1170, -1169, -1167, -1166, -1165,
|
||||
-1163, -1162, -1161, -1159, -1158, -1156, -1155, -1153,
|
||||
-1152, -1150, -1149, -1147, -1146, -1144, -1143, -1141,
|
||||
-1139, -1138, -1136, -1134, -1133, -1131, -1129, -1127,
|
||||
-1125, -1124, -1122, -1120, -1118, -1116, -1114, -1112,
|
||||
-1110, -1108, -1106, -1104, -1102, -1100, -1098, -1096,
|
||||
-1094, -1092, -1089, -1087, -1085, -1083, -1080, -1078,
|
||||
-1076, -1074, -1071, -1069, -1066, -1064, -1062, -1059,
|
||||
-1057, -1054, -1052, -1049, -1047, -1044, -1041, -1039,
|
||||
-1036, -1033, -1031, -1028, -1025, -1022, -1020, -1017,
|
||||
-1014, -1011, -1008, -1005, -1002, -999, -997, -994,
|
||||
-991, -987, -984, -981, -978, -975, -972, -969,
|
||||
-966, -962, -959, -956, -953, -949, -946, -943,
|
||||
-939, -936, -932, -929, -925, -922, -918, -915,
|
||||
-911, -908, -904, -900, -897, -893, -889, -886,
|
||||
-882, -878, -874, -870, -866, -863, -859, -855,
|
||||
-851, -847, -843, -839, -835, -831, -826, -822,
|
||||
-818, -814, -810, -806, -801, -797, -793, -788,
|
||||
-784, -780, -775, -771, -766, -762, -757, -753,
|
||||
-748, -744, -739, -734, -730, -725, -720, -715,
|
||||
-711, -706, -701, -696, -691, -686, -682, -677,
|
||||
-672, -667, -662, -656, -651, -646, -641, -636,
|
||||
-631, -626, -620, -615, -610, -604, -599, -594,
|
||||
-588, -583, -577, -572, -566, -561, -555, -550,
|
||||
-544, -538, -533, -527, -521, -515, -510, -504,
|
||||
-498, -492, -486, -480, -474, -468, -462, -456,
|
||||
-450, -444, -438, -432, -425, -419, -413, -407,
|
||||
-400, -394, -388, -381, -375, -368, -362, -355,
|
||||
-349, -342, -336, -329, -322, -316, -309, -302,
|
||||
-295, -289, -282, -275, -268, -261, -254, -247,
|
||||
-240, -233, -226, -219, -212, -205, -198, -190,
|
||||
-183, -176, -169, -161, -154, -146, -139, -132,
|
||||
-124, -117, -109, -101, -94, -86, -78, -71,
|
||||
-63, -55, -47, -40, -32, -24, -16, -8,
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,116 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* S3M packed pattern macros */
|
||||
#define S3M_EOR 0 /* End of row */
|
||||
#define S3M_CH_MASK 0x1f /* Channel */
|
||||
#define S3M_NI_FOLLOW 0x20 /* Note and instrument follow */
|
||||
#define S3M_VOL_FOLLOWS 0x40 /* Volume follows */
|
||||
#define S3M_FX_FOLLOWS 0x80 /* Effect and parameter follow */
|
||||
|
||||
/* S3M channel info macros */
|
||||
#define S3M_CH_ON 0x80 /* Psi says it's bit 8, I'll assume bit 7 */
|
||||
#define S3M_CH_OFF 0xff
|
||||
#define S3M_CH_PAN 0x7f /* Left/Right */
|
||||
|
||||
/* S3M channel pan macros */
|
||||
#define S3M_PAN_SET 0x20
|
||||
#define S3M_PAN_MASK 0x0f
|
||||
|
||||
/* S3M flags */
|
||||
#define S3M_ST2_VIB 0x01 /* Not recognized */
|
||||
#define S3M_ST2_TEMPO 0x02 /* Not recognized */
|
||||
#define S3M_AMIGA_SLIDE 0x04 /* Not recognized */
|
||||
#define S3M_VOL_OPT 0x08 /* Not recognized */
|
||||
#define S3M_AMIGA_RANGE 0x10
|
||||
#define S3M_SB_FILTER 0x20 /* Not recognized */
|
||||
#define S3M_ST300_VOLS 0x40
|
||||
#define S3M_CUSTOM_DATA 0x80 /* Not recognized */
|
||||
|
||||
/* S3M Adlib instrument types */
|
||||
#define S3M_INST_SAMPLE 0x01
|
||||
#define S3M_INST_AMEL 0x02
|
||||
#define S3M_INST_ABD 0x03
|
||||
#define S3M_INST_ASNARE 0x04
|
||||
#define S3M_INST_ATOM 0x05
|
||||
#define S3M_INST_ACYM 0x06
|
||||
#define S3M_INST_AHIHAT 0x07
|
||||
|
||||
struct s3m_file_header {
|
||||
uint8 name[28]; /* Song name */
|
||||
uint8 doseof; /* 0x1a */
|
||||
uint8 type; /* File type */
|
||||
uint8 rsvd1[2]; /* Reserved */
|
||||
uint16 ordnum; /* Number of orders (must be even) */
|
||||
uint16 insnum; /* Number of instruments */
|
||||
uint16 patnum; /* Number of patterns */
|
||||
uint16 flags; /* Flags */
|
||||
uint16 version; /* Tracker ID and version */
|
||||
uint16 ffi; /* File format information */
|
||||
uint32 magic; /* 'SCRM' */
|
||||
uint8 gv; /* Global volume */
|
||||
uint8 is; /* Initial speed */
|
||||
uint8 it; /* Initial tempo */
|
||||
uint8 mv; /* Master volume */
|
||||
uint8 uc; /* Ultra click removal */
|
||||
uint8 dp; /* Default pan positions if 0xfc */
|
||||
uint8 rsvd2[8]; /* Reserved */
|
||||
uint16 special; /* Ptr to special custom data */
|
||||
uint8 chset[32]; /* Channel settings */
|
||||
};
|
||||
|
||||
struct s3m_instrument_header {
|
||||
uint8 dosname[13]; /* DOS file name */
|
||||
uint16 memseg; /* Pointer to sample data */
|
||||
uint32 length; /* Length */
|
||||
uint32 loopbeg; /* Loop begin */
|
||||
uint32 loopend; /* Loop end */
|
||||
uint8 vol; /* Volume */
|
||||
uint8 rsvd1; /* Reserved */
|
||||
uint8 pack; /* Packing type (not used) */
|
||||
uint8 flags; /* Loop/stereo/16bit samples flags */
|
||||
uint16 c2spd; /* C 4 speed */
|
||||
uint16 rsvd2; /* Reserved */
|
||||
uint8 rsvd3[4]; /* Reserved */
|
||||
uint16 int_gp; /* Internal - GUS pointer */
|
||||
uint16 int_512; /* Internal - SB pointer */
|
||||
uint32 int_last; /* Internal - SB index */
|
||||
uint8 name[28]; /* Instrument name */
|
||||
uint32 magic; /* 'SCRS' */
|
||||
};
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
struct s3m_adlib_header {
|
||||
uint8 dosname[12]; /* DOS file name */
|
||||
uint8 rsvd1[3]; /* 0x00 0x00 0x00 */
|
||||
uint8 reg[12]; /* Adlib registers */
|
||||
uint8 vol;
|
||||
uint8 dsk;
|
||||
uint8 rsvd2[2];
|
||||
uint16 c2spd; /* C 4 speed */
|
||||
uint16 rsvd3; /* Reserved */
|
||||
uint8 rsvd4[12]; /* Reserved */
|
||||
uint8 name[28]; /* Instrument name */
|
||||
uint32 magic; /* 'SCRI' */
|
||||
};
|
||||
#endif
|
||||
|
|
@ -1,661 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tue, 30 Jun 1998 20:23:11 +0200
|
||||
* Reported by John v/d Kamp <blade_@dds.nl>:
|
||||
* I have this song from Purple Motion called wcharts.s3m, the global
|
||||
* volume was set to 0, creating a devide by 0 error in xmp. There should
|
||||
* be an extra test if it's 0 or not.
|
||||
*
|
||||
* Claudio's fix: global volume ignored
|
||||
*/
|
||||
|
||||
/*
|
||||
* Sat, 29 Aug 1998 18:50:43 -0500 (CDT)
|
||||
* Reported by Joel Jordan <scriber@usa.net>:
|
||||
* S3M files support tempos outside the ranges defined by xmp (that is,
|
||||
* the MOD/XM tempo ranges). S3M's can have tempos from 0 to 255 and speeds
|
||||
* from 0 to 255 as well, since these are handled with separate effects
|
||||
* unlike the MOD format. This becomes an issue in such songs as Skaven's
|
||||
* "Catch that Goblin", which uses speeds above 0x1f.
|
||||
*
|
||||
* Claudio's fix: FX_S3M_SPEED added. S3M supports speeds from 0 to 255 and
|
||||
* tempos from 32 to 255 (S3M speed == xmp tempo, S3M tempo == xmp BPM).
|
||||
*/
|
||||
|
||||
/* Wed, 21 Oct 1998 15:03:44 -0500 Geoff Reedy <vader21@imsa.edu>
|
||||
* It appears that xmp has issues loading/playing a specific instrument
|
||||
* used in LUCCA.S3M.
|
||||
* (Fixed by Hipolito in xmp-2.0.0dev34)
|
||||
*/
|
||||
|
||||
/*
|
||||
* From http://code.pui.ch/2007/02/18/turn-demoscene-modules-into-mp3s/
|
||||
* The only flaw I noticed [in xmp] is a problem with portamento in Purple
|
||||
* Motion's second reality soundtrack (1:06-1:17)
|
||||
*
|
||||
* Claudio's note: that's a dissonant beating between channels 6 and 7
|
||||
* starting at pos12, caused by pitchbending effect F25.
|
||||
*/
|
||||
|
||||
/*
|
||||
* From: Ralf Hoffmann <ralf@boomerangsworld.de>
|
||||
* Date: Wed, 26 Sep 2007 17:12:41 +0200
|
||||
* ftp://ftp.scenesp.org/pub/compilations/modplanet/normal/bonuscd/artists/
|
||||
* Iq/return%20of%20litmus.s3m doesn't start playing, just uses 100% cpu,
|
||||
* the number of patterns is unusually high
|
||||
*
|
||||
* Claudio's fix: this module seems to be a bad conversion, bad rip or
|
||||
* simply corrupted since it has many instances of 0x87 instead of 0x00
|
||||
* in the module and instrument headers. I'm adding a simple workaround
|
||||
* to be able to load/play the module as is, see the fix87() macro below.
|
||||
*/
|
||||
|
||||
#include "loader.h"
|
||||
#include "s3m.h"
|
||||
#include "period.h"
|
||||
|
||||
#define MAGIC_SCRM MAGIC4('S','C','R','M')
|
||||
#define MAGIC_SCRI MAGIC4('S','C','R','I')
|
||||
#define MAGIC_SCRS MAGIC4('S','C','R','S')
|
||||
|
||||
static int s3m_test(HIO_HANDLE *, char *, const int);
|
||||
static int s3m_load(struct module_data *, HIO_HANDLE *, const int);
|
||||
|
||||
extern const struct format_loader libxmp_loader_s3m;
|
||||
const struct format_loader libxmp_loader_s3m = {
|
||||
"Scream Tracker 3",
|
||||
s3m_test,
|
||||
s3m_load
|
||||
};
|
||||
|
||||
static int s3m_test(HIO_HANDLE *f, char *t, const int start)
|
||||
{
|
||||
hio_seek(f, start + 44, SEEK_SET);
|
||||
if (hio_read32b(f) != MAGIC_SCRM)
|
||||
return -1;
|
||||
|
||||
hio_seek(f, start + 29, SEEK_SET);
|
||||
if (hio_read8(f) != 0x10)
|
||||
return -1;
|
||||
|
||||
hio_seek(f, start + 0, SEEK_SET);
|
||||
libxmp_read_title(f, t, 28);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NONE 0xff
|
||||
#define FX_S3M_EXTENDED 0xfe
|
||||
|
||||
#define fix87(x) do { \
|
||||
int i; for (i = 0; i < sizeof(x); i++) { \
|
||||
if (*((uint8 *)&x + i) == 0x87) *((uint8 *)&x + i) = 0; } \
|
||||
} while (0)
|
||||
|
||||
/* Effect conversion table */
|
||||
static const uint8 fx[] = {
|
||||
NONE,
|
||||
FX_S3M_SPEED, /* Axx Set speed to xx (the default is 06) */
|
||||
FX_JUMP, /* Bxx Jump to order xx (hexadecimal) */
|
||||
FX_BREAK, /* Cxx Break pattern to row xx (decimal) */
|
||||
FX_VOLSLIDE, /* Dxy Volume slide down by y/up by x */
|
||||
FX_PORTA_DN, /* Exx Slide down by xx */
|
||||
FX_PORTA_UP, /* Fxx Slide up by xx */
|
||||
FX_TONEPORTA, /* Gxx Tone portamento with speed xx */
|
||||
FX_VIBRATO, /* Hxy Vibrato with speed x and depth y */
|
||||
FX_TREMOR, /* Ixy Tremor with ontime x and offtime y */
|
||||
FX_S3M_ARPEGGIO, /* Jxy Arpeggio with halfnote additions */
|
||||
FX_VIBRA_VSLIDE, /* Kxy Dual command: H00 and Dxy */
|
||||
FX_TONE_VSLIDE, /* Lxy Dual command: G00 and Dxy */
|
||||
NONE,
|
||||
NONE,
|
||||
FX_OFFSET, /* Oxy Set sample offset */
|
||||
NONE,
|
||||
FX_MULTI_RETRIG, /* Qxy Retrig (+volumeslide) note */
|
||||
FX_TREMOLO, /* Rxy Tremolo with speed x and depth y */
|
||||
FX_S3M_EXTENDED, /* Sxx (misc effects) */
|
||||
FX_S3M_BPM, /* Txx Tempo = xx (hex) */
|
||||
FX_FINE_VIBRATO, /* Uxx Fine vibrato */
|
||||
FX_GLOBALVOL, /* Vxx Set global volume */
|
||||
NONE,
|
||||
FX_SETPAN, /* Xxx Set pan */
|
||||
NONE,
|
||||
NONE
|
||||
};
|
||||
|
||||
/* Effect translation */
|
||||
static void xlat_fx(int c, struct xmp_event *e)
|
||||
{
|
||||
uint8 h = MSN(e->fxp), l = LSN(e->fxp);
|
||||
|
||||
if (e->fxt > 26) {
|
||||
D_(D_WARN "invalid effect %02x", e->fxt);
|
||||
e->fxt = e->fxp = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e->fxt = fx[e->fxt]) {
|
||||
case FX_S3M_BPM:
|
||||
if (e->fxp < 0x20) {
|
||||
e->fxp = e->fxt = 0;
|
||||
}
|
||||
break;
|
||||
case FX_S3M_EXTENDED: /* Extended effects */
|
||||
e->fxt = FX_EXTENDED;
|
||||
switch (h) {
|
||||
case 0x1: /* Glissando */
|
||||
e->fxp = LSN(e->fxp) | (EX_GLISS << 4);
|
||||
break;
|
||||
case 0x2: /* Finetune */
|
||||
e->fxp =
|
||||
((LSN(e->fxp) - 8) & 0x0f) | (EX_FINETUNE << 4);
|
||||
break;
|
||||
case 0x3: /* Vibrato wave */
|
||||
e->fxp = LSN(e->fxp) | (EX_VIBRATO_WF << 4);
|
||||
break;
|
||||
case 0x4: /* Tremolo wave */
|
||||
e->fxp = LSN(e->fxp) | (EX_TREMOLO_WF << 4);
|
||||
break;
|
||||
case 0x5:
|
||||
case 0x6:
|
||||
case 0x7:
|
||||
case 0x9:
|
||||
case 0xa: /* Ignore */
|
||||
e->fxt = e->fxp = 0;
|
||||
break;
|
||||
case 0x8: /* Set pan */
|
||||
e->fxt = FX_SETPAN;
|
||||
e->fxp = l << 4;
|
||||
break;
|
||||
case 0xb: /* Pattern loop */
|
||||
e->fxp = LSN(e->fxp) | (EX_PATTERN_LOOP << 4);
|
||||
break;
|
||||
case 0xc:
|
||||
if (!l)
|
||||
e->fxt = e->fxp = 0;
|
||||
}
|
||||
break;
|
||||
case FX_SETPAN:
|
||||
/* Saga Musix says: "The X effect in S3M files is not
|
||||
* exclusive to IT and clones. You will find tons of S3Ms made
|
||||
* with ST3 itself using this effect (and relying on an
|
||||
* external player being used). X in S3M also behaves
|
||||
* differently than in IT, which your code does not seem to
|
||||
* handle: X00 - X80 is left... right, XA4 is surround (like
|
||||
* S91 in IT), other values are not supposed to do anything.
|
||||
*/
|
||||
if (e->fxp == 0xa4) {
|
||||
// surround
|
||||
e->fxt = FX_SURROUND;
|
||||
e->fxp = 1;
|
||||
} else {
|
||||
int pan = ((int)e->fxp) << 1;
|
||||
if (pan > 0xff) {
|
||||
pan = 0xff;
|
||||
}
|
||||
e->fxp = pan;
|
||||
}
|
||||
break;
|
||||
case NONE: /* No effect */
|
||||
e->fxt = e->fxp = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int s3m_load(struct module_data *m, HIO_HANDLE * f, const int start)
|
||||
{
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int c, r, i;
|
||||
struct xmp_event *event = 0, dummy;
|
||||
struct s3m_file_header sfh;
|
||||
struct s3m_instrument_header sih;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
struct s3m_adlib_header sah;
|
||||
char tracker_name[40];
|
||||
int quirk87 = 0;
|
||||
#endif
|
||||
int pat_len;
|
||||
uint8 n, b;
|
||||
uint16 *pp_ins; /* Parapointers to instruments */
|
||||
uint16 *pp_pat; /* Parapointers to patterns */
|
||||
int ret;
|
||||
uint8 buf[96]
|
||||
|
||||
LOAD_INIT();
|
||||
|
||||
if (hio_read(buf, 1, 96, f) != 96) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(&sfh.name, buf, 28); /* Song name */
|
||||
sfh.type = buf[30]; /* File type */
|
||||
sfh.ordnum = readmem16l(buf + 32); /* Number of orders (must be even) */
|
||||
sfh.insnum = readmem16l(buf + 34); /* Number of instruments */
|
||||
sfh.patnum = readmem16l(buf + 36); /* Number of patterns */
|
||||
sfh.flags = readmem16l(buf + 38); /* Flags */
|
||||
sfh.version = readmem16l(buf + 40); /* Tracker ID and version */
|
||||
sfh.ffi = readmem16l(buf + 42); /* File format information */
|
||||
|
||||
/* Sanity check */
|
||||
if (sfh.ffi != 1 && sfh.ffi != 2) {
|
||||
goto err;
|
||||
}
|
||||
if (sfh.ordnum > 255 || sfh.insnum > 255 || sfh.patnum > 255) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
sfh.magic = readmem32b(buf + 44); /* 'SCRM' */
|
||||
sfh.gv = buf[48]; /* Global volume */
|
||||
sfh.is = buf[49]; /* Initial speed */
|
||||
sfh.it = buf[50]; /* Initial tempo */
|
||||
sfh.mv = buf[51]; /* Master volume */
|
||||
sfh.uc = buf[52]; /* Ultra click removal */
|
||||
sfh.dp = buf[53]; /* Default pan positions if 0xfc */
|
||||
/* 54-61 reserved */
|
||||
sfh.special = readmem16l(buf + 62); /* Ptr to special custom data */
|
||||
memcpy(sfh.chset, buf + 64, 32); /* Channel settings */
|
||||
|
||||
if (sfh.magic != MAGIC_SCRM) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
/* S3M anomaly in return_of_litmus.s3m */
|
||||
if (sfh.version == 0x1301 && sfh.name[27] == 0x87)
|
||||
quirk87 = 1;
|
||||
|
||||
if (quirk87) {
|
||||
fix87(sfh.name);
|
||||
fix87(sfh.patnum);
|
||||
fix87(sfh.flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
libxmp_copy_adjust(mod->name, sfh.name, 28);
|
||||
|
||||
pp_ins = (uint16 *)calloc(2, sfh.insnum);
|
||||
if (pp_ins == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
pp_pat = (uint16 *)calloc(2, sfh.patnum);
|
||||
if (pp_pat == NULL) {
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (sfh.flags & S3M_AMIGA_RANGE) {
|
||||
m->period_type = PERIOD_MODRNG;
|
||||
}
|
||||
if (sfh.flags & S3M_ST300_VOLS) {
|
||||
m->quirk |= QUIRK_VSALL;
|
||||
}
|
||||
/* m->volbase = 4096 / sfh.gv; */
|
||||
mod->spd = sfh.is;
|
||||
mod->bpm = sfh.it;
|
||||
mod->chn = 0;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (sfh.chset[i] == S3M_CH_OFF)
|
||||
continue;
|
||||
|
||||
mod->chn = i + 1;
|
||||
|
||||
if (sfh.mv & 0x80) { /* stereo */
|
||||
int x = sfh.chset[i] & S3M_CH_PAN;
|
||||
mod->xxc[i].pan = (x & 0x0f) < 8 ? 0x30 : 0xc0;
|
||||
} else {
|
||||
mod->xxc[i].pan = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
if (sfh.ordnum <= XMP_MAX_MOD_LENGTH) {
|
||||
mod->len = sfh.ordnum;
|
||||
if (hio_read(mod->xxo, 1, mod->len, f) != mod->len) {
|
||||
goto err3;
|
||||
}
|
||||
} else {
|
||||
mod->len = XMP_MAX_MOD_LENGTH;
|
||||
if (hio_read(mod->xxo, 1, mod->len, f) != mod->len) {
|
||||
goto err3;
|
||||
}
|
||||
if (hio_seek(f, sfh.ordnum - XMP_MAX_MOD_LENGTH, SEEK_CUR) < 0) {
|
||||
goto err3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't trust sfh.patnum */
|
||||
mod->pat = -1;
|
||||
for (i = 0; i < mod->len; ++i) {
|
||||
if (mod->xxo[i] < 0xfe && mod->xxo[i] > mod->pat) {
|
||||
mod->pat = mod->xxo[i];
|
||||
}
|
||||
}
|
||||
mod->pat++;
|
||||
if (mod->pat > sfh.patnum) {
|
||||
mod->pat = sfh.patnum;
|
||||
}
|
||||
if (mod->pat == 0) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
mod->trk = mod->pat * mod->chn;
|
||||
/* Load and convert header */
|
||||
mod->ins = sfh.insnum;
|
||||
mod->smp = mod->ins;
|
||||
|
||||
for (i = 0; i < sfh.insnum; i++) {
|
||||
pp_ins[i] = hio_read16l(f);
|
||||
}
|
||||
|
||||
for (i = 0; i < sfh.patnum; i++) {
|
||||
pp_pat[i] = hio_read16l(f);
|
||||
}
|
||||
|
||||
/* Default pan positions */
|
||||
|
||||
for (i = 0, sfh.dp -= 0xfc; !sfh.dp /* && n */ && (i < 32); i++) {
|
||||
uint8 x = hio_read8(f);
|
||||
if (x & S3M_PAN_SET) {
|
||||
mod->xxc[i].pan = (x << 4) & 0xff;
|
||||
} else {
|
||||
mod->xxc[i].pan =
|
||||
sfh.mv % 0x80 ? 0x30 + 0xa0 * (i & 1) : 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
|
||||
if (sfh.version == 0x1300) {
|
||||
m->quirk |= QUIRK_VSALL;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
switch (sfh.version >> 12) {
|
||||
case 1:
|
||||
snprintf(tracker_name, 40, "Scream Tracker %d.%02x",
|
||||
(sfh.version & 0x0f00) >> 8, sfh.version & 0xff);
|
||||
m->quirk |= QUIRK_ST3BUGS;
|
||||
break;
|
||||
case 2:
|
||||
snprintf(tracker_name, 40, "Imago Orpheus %d.%02x",
|
||||
(sfh.version & 0x0f00) >> 8, sfh.version & 0xff);
|
||||
break;
|
||||
case 3:
|
||||
if (sfh.version == 0x3216) {
|
||||
strcpy(tracker_name, "Impulse Tracker 2.14v3");
|
||||
} else if (sfh.version == 0x3217) {
|
||||
strcpy(tracker_name, "Impulse Tracker 2.14v5");
|
||||
} else {
|
||||
snprintf(tracker_name, 40, "Impulse Tracker %d.%02x",
|
||||
(sfh.version & 0x0f00) >> 8,
|
||||
sfh.version & 0xff);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
snprintf(tracker_name, 40, "OpenMPT %d.%02x",
|
||||
(sfh.version & 0x0f00) >> 8, sfh.version & 0xff);
|
||||
m->quirk |= QUIRK_ST3BUGS;
|
||||
break;
|
||||
case 4:
|
||||
if (sfh.version != 0x4100) {
|
||||
snprintf(tracker_name, 40, "Schism Tracker %d.%02x",
|
||||
(sfh.version & 0x0f00) >> 8,
|
||||
sfh.version & 0xff);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case 6:
|
||||
snprintf(tracker_name, 40, "BeRoTracker %d.%02x",
|
||||
(sfh.version & 0x0f00) >> 8, sfh.version & 0xff);
|
||||
break;
|
||||
default:
|
||||
snprintf(tracker_name, 40, "unknown (%04x)", sfh.version);
|
||||
}
|
||||
|
||||
libxmp_set_type(m, "%s S3M", tracker_name);
|
||||
#else
|
||||
libxmp_set_type(m, "Scream Tracker 3");
|
||||
m->quirk |= QUIRK_ST3BUGS;
|
||||
#endif
|
||||
|
||||
MODULE_INFO();
|
||||
|
||||
if (libxmp_init_pattern(mod) < 0)
|
||||
goto err3;
|
||||
|
||||
/* Read patterns */
|
||||
|
||||
D_(D_INFO "Stored patterns: %d", mod->pat);
|
||||
|
||||
for (i = 0; i < mod->pat; i++) {
|
||||
if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0)
|
||||
goto err3;
|
||||
|
||||
if (pp_pat[i] == 0)
|
||||
continue;
|
||||
|
||||
hio_seek(f, start + pp_pat[i] * 16, SEEK_SET);
|
||||
r = 0;
|
||||
pat_len = hio_read16l(f) - 2;
|
||||
|
||||
while (pat_len >= 0 && r < mod->xxp[i]->rows) {
|
||||
b = hio_read8(f);
|
||||
|
||||
if (hio_error(f)) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
if (b == S3M_EOR) {
|
||||
r++;
|
||||
continue;
|
||||
}
|
||||
|
||||
c = b & S3M_CH_MASK;
|
||||
event = c >= mod->chn ? &dummy : &EVENT(i, c, r);
|
||||
|
||||
if (b & S3M_NI_FOLLOW) {
|
||||
switch (n = hio_read8(f)) {
|
||||
case 255:
|
||||
n = 0;
|
||||
break; /* Empty note */
|
||||
case 254:
|
||||
n = XMP_KEY_OFF;
|
||||
break; /* Key off */
|
||||
default:
|
||||
n = 13 + 12 * MSN(n) + LSN(n);
|
||||
}
|
||||
event->note = n;
|
||||
event->ins = hio_read8(f);
|
||||
pat_len -= 2;
|
||||
}
|
||||
|
||||
if (b & S3M_VOL_FOLLOWS) {
|
||||
event->vol = hio_read8(f) + 1;
|
||||
pat_len--;
|
||||
}
|
||||
|
||||
if (b & S3M_FX_FOLLOWS) {
|
||||
event->fxt = hio_read8(f);
|
||||
event->fxp = hio_read8(f);
|
||||
xlat_fx(c, event);
|
||||
|
||||
pat_len -= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
D_(D_INFO "Stereo enabled: %s", sfh.mv & 0x80 ? "yes" : "no");
|
||||
D_(D_INFO "Pan settings: %s", sfh.dp ? "no" : "yes");
|
||||
|
||||
if (libxmp_init_instrument(m) < 0)
|
||||
goto err3;
|
||||
|
||||
/* Read and convert instruments and samples */
|
||||
|
||||
D_(D_INFO "Instruments: %d", mod->ins);
|
||||
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
struct xmp_instrument *xxi = &mod->xxi[i];
|
||||
struct xmp_sample *xxs = &mod->xxs[i];
|
||||
struct xmp_subinstrument *sub;
|
||||
|
||||
xxi->sub = (struct xmp_subinstrument *)calloc(sizeof(struct xmp_subinstrument), 1);
|
||||
if (xxi->sub == NULL) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
sub = &xxi->sub[0];
|
||||
|
||||
hio_seek(f, start + pp_ins[i] * 16, SEEK_SET);
|
||||
sub->pan = 0x80;
|
||||
sub->sid = i;
|
||||
|
||||
if (hio_read(buf, 1, 80, f) != 80) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
if (buf[0] >= 2) {
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
/* OPL2 FM instrument */
|
||||
|
||||
memcpy(sah.dosname, buf + 1, 12); /* DOS file name */
|
||||
memcpy(sah.reg, buf + 16, 12); /* Adlib registers */
|
||||
sah.vol = buf[28];
|
||||
sah.dsk = buf[29];
|
||||
sah.c2spd = readmem16l(buf + 32); /* C4 speed */
|
||||
memcpy(sah.name, buf + 48, 28); /* Instrument name */
|
||||
sah.magic = readmem32b(buf + 76); /* 'SCRI' */
|
||||
|
||||
if (sah.magic != MAGIC_SCRI) {
|
||||
D_(D_CRIT "error: FM instrument magic");
|
||||
goto err3;
|
||||
}
|
||||
sah.magic = 0;
|
||||
|
||||
libxmp_instrument_name(mod, i, sah.name, 28);
|
||||
|
||||
xxi->nsm = 1;
|
||||
sub->vol = sah.vol;
|
||||
libxmp_c2spd_to_note(sah.c2spd, &sub->xpo, &sub->fin);
|
||||
sub->xpo += 12;
|
||||
ret =
|
||||
libxmp_load_sample(m, f, SAMPLE_FLAG_ADLIB, xxs,
|
||||
(char *)&sah.reg);
|
||||
if (ret < 0)
|
||||
goto err3;
|
||||
|
||||
D_(D_INFO "[%2X] %-28.28s", i, xxi->name);
|
||||
|
||||
continue;
|
||||
#else
|
||||
goto err3;
|
||||
#endif
|
||||
}
|
||||
|
||||
memcpy(sih.dosname, buf + 1, 13); /* DOS file name */
|
||||
sih.memseg = readmem16l(buf + 14); /* Pointer to sample data */
|
||||
sih.length = readmem32l(buf + 16); /* Length */
|
||||
|
||||
#if 0
|
||||
/* ST3 limit */
|
||||
if ((sfh.version >> 12) == 1 && sih.length > 64000)
|
||||
sih.length = 64000;
|
||||
#endif
|
||||
|
||||
if (sih.length > MAX_SAMPLE_SIZE) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
sih.loopbeg = readmem32l(buf + 20); /* Loop begin */
|
||||
sih.loopend = readmem32l(buf + 24); /* Loop end */
|
||||
sih.vol = buf[28]; /* Volume */
|
||||
sih.pack = buf[30]; /* Packing type (not used) */
|
||||
sih.flags = buf[31]; /* Loop/stereo/16bit flags */
|
||||
sih.c2spd = readmem16l(buf + 32); /* C4 speed */
|
||||
memcpy(sih.name, buf + 48, 28); /* Instrument name */
|
||||
sih.magic = readmem32b(buf + 76); /* 'SCRS' */
|
||||
|
||||
if (buf[0] == 1 && sih.magic != MAGIC_SCRS) {
|
||||
D_(D_CRIT "error: instrument magic");
|
||||
goto err3;
|
||||
}
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (quirk87) {
|
||||
fix87(sih.length);
|
||||
fix87(sih.loopbeg);
|
||||
fix87(sih.loopend);
|
||||
fix87(sih.flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
xxs->len = sih.length;
|
||||
xxi->nsm = sih.length > 0 ? 1 : 0;
|
||||
xxs->lps = sih.loopbeg;
|
||||
xxs->lpe = sih.loopend;
|
||||
|
||||
xxs->flg = sih.flags & 1 ? XMP_SAMPLE_LOOP : 0;
|
||||
|
||||
if (sih.flags & 4) {
|
||||
xxs->flg |= XMP_SAMPLE_16BIT;
|
||||
}
|
||||
|
||||
sub->vol = sih.vol;
|
||||
sih.magic = 0;
|
||||
|
||||
libxmp_instrument_name(mod, i, sih.name, 28);
|
||||
|
||||
D_(D_INFO "[%2X] %-28.28s %04x%c%04x %04x %c V%02x %5d",
|
||||
i, mod->xxi[i].name, mod->xxs[i].len,
|
||||
xxs->flg & XMP_SAMPLE_16BIT ? '+' : ' ',
|
||||
xxs->lps, mod->xxs[i].lpe,
|
||||
xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ', sub->vol, sih.c2spd);
|
||||
|
||||
libxmp_c2spd_to_note(sih.c2spd, &sub->xpo, &sub->fin);
|
||||
|
||||
if (hio_seek(f, start + 16L * sih.memseg, SEEK_SET) < 0) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
ret = libxmp_load_sample(m, f, sfh.ffi == 1 ? 0 : SAMPLE_FLAG_UNS,
|
||||
xxs, NULL);
|
||||
if (ret < 0) {
|
||||
goto err3;
|
||||
}
|
||||
}
|
||||
|
||||
free(pp_pat);
|
||||
free(pp_ins);
|
||||
|
||||
m->quirk |= QUIRKS_ST3 | QUIRK_ARPMEM;
|
||||
m->read_event_type = READ_EVENT_ST3;
|
||||
|
||||
return 0;
|
||||
|
||||
err3:
|
||||
free(pp_pat);
|
||||
err2:
|
||||
free(pp_ins);
|
||||
err:
|
||||
return -1;
|
||||
}
|
|
@ -1,417 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "loader.h"
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
|
||||
/*
|
||||
* From the Audio File Formats (version 2.5)
|
||||
* Submitted-by: Guido van Rossum <guido@cwi.nl>
|
||||
* Last-modified: 27-Aug-1992
|
||||
*
|
||||
* The Acorn Archimedes uses a variation on U-LAW with the bit order
|
||||
* reversed and the sign bit in bit 0. Being a 'minority' architecture,
|
||||
* Arc owners are quite adept at converting sound/image formats from
|
||||
* other machines, and it is unlikely that you'll ever encounter sound in
|
||||
* one of the Arc's own formats (there are several).
|
||||
*/
|
||||
static const int8 vdic_table[128] = {
|
||||
/* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 24 */ 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 32 */ 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
/* 40 */ 2, 2, 2, 2, 3, 3, 3, 3,
|
||||
/* 48 */ 3, 3, 4, 4, 4, 4, 5, 5,
|
||||
/* 56 */ 5, 5, 6, 6, 6, 6, 7, 7,
|
||||
/* 64 */ 7, 8, 8, 9, 9, 10, 10, 11,
|
||||
/* 72 */ 11, 12, 12, 13, 13, 14, 14, 15,
|
||||
/* 80 */ 15, 16, 17, 18, 19, 20, 21, 22,
|
||||
/* 88 */ 23, 24, 25, 26, 27, 28, 29, 30,
|
||||
/* 96 */ 31, 33, 34, 36, 38, 40, 42, 44,
|
||||
/* 104 */ 46, 48, 50, 52, 54, 56, 58, 60,
|
||||
/* 112 */ 62, 65, 68, 72, 77, 80, 84, 91,
|
||||
/* 120 */ 95, 98, 103, 109, 114, 120, 126, 127
|
||||
};
|
||||
|
||||
|
||||
/* Convert 7 bit samples to 8 bit */
|
||||
static void convert_7bit_to_8bit(uint8 *p, int l)
|
||||
{
|
||||
for (; l--; p++) {
|
||||
*p <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert Archimedes VIDC samples to linear */
|
||||
static void convert_vidc_to_linear(uint8 *p, int l)
|
||||
{
|
||||
int i;
|
||||
uint8 x;
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
x = p[i];
|
||||
p[i] = vdic_table[x >> 1];
|
||||
if (x & 0x01)
|
||||
p[i] *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm4_decoder(uint8 *inp, uint8 *outp, char *tab, int len)
|
||||
{
|
||||
char delta = 0;
|
||||
uint8 b0, b1;
|
||||
int i;
|
||||
|
||||
len = (len + 1) / 2;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
b0 = *inp;
|
||||
b1 = *inp++ >> 4;
|
||||
delta += tab[b0 & 0x0f];
|
||||
*outp++ = delta;
|
||||
delta += tab[b1 & 0x0f];
|
||||
*outp++ = delta;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Convert differential to absolute sample data */
|
||||
static void convert_delta(uint8 *p, int l, int r)
|
||||
{
|
||||
uint16 *w = (uint16 *)p;
|
||||
uint16 abs = 0;
|
||||
|
||||
if (r) {
|
||||
for (; l--;) {
|
||||
abs = *w + abs;
|
||||
*w++ = abs;
|
||||
}
|
||||
} else {
|
||||
for (; l--;) {
|
||||
abs = *p + abs;
|
||||
*p++ = (uint8) abs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert signed to unsigned sample data */
|
||||
static void convert_signal(uint8 *p, int l, int r)
|
||||
{
|
||||
uint16 *w = (uint16 *)p;
|
||||
|
||||
if (r) {
|
||||
for (; l--; w++)
|
||||
*w += 0x8000;
|
||||
} else {
|
||||
for (; l--; p++)
|
||||
*p += (char)0x80; /* cast needed by MSVC++ */
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert little-endian 16 bit samples to big-endian */
|
||||
static void convert_endian(uint8 *p, int l)
|
||||
{
|
||||
uint8 b;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
b = p[0];
|
||||
p[0] = p[1];
|
||||
p[1] = b;
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Downmix stereo samples to mono */
|
||||
static void convert_stereo_to_mono(uint8 *p, int l, int r)
|
||||
{
|
||||
int16 *b = (int16 *)p;
|
||||
int i;
|
||||
|
||||
if (r) {
|
||||
l /= 2;
|
||||
for (i = 0; i < l; i++)
|
||||
b[i] = (b[i * 2] + b[i * 2 + 1]) / 2;
|
||||
} else {
|
||||
for (i = 0; i < l; i++)
|
||||
p[i] = (p[i * 2] + p[i * 2 + 1]) / 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void unroll_loop(struct xmp_sample *xxs)
|
||||
{
|
||||
int8 *s8;
|
||||
int16 *s16;
|
||||
int start, loop_size;
|
||||
int i;
|
||||
|
||||
s16 = (int16 *)xxs->data;
|
||||
s8 = (int8 *)xxs->data;
|
||||
|
||||
if (xxs->len > xxs->lpe) {
|
||||
start = xxs->lpe;
|
||||
} else {
|
||||
start = xxs->len;
|
||||
}
|
||||
|
||||
loop_size = xxs->lpe - xxs->lps;
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
s16 += start;
|
||||
for (i = 0; i < loop_size; i++) {
|
||||
*(s16 + i) = *(s16 - i - 1);
|
||||
}
|
||||
} else {
|
||||
s8 += start;
|
||||
for (i = 0; i < loop_size; i++) {
|
||||
*(s8 + i) = *(s8 - i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int libxmp_load_sample(struct module_data *m, HIO_HANDLE *f, int flags, struct xmp_sample *xxs, const void *buffer)
|
||||
{
|
||||
int bytelen, extralen, unroll_extralen, i;
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
/* Adlib FM patches */
|
||||
if (flags & SAMPLE_FLAG_ADLIB) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Empty or invalid samples
|
||||
*/
|
||||
if (xxs->len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Skip sample loading
|
||||
* FIXME: fails for ADPCM samples
|
||||
*
|
||||
* + Sanity check: skip huge samples (likely corrupt module)
|
||||
*/
|
||||
if (xxs->len > MAX_SAMPLE_SIZE || (m && m->smpctl & XMP_SMPCTL_SKIP)) {
|
||||
if (~flags & SAMPLE_FLAG_NOLOAD) {
|
||||
/* coverity[check_return] */
|
||||
hio_seek(f, xxs->len, SEEK_CUR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Loop parameters sanity check
|
||||
*/
|
||||
if (xxs->lps < 0) {
|
||||
xxs->lps = 0;
|
||||
}
|
||||
if (xxs->lpe > xxs->len) {
|
||||
xxs->lpe = xxs->len;
|
||||
}
|
||||
if (xxs->lps >= xxs->len || xxs->lps >= xxs->lpe) {
|
||||
xxs->lps = xxs->lpe = 0;
|
||||
xxs->flg &= ~(XMP_SAMPLE_LOOP | XMP_SAMPLE_LOOP_BIDIR);
|
||||
}
|
||||
|
||||
/* Patches with samples
|
||||
* Allocate extra sample for interpolation.
|
||||
*/
|
||||
bytelen = xxs->len;
|
||||
extralen = 4;
|
||||
unroll_extralen = 0;
|
||||
|
||||
/* Disable birectional loop flag if sample is not looped
|
||||
*/
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
if (~xxs->flg & XMP_SAMPLE_LOOP)
|
||||
xxs->flg &= ~XMP_SAMPLE_LOOP_BIDIR;
|
||||
}
|
||||
/* Unroll bidirectional loops
|
||||
*/
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
unroll_extralen = (xxs->lpe - xxs->lps) -
|
||||
(xxs->len - xxs->lpe);
|
||||
|
||||
if (unroll_extralen < 0) {
|
||||
unroll_extralen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
bytelen *= 2;
|
||||
extralen *= 2;
|
||||
unroll_extralen *= 2;
|
||||
}
|
||||
|
||||
/* add guard bytes before the buffer for higher order interpolation */
|
||||
xxs->data = (unsigned char *)malloc(bytelen + extralen + unroll_extralen + 4);
|
||||
if (xxs->data == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
*(uint32 *)xxs->data = 0;
|
||||
xxs->data += 4;
|
||||
|
||||
if (flags & SAMPLE_FLAG_NOLOAD) {
|
||||
memcpy(xxs->data, buffer, bytelen);
|
||||
} else
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (flags & SAMPLE_FLAG_ADPCM) {
|
||||
int x2 = (bytelen + 1) >> 1;
|
||||
char table[16];
|
||||
|
||||
if (hio_read(table, 1, 16, f) != 16) {
|
||||
goto err2;
|
||||
}
|
||||
if (hio_read(xxs->data + x2, 1, x2, f) != x2) {
|
||||
goto err2;
|
||||
}
|
||||
adpcm4_decoder((uint8 *)xxs->data + x2,
|
||||
(uint8 *)xxs->data, table, bytelen);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
int x = hio_read(xxs->data, 1, bytelen, f);
|
||||
if (x != bytelen) {
|
||||
D_(D_WARN "short read (%d) in sample load", x - bytelen);
|
||||
memset(xxs->data + x, 0, bytelen - x);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (flags & SAMPLE_FLAG_7BIT) {
|
||||
convert_7bit_to_8bit(xxs->data, xxs->len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Fix endianism if needed */
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
if (~flags & SAMPLE_FLAG_BIGEND)
|
||||
convert_endian(xxs->data, xxs->len);
|
||||
#else
|
||||
if (flags & SAMPLE_FLAG_BIGEND)
|
||||
convert_endian(xxs->data, xxs->len);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Convert delta samples */
|
||||
if (flags & SAMPLE_FLAG_DIFF) {
|
||||
convert_delta(xxs->data, xxs->len, xxs->flg & XMP_SAMPLE_16BIT);
|
||||
} else if (flags & SAMPLE_FLAG_8BDIFF) {
|
||||
int len = xxs->len;
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
len *= 2;
|
||||
}
|
||||
convert_delta(xxs->data, len, 0);
|
||||
}
|
||||
|
||||
/* Convert samples to signed */
|
||||
if (flags & SAMPLE_FLAG_UNS) {
|
||||
convert_signal(xxs->data, xxs->len,
|
||||
xxs->flg & XMP_SAMPLE_16BIT);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Downmix stereo samples */
|
||||
if (flags & SAMPLE_FLAG_STEREO) {
|
||||
convert_stereo_to_mono(xxs->data, xxs->len,
|
||||
xxs->flg & XMP_SAMPLE_16BIT);
|
||||
xxs->len /= 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (flags & SAMPLE_FLAG_VIDC) {
|
||||
convert_vidc_to_linear(xxs->data, xxs->len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check for full loop samples */
|
||||
if (flags & SAMPLE_FLAG_FULLREP) {
|
||||
if (xxs->lps == 0 && xxs->len > xxs->lpe)
|
||||
xxs->flg |= XMP_SAMPLE_LOOP_FULL;
|
||||
}
|
||||
|
||||
/* Unroll bidirectional loops */
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
unroll_loop(xxs);
|
||||
bytelen += unroll_extralen;
|
||||
}
|
||||
|
||||
/* Add extra samples at end */
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
xxs->data[bytelen + i] = xxs->data[bytelen - 2 + i];
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 4; i++) {
|
||||
xxs->data[bytelen + i] = xxs->data[bytelen - 1 + i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Add extra samples at start */
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
xxs->data[-2] = xxs->data[0];
|
||||
xxs->data[-1] = xxs->data[1];
|
||||
} else {
|
||||
xxs->data[-1] = xxs->data[0];
|
||||
}
|
||||
|
||||
/* Fix sample at loop */
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP) {
|
||||
int lpe = xxs->lpe;
|
||||
int lps = xxs->lps;
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
lpe += lpe - lps;
|
||||
}
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
lpe <<= 1;
|
||||
lps <<= 1;
|
||||
for (i = 0; i < 8; i++) {
|
||||
xxs->data[lpe + i] = xxs->data[lps + i];
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 4; i++) {
|
||||
xxs->data[lpe + i] = xxs->data[lps + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
err2:
|
||||
free(xxs->data - 4);
|
||||
xxs->data = NULL; /* prevent double free in PCM load error */
|
||||
#endif
|
||||
err:
|
||||
return -1;
|
||||
}
|
|
@ -1,549 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Sun, 31 May 1998 17:50:02 -0600
|
||||
* Reported by ToyKeeper <scriven@CS.ColoState.EDU>:
|
||||
* For loop-prevention, I know a way to do it which lets most songs play
|
||||
* fine once through even if they have backward-jumps. Just keep a small
|
||||
* array (256 bytes, or even bits) of flags, each entry determining if a
|
||||
* pattern in the song order has been played. If you get to an entry which
|
||||
* is already non-zero, skip to the next song (assuming looping is off).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tue, 6 Oct 1998 21:23:17 +0200 (CEST)
|
||||
* Reported by John v/d Kamp <blade_@dds.nl>:
|
||||
* scan.c was hanging when it jumps to an invalid restart value.
|
||||
* (Fixed by hipolito)
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
#include "effects.h"
|
||||
#include "mixer.h"
|
||||
|
||||
#define S3M_END 0xff
|
||||
#define S3M_SKIP 0xfe
|
||||
|
||||
|
||||
static int scan_module(struct context_data *ctx, int ep, int chain)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int parm, gvol_memory, f1, f2, p1, p2, ord, ord2;
|
||||
int row, last_row, break_row, row_count;
|
||||
int gvl, bpm, speed, base_time, chn;
|
||||
int frame_count;
|
||||
double time, start_time;
|
||||
int loop_chn, loop_num, inside_loop;
|
||||
int pdelay = 0;
|
||||
int loop_count[XMP_MAX_CHANNELS];
|
||||
int loop_row[XMP_MAX_CHANNELS];
|
||||
struct xmp_event* event;
|
||||
int i, pat;
|
||||
int has_marker;
|
||||
struct ord_data *info;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
int st26_speed;
|
||||
#endif
|
||||
|
||||
if (mod->len == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < mod->len; i++) {
|
||||
int pat = mod->xxo[i];
|
||||
memset(m->scan_cnt[i], 0, pat >= mod->pat ? 1 :
|
||||
mod->xxp[pat]->rows ? mod->xxp[pat]->rows : 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < mod->chn; i++) {
|
||||
loop_count[i] = 0;
|
||||
loop_row[i] = -1;
|
||||
}
|
||||
loop_num = 0;
|
||||
loop_chn = -1;
|
||||
|
||||
gvl = mod->gvl;
|
||||
bpm = mod->bpm;
|
||||
|
||||
speed = mod->spd;
|
||||
base_time = (int) m->rrate;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
st26_speed = 0;
|
||||
#endif
|
||||
|
||||
has_marker = HAS_QUIRK(QUIRK_MARKER);
|
||||
|
||||
/* By erlk ozlr <erlk.ozlr@gmail.com>
|
||||
*
|
||||
* xmp doesn't handle really properly the "start" option (-s for the
|
||||
* command-line) for DeusEx's .umx files. These .umx files contain
|
||||
* several loop "tracks" that never join together. That's how they put
|
||||
* multiple musics on each level with a file per level. Each "track"
|
||||
* starts at the same order in all files. The problem is that xmp starts
|
||||
* decoding the module at order 0 and not at the order specified with
|
||||
* the start option. If we have a module that does "0 -> 2 -> 0 -> ...",
|
||||
* we cannot play order 1, even with the supposed right option.
|
||||
*
|
||||
* was: ord2 = ord = -1;
|
||||
*
|
||||
* CM: Fixed by using different "sequences" for each loop or subsong.
|
||||
* Each sequence has its entry point. Sequences don't overlap.
|
||||
*/
|
||||
ord2 = -1;
|
||||
ord = ep - 1;
|
||||
|
||||
gvol_memory = break_row = row_count = frame_count = 0;
|
||||
start_time = time = 0.0;
|
||||
inside_loop = 0;
|
||||
|
||||
while (42) {
|
||||
if ((uint32)++ord >= mod->len) {
|
||||
if (mod->rst > mod->len || mod->xxo[mod->rst] >= mod->pat) {
|
||||
ord = ep;
|
||||
} else {
|
||||
if (libxmp_get_sequence(ctx, mod->rst) == chain) {
|
||||
ord = mod->rst;
|
||||
} else {
|
||||
ord = ep;
|
||||
}
|
||||
}
|
||||
|
||||
pat = mod->xxo[ord];
|
||||
if (has_marker && pat == S3M_END) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pat = mod->xxo[ord];
|
||||
info = &m->xxo_info[ord];
|
||||
|
||||
/* Allow more complex order reuse only in main sequence */
|
||||
if (ep != 0 && p->sequence_control[ord] != 0xff) {
|
||||
break;
|
||||
}
|
||||
p->sequence_control[ord] = chain;
|
||||
|
||||
/* All invalid patterns skipped, only S3M_END aborts replay */
|
||||
if (pat >= mod->pat) {
|
||||
if (has_marker && pat == S3M_END) {
|
||||
ord = mod->len;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (break_row >= mod->xxp[pat]->rows) {
|
||||
break_row = 0;
|
||||
}
|
||||
|
||||
/* Loops can cross pattern boundaries, so check if we're not looping */
|
||||
if (m->scan_cnt[ord][break_row] && !inside_loop) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Don't update pattern information if we're inside a loop, otherwise
|
||||
* a loop containing e.g. a global volume fade can make the pattern
|
||||
* start with the wrong volume.
|
||||
*/
|
||||
if (!inside_loop && info->gvl < 0) {
|
||||
info->gvl = gvl;
|
||||
info->bpm = bpm;
|
||||
info->speed = speed;
|
||||
info->time = (int) (time + m->time_factor * frame_count * base_time / bpm);
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
info->st26_speed = st26_speed;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (info->start_row == 0 && ord != 0) {
|
||||
if (ord == ep) {
|
||||
start_time = time + m->time_factor * frame_count * base_time / bpm;
|
||||
}
|
||||
|
||||
info->start_row = break_row;
|
||||
}
|
||||
|
||||
last_row = mod->xxp[pat]->rows;
|
||||
for (row = break_row, break_row = 0; row < last_row; row++, row_count++) {
|
||||
/* Prevent crashes caused by large softmixer frames */
|
||||
if (bpm < XMP_MIN_BPM) {
|
||||
bpm = XMP_MIN_BPM;
|
||||
}
|
||||
|
||||
/* Date: Sat, 8 Sep 2007 04:01:06 +0200
|
||||
* Reported by Zbigniew Luszpinski <zbiggy@o2.pl>
|
||||
* The scan routine falls into infinite looping and doesn't let
|
||||
* xmp play jos-dr4k.xm.
|
||||
* Claudio's workaround: we'll break infinite loops here.
|
||||
*
|
||||
* Date: Oct 27, 2007 8:05 PM
|
||||
* From: Adric Riedel <adric.riedel@gmail.com>
|
||||
* Jesper Kyd: Global Trash 3.mod (the 'Hardwired' theme) only
|
||||
* plays the first 4:41 of what should be a 10 minute piece.
|
||||
* (...) it dies at the end of position 2F
|
||||
*/
|
||||
|
||||
if (row_count > 512) /* was 255, but Global trash goes to 318 */
|
||||
goto end_module;
|
||||
|
||||
if (!loop_num && m->scan_cnt[ord][row]) {
|
||||
row_count--;
|
||||
goto end_module;
|
||||
}
|
||||
m->scan_cnt[ord][row]++;
|
||||
|
||||
pdelay = 0;
|
||||
|
||||
for (chn = 0; chn < mod->chn; chn++) {
|
||||
if (row >= mod->xxt[mod->xxp[pat]->index[chn]]->rows)
|
||||
continue;
|
||||
|
||||
event = &EVENT(mod->xxo[ord], chn, row);
|
||||
|
||||
f1 = event->fxt;
|
||||
p1 = event->fxp;
|
||||
f2 = event->f2t;
|
||||
p2 = event->f2p;
|
||||
|
||||
if (f1 == FX_GLOBALVOL || f2 == FX_GLOBALVOL) {
|
||||
gvl = (f1 == FX_GLOBALVOL) ? p1 : p2;
|
||||
gvl = gvl > m->gvolbase ? m->gvolbase : gvl < 0 ? 0 : gvl;
|
||||
}
|
||||
|
||||
/* Process fine global volume slide */
|
||||
if (f1 == FX_GVOL_SLIDE || f2 == FX_GVOL_SLIDE) {
|
||||
int h, l;
|
||||
parm = (f1 == FX_GVOL_SLIDE) ? p1 : p2;
|
||||
|
||||
process_gvol:
|
||||
if (parm) {
|
||||
gvol_memory = parm;
|
||||
h = MSN(parm);
|
||||
l = LSN(parm);
|
||||
|
||||
if (HAS_QUIRK(QUIRK_FINEFX)) {
|
||||
if (l == 0xf && h != 0) {
|
||||
gvl += h;
|
||||
} else if (h == 0xf && l != 0) {
|
||||
gvl -= l;
|
||||
} else {
|
||||
if (m->quirk & QUIRK_VSALL) {
|
||||
gvl += (h - l) * speed;
|
||||
} else {
|
||||
gvl += (h - l) * (speed - 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (m->quirk & QUIRK_VSALL) {
|
||||
gvl += (h - l) * speed;
|
||||
} else {
|
||||
gvl += (h - l) * (speed - 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((parm = gvol_memory) != 0)
|
||||
goto process_gvol;
|
||||
}
|
||||
}
|
||||
|
||||
if ((f1 == FX_SPEED && p1) || (f2 == FX_SPEED && p2)) {
|
||||
parm = (f1 == FX_SPEED) ? p1 : p2;
|
||||
frame_count += row_count * speed;
|
||||
row_count = 0;
|
||||
if (parm) {
|
||||
if (HAS_QUIRK(QUIRK_NOBPM) || p->flags & XMP_FLAGS_VBLANK || parm < 0x20) {
|
||||
if (parm > 0) {
|
||||
speed = parm;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
st26_speed = 0;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
time += m->time_factor * frame_count * base_time / bpm;
|
||||
frame_count = 0;
|
||||
bpm = parm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (f1 == FX_SPEED_CP) {
|
||||
f1 = FX_S3M_SPEED;
|
||||
}
|
||||
if (f2 == FX_SPEED_CP) {
|
||||
f2 = FX_S3M_SPEED;
|
||||
}
|
||||
|
||||
/* ST2.6 speed processing */
|
||||
|
||||
if (f1 == FX_ICE_SPEED && p1) {
|
||||
if (LSN(p1)) {
|
||||
st26_speed = (MSN(p1) << 8) | LSN(p1);
|
||||
} else {
|
||||
st26_speed = MSN(p1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((f1 == FX_S3M_SPEED && p1) || (f2 == FX_S3M_SPEED && p2)) {
|
||||
parm = (f1 == FX_S3M_SPEED) ? p1 : p2;
|
||||
if (parm > 0) {
|
||||
frame_count += row_count * speed;
|
||||
row_count = 0;
|
||||
speed = parm;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
st26_speed = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if ((f1 == FX_S3M_BPM && p1) || (f2 == FX_S3M_BPM && p2)) {
|
||||
parm = (f1 == FX_S3M_BPM) ? p1 : p2;
|
||||
if (parm >= 0x20) {
|
||||
frame_count += row_count * speed;
|
||||
row_count = 0;
|
||||
time += m->time_factor * frame_count * base_time / bpm;
|
||||
frame_count = 0;
|
||||
bpm = parm;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
if ((f1 == FX_IT_BPM && p1) || (f2 == FX_IT_BPM && p2)) {
|
||||
parm = (f1 == FX_IT_BPM) ? p1 : p2;
|
||||
frame_count += row_count * speed;
|
||||
row_count = 0;
|
||||
time += m->time_factor * frame_count * base_time / bpm;
|
||||
frame_count = 0;
|
||||
|
||||
if (MSN(parm) == 0) {
|
||||
time += m->time_factor * base_time / bpm;
|
||||
for (i = 1; i < speed; i++) {
|
||||
bpm -= LSN(parm);
|
||||
if (bpm < 0x20)
|
||||
bpm = 0x20;
|
||||
time += m->time_factor * base_time / bpm;
|
||||
}
|
||||
|
||||
/* remove one row at final bpm */
|
||||
time -= m->time_factor * speed * base_time / bpm;
|
||||
|
||||
} else if (MSN(parm) == 1) {
|
||||
time += m->time_factor * base_time / bpm;
|
||||
for (i = 1; i < speed; i++) {
|
||||
bpm += LSN(parm);
|
||||
if (bpm > 0xff)
|
||||
bpm = 0xff;
|
||||
time += m->time_factor * base_time / bpm;
|
||||
}
|
||||
|
||||
/* remove one row at final bpm */
|
||||
time -= m->time_factor * speed * base_time / bpm;
|
||||
|
||||
} else {
|
||||
bpm = parm;
|
||||
}
|
||||
}
|
||||
|
||||
if (f1 == FX_IT_ROWDELAY) {
|
||||
m->scan_cnt[ord][row] += p1 & 0x0f;
|
||||
frame_count += (p1 & 0x0f) * speed;
|
||||
}
|
||||
|
||||
if (f1 == FX_IT_BREAK) {
|
||||
break_row = p1;
|
||||
last_row = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (f1 == FX_JUMP || f2 == FX_JUMP) {
|
||||
ord2 = (f1 == FX_JUMP) ? p1 : p2;
|
||||
break_row = 0;
|
||||
last_row = 0;
|
||||
|
||||
/* prevent infinite loop, see OpenMPT PatLoop-Various.xm */
|
||||
inside_loop = 0;
|
||||
}
|
||||
|
||||
if (f1 == FX_BREAK || f2 == FX_BREAK) {
|
||||
parm = (f1 == FX_BREAK) ? p1 : p2;
|
||||
break_row = 10 * MSN(parm) + LSN(parm);
|
||||
last_row = 0;
|
||||
}
|
||||
|
||||
if (f1 == FX_EXTENDED || f2 == FX_EXTENDED) {
|
||||
parm = (f1 == FX_EXTENDED) ? p1 : p2;
|
||||
|
||||
if ((parm >> 4) == EX_PATT_DELAY) {
|
||||
if (m->read_event_type != READ_EVENT_ST3 || !pdelay) {
|
||||
pdelay = parm & 0x0f;
|
||||
frame_count += pdelay * speed;
|
||||
}
|
||||
}
|
||||
|
||||
if ((parm >> 4) == EX_PATTERN_LOOP) {
|
||||
if (parm &= 0x0f) {
|
||||
/* Loop end */
|
||||
if (loop_count[chn]) {
|
||||
if (--loop_count[chn]) {
|
||||
/* next iteraction */
|
||||
loop_chn = chn;
|
||||
} else {
|
||||
/* finish looping */
|
||||
loop_num--;
|
||||
inside_loop = 0;
|
||||
if (m->quirk & QUIRK_S3MLOOP)
|
||||
loop_row[chn] = row;
|
||||
}
|
||||
} else {
|
||||
loop_count[chn] = parm;
|
||||
loop_chn = chn;
|
||||
loop_num++;
|
||||
}
|
||||
} else {
|
||||
/* Loop start */
|
||||
loop_row[chn] = row - 1;
|
||||
inside_loop = 1;
|
||||
if (HAS_QUIRK(QUIRK_FT2BUGS))
|
||||
break_row = row;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (loop_chn >= 0) {
|
||||
row = loop_row[loop_chn];
|
||||
loop_chn = -1;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (st26_speed) {
|
||||
frame_count += row_count * speed;
|
||||
row_count = 0;
|
||||
if (st26_speed & 0x10000) {
|
||||
speed = (st26_speed & 0xff00) >> 8;
|
||||
} else {
|
||||
speed = st26_speed & 0xff;
|
||||
}
|
||||
st26_speed ^= 0x10000;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (break_row && pdelay) {
|
||||
break_row++;
|
||||
}
|
||||
|
||||
if (ord2 >= 0) {
|
||||
ord = ord2 - 1;
|
||||
ord2 = -1;
|
||||
}
|
||||
|
||||
frame_count += row_count * speed;
|
||||
row_count = 0;
|
||||
}
|
||||
row = break_row;
|
||||
|
||||
end_module:
|
||||
|
||||
/* Sanity check */
|
||||
{
|
||||
pat = mod->xxo[ord];
|
||||
if (pat >= mod->pat || row >= mod->xxp[pat]->rows) {
|
||||
row = 0;
|
||||
}
|
||||
}
|
||||
|
||||
p->scan[chain].num = m->scan_cnt[ord][row];
|
||||
p->scan[chain].row = row;
|
||||
p->scan[chain].ord = ord;
|
||||
|
||||
time -= start_time;
|
||||
frame_count += row_count * speed;
|
||||
|
||||
return (int) (time + m->time_factor * frame_count * base_time / bpm);
|
||||
}
|
||||
|
||||
int libxmp_get_sequence(struct context_data *ctx, int ord)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
return p->sequence_control[ord];
|
||||
}
|
||||
|
||||
int libxmp_scan_sequences(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, ep;
|
||||
int seq;
|
||||
unsigned char temp_ep[XMP_MAX_MOD_LENGTH];
|
||||
|
||||
/* Initialize order data to prevent overwrite when a position is used
|
||||
* multiple times at different starting points (see janosik.xm).
|
||||
*/
|
||||
for (i = 0; i < XMP_MAX_MOD_LENGTH; i++) {
|
||||
m->xxo_info[i].gvl = -1;
|
||||
}
|
||||
|
||||
ep = 0;
|
||||
memset(p->sequence_control, 0xff, XMP_MAX_MOD_LENGTH);
|
||||
temp_ep[0] = 0;
|
||||
p->scan[0].time = scan_module(ctx, ep, 0);
|
||||
seq = 1;
|
||||
|
||||
while (1) {
|
||||
/* Scan song starting at given entry point */
|
||||
/* Check if any patterns left */
|
||||
for (i = 0; i < mod->len; i++) {
|
||||
if (p->sequence_control[i] == 0xff) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i != mod->len && seq < MAX_SEQUENCES) {
|
||||
/* New entry point */
|
||||
ep = i;
|
||||
temp_ep[seq] = ep;
|
||||
p->scan[seq].time = scan_module(ctx, ep, seq);
|
||||
if (p->scan[seq].time > 0)
|
||||
seq++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m->num_sequences = seq;
|
||||
|
||||
/* Now place entry points in the public accessible array */
|
||||
for (i = 0; i < m->num_sequences; i++) {
|
||||
m->seq_data[i].entry_point = temp_ep[i];
|
||||
m->seq_data[i].duration = p->scan[i].time;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,333 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "common.h"
|
||||
#include "period.h"
|
||||
#include "player.h"
|
||||
#include "hio.h"
|
||||
|
||||
|
||||
struct xmp_instrument *libxmp_get_instrument(struct context_data *ctx, int ins)
|
||||
{
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xmp_instrument *xxi;
|
||||
|
||||
if (ins < mod->ins) {
|
||||
xxi = &mod->xxi[ins];
|
||||
} else if (ins < mod->ins + smix->ins) {
|
||||
xxi = &smix->xxi[ins - mod->ins];
|
||||
} else {
|
||||
xxi = NULL;
|
||||
}
|
||||
|
||||
return xxi;
|
||||
}
|
||||
|
||||
struct xmp_sample *libxmp_get_sample(struct context_data *ctx, int smp)
|
||||
{
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xmp_sample *xxs;
|
||||
|
||||
if (smp < mod->smp) {
|
||||
xxs = &mod->xxs[smp];
|
||||
} else if (smp < mod->smp + smix->smp) {
|
||||
xxs = &smix->xxs[smp - mod->smp];
|
||||
} else {
|
||||
xxs = NULL;
|
||||
}
|
||||
|
||||
return xxs;
|
||||
}
|
||||
|
||||
int xmp_start_smix(xmp_context opaque, int chn, int smp)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
|
||||
if (ctx->state > XMP_STATE_LOADED) {
|
||||
return -XMP_ERROR_STATE;
|
||||
}
|
||||
|
||||
smix->xxi = (struct xmp_instrument *)calloc(sizeof (struct xmp_instrument), smp);
|
||||
if (smix->xxi == NULL) {
|
||||
goto err;
|
||||
}
|
||||
smix->xxs = (struct xmp_sample *)calloc(sizeof (struct xmp_sample), smp);
|
||||
if (smix->xxs == NULL) {
|
||||
goto err1;
|
||||
}
|
||||
|
||||
smix->chn = chn;
|
||||
smix->ins = smix->smp = smp;
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
free(smix->xxi);
|
||||
err:
|
||||
return -XMP_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
int xmp_smix_play_instrument(xmp_context opaque, int ins, int note, int vol, int chn)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xmp_event *event;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING) {
|
||||
return -XMP_ERROR_STATE;
|
||||
}
|
||||
|
||||
if (chn >= smix->chn || ins >= mod->ins) {
|
||||
return -XMP_ERROR_INVALID;
|
||||
}
|
||||
|
||||
if (note == 0) {
|
||||
note = 60; /* middle C note number */
|
||||
}
|
||||
|
||||
event = &p->inject_event[mod->chn + chn];
|
||||
memset(event, 0, sizeof (struct xmp_event));
|
||||
event->note = note + 1;
|
||||
event->ins = ins + 1;
|
||||
event->vol = vol + 1;
|
||||
event->_flag = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xmp_smix_play_sample(xmp_context opaque, int ins, int note, int vol, int chn)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xmp_event *event;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING) {
|
||||
return -XMP_ERROR_STATE;
|
||||
}
|
||||
|
||||
if (chn >= smix->chn || ins >= smix->ins) {
|
||||
return -XMP_ERROR_INVALID;
|
||||
}
|
||||
|
||||
if (note == 0) {
|
||||
note = 60; /* middle C note number */
|
||||
}
|
||||
|
||||
event = &p->inject_event[mod->chn + chn];
|
||||
memset(event, 0, sizeof (struct xmp_event));
|
||||
event->note = note + 1;
|
||||
event->ins = mod->ins + ins + 1;
|
||||
event->vol = vol + 1;
|
||||
event->_flag = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xmp_smix_channel_pan(xmp_context opaque, int chn, int pan)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct channel_data *xc;
|
||||
|
||||
if (chn >= smix->chn || pan < 0 || pan > 255) {
|
||||
return -XMP_ERROR_INVALID;
|
||||
}
|
||||
|
||||
xc = &p->xc_data[m->mod.chn + chn];
|
||||
xc->pan.val = pan;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef EDUKE32_DISABLED
|
||||
int xmp_smix_load_sample(xmp_context opaque, int num, char *path)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_instrument *xxi;
|
||||
struct xmp_sample *xxs;
|
||||
HIO_HANDLE *h;
|
||||
uint32 magic;
|
||||
int chn, rate, bits, size;
|
||||
int retval = -XMP_ERROR_INTERNAL;
|
||||
|
||||
if (num >= smix->ins) {
|
||||
retval = -XMP_ERROR_INVALID;
|
||||
goto err;
|
||||
}
|
||||
|
||||
xxi = &smix->xxi[num];
|
||||
xxs = &smix->xxs[num];
|
||||
|
||||
h = hio_open(path, "rb");
|
||||
if (h == NULL) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Init instrument */
|
||||
|
||||
xxi->sub = (struct xmp_subinstrument *)calloc(sizeof(struct xmp_subinstrument), 1);
|
||||
if (xxi->sub == NULL) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
xxi->vol = m->volbase;
|
||||
xxi->nsm = 1;
|
||||
xxi->sub[0].sid = num;
|
||||
xxi->sub[0].vol = xxi->vol;
|
||||
xxi->sub[0].pan = 0x80;
|
||||
|
||||
/* Load sample */
|
||||
|
||||
magic = hio_read32b(h);
|
||||
if (magic != 0x52494646) { /* RIFF */
|
||||
retval = -XMP_ERROR_FORMAT;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (hio_seek(h, 22, SEEK_SET) < 0) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err2;
|
||||
}
|
||||
chn = hio_read16l(h);
|
||||
if (chn != 1) {
|
||||
retval = -XMP_ERROR_FORMAT;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
rate = hio_read32l(h);
|
||||
if (rate == 0) {
|
||||
retval = -XMP_ERROR_FORMAT;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (hio_seek(h, 34, SEEK_SET) < 0) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err2;
|
||||
}
|
||||
bits = hio_read16l(h);
|
||||
if (bits == 0) {
|
||||
retval = -XMP_ERROR_FORMAT;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (hio_seek(h, 40, SEEK_SET) < 0) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err2;
|
||||
}
|
||||
size = hio_read32l(h);
|
||||
if (size == 0) {
|
||||
retval = -XMP_ERROR_FORMAT;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
libxmp_c2spd_to_note(rate, &xxi->sub[0].xpo, &xxi->sub[0].fin);
|
||||
|
||||
xxs->len = 8 * size / bits;
|
||||
xxs->lps = 0;
|
||||
xxs->lpe = 0;
|
||||
xxs->flg = bits == 16 ? XMP_SAMPLE_16BIT : 0;
|
||||
|
||||
xxs->data = malloc(size + 8);
|
||||
if (xxs->data == NULL) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
/* ugly hack to make the interpolator happy */
|
||||
memset(xxs->data, 0, 4);
|
||||
memset(xxs->data + 4 + size, 0, 4);
|
||||
xxs->data += 4;
|
||||
|
||||
if (hio_seek(h, 44, SEEK_SET) < 0) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err2;
|
||||
}
|
||||
if (hio_read(xxs->data, 1, size, h) != size) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err2;
|
||||
}
|
||||
hio_close(h);
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
free(xxi->sub);
|
||||
xxi->sub = NULL;
|
||||
err1:
|
||||
hio_close(h);
|
||||
err:
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
int xmp_smix_release_sample(xmp_context opaque, int num)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
|
||||
if (num >= smix->ins) {
|
||||
return -XMP_ERROR_INVALID;
|
||||
}
|
||||
|
||||
if (smix->xxs[num].data != NULL) {
|
||||
free(smix->xxs[num].data - 4);
|
||||
}
|
||||
free(smix->xxi[num].sub);
|
||||
|
||||
smix->xxs[num].data = NULL;
|
||||
smix->xxi[num].sub = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xmp_end_smix(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < smix->smp; i++) {
|
||||
xmp_smix_release_sample(opaque, i);
|
||||
}
|
||||
|
||||
free(smix->xxs);
|
||||
free(smix->xxi);
|
||||
}
|
||||
|
|
@ -1,608 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include "common.h"
|
||||
#include "virtual.h"
|
||||
#include "mixer.h"
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
#include "paula.h"
|
||||
#endif
|
||||
|
||||
#define FREE -1
|
||||
|
||||
/* For virt_pastnote() */
|
||||
void libxmp_player_set_release(struct context_data *, int);
|
||||
void libxmp_player_set_fadeout(struct context_data *, int);
|
||||
|
||||
|
||||
/* Get parent channel */
|
||||
int libxmp_virt_getroot(struct context_data *ctx, int chn)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi;
|
||||
int voc;
|
||||
|
||||
voc = p->virt.virt_channel[chn].map;
|
||||
if (voc < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
vi = &p->virt.voice_array[voc];
|
||||
|
||||
return vi->root;
|
||||
}
|
||||
|
||||
void libxmp_virt_resetvoice(struct context_data *ctx, int voc, int mute)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
struct paula_state *paula;
|
||||
#endif
|
||||
|
||||
if ((uint32)voc >= p->virt.maxvoc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mute) {
|
||||
libxmp_mixer_setvol(ctx, voc, 0);
|
||||
}
|
||||
|
||||
p->virt.virt_used--;
|
||||
p->virt.virt_channel[vi->root].count--;
|
||||
p->virt.virt_channel[vi->chn].map = FREE;
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
paula = vi->paula;
|
||||
#endif
|
||||
memset(vi, 0, sizeof(struct mixer_voice));
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
vi->paula = paula;
|
||||
#endif
|
||||
vi->chn = vi->root = FREE;
|
||||
}
|
||||
|
||||
/* virt_on (number of tracks) */
|
||||
int libxmp_virt_on(struct context_data *ctx, int num)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
int i;
|
||||
|
||||
p->virt.num_tracks = num;
|
||||
num = libxmp_mixer_numvoices(ctx, -1);
|
||||
|
||||
p->virt.virt_channels = p->virt.num_tracks;
|
||||
|
||||
if (HAS_QUIRK(QUIRK_VIRTUAL)) {
|
||||
p->virt.virt_channels += num;
|
||||
} else if (num > p->virt.virt_channels) {
|
||||
num = p->virt.virt_channels;
|
||||
}
|
||||
|
||||
p->virt.maxvoc = libxmp_mixer_numvoices(ctx, num);
|
||||
|
||||
p->virt.voice_array = (struct mixer_voice *)calloc(p->virt.maxvoc,
|
||||
sizeof(struct mixer_voice));
|
||||
if (p->virt.voice_array == NULL)
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
p->virt.voice_array[i].chn = FREE;
|
||||
p->virt.voice_array[i].root = FREE;
|
||||
}
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
/* Initialize Paula simulator */
|
||||
if (IS_AMIGA_MOD()) {
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
p->virt.voice_array[i].paula = calloc(1, sizeof (struct paula_state));
|
||||
if (p->virt.voice_array[i].paula == NULL) {
|
||||
goto err2;
|
||||
}
|
||||
libxmp_paula_init(ctx, p->virt.voice_array[i].paula);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
p->virt.virt_channel = (struct virt_channel *)malloc(p->virt.virt_channels *
|
||||
sizeof(struct virt_channel));
|
||||
if (p->virt.virt_channel == NULL)
|
||||
goto err2;
|
||||
|
||||
for (i = 0; i < p->virt.virt_channels; i++) {
|
||||
p->virt.virt_channel[i].map = FREE;
|
||||
p->virt.virt_channel[i].count = 0;
|
||||
}
|
||||
|
||||
p->virt.virt_used = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
if (IS_AMIGA_MOD()) {
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
free(p->virt.voice_array[i].paula);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
free(p->virt.voice_array);
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void libxmp_virt_off(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
struct module_data *m = &ctx->m;
|
||||
int i;
|
||||
#endif
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
/* Free Paula simulator state */
|
||||
if (IS_AMIGA_MOD()) {
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
free(p->virt.voice_array[i].paula);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
p->virt.virt_used = p->virt.maxvoc = 0;
|
||||
p->virt.virt_channels = 0;
|
||||
p->virt.num_tracks = 0;
|
||||
|
||||
free(p->virt.voice_array);
|
||||
free(p->virt.virt_channel);
|
||||
}
|
||||
|
||||
void libxmp_virt_reset(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int i;
|
||||
|
||||
if (p->virt.virt_channels < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* CID 129203 (#1 of 1): Useless call (USELESS_CALL)
|
||||
* Call is only useful for its return value, which is ignored.
|
||||
*
|
||||
* libxmp_mixer_numvoices(ctx, p->virt.maxvoc);
|
||||
*/
|
||||
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
struct mixer_voice *vi = &p->virt.voice_array[i];
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
struct paula_state *paula = vi->paula;
|
||||
#endif
|
||||
memset(vi, 0, sizeof(struct mixer_voice));
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
vi->paula = paula;
|
||||
#endif
|
||||
vi->chn = FREE;
|
||||
vi->root = FREE;
|
||||
}
|
||||
|
||||
for (i = 0; i < p->virt.virt_channels; i++) {
|
||||
p->virt.virt_channel[i].map = FREE;
|
||||
p->virt.virt_channel[i].count = 0;
|
||||
}
|
||||
|
||||
p->virt.virt_used = 0;
|
||||
}
|
||||
|
||||
static int free_voice(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int i, num, vol;
|
||||
|
||||
/* Find background voice with lowest volume*/
|
||||
num = FREE;
|
||||
vol = INT_MAX;
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
struct mixer_voice *vi = &p->virt.voice_array[i];
|
||||
|
||||
if (vi->chn >= p->virt.num_tracks && vi->vol < vol) {
|
||||
num = i;
|
||||
vol = vi->vol;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free voice */
|
||||
if (num >= 0) {
|
||||
p->virt.virt_channel[p->virt.voice_array[num].chn].map = FREE;
|
||||
p->virt.virt_channel[p->virt.voice_array[num].root].count--;
|
||||
p->virt.virt_used--;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static int alloc_voice(struct context_data *ctx, int chn)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int i;
|
||||
|
||||
/* Find free voice */
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
if (p->virt.voice_array[i].chn == FREE)
|
||||
break;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
if (i == p->virt.maxvoc) {
|
||||
i = free_voice(ctx);
|
||||
}
|
||||
|
||||
if (i >= 0) {
|
||||
p->virt.virt_channel[chn].count++;
|
||||
p->virt.virt_used++;
|
||||
|
||||
p->virt.voice_array[i].chn = chn;
|
||||
p->virt.voice_array[i].root = chn;
|
||||
p->virt.virt_channel[chn].map = i;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int map_virt_channel(struct player_data *p, int chn)
|
||||
{
|
||||
int voc;
|
||||
|
||||
if ((uint32)chn >= p->virt.virt_channels)
|
||||
return -1;
|
||||
|
||||
voc = p->virt.virt_channel[chn].map;
|
||||
|
||||
if ((uint32)voc >= p->virt.maxvoc)
|
||||
return -1;
|
||||
|
||||
return voc;
|
||||
}
|
||||
|
||||
int libxmp_virt_mapchannel(struct context_data *ctx, int chn)
|
||||
{
|
||||
return map_virt_channel(&ctx->p, chn);
|
||||
}
|
||||
|
||||
void libxmp_virt_resetchannel(struct context_data *ctx, int chn)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi;
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
struct paula_state *paula;
|
||||
#endif
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0)
|
||||
return;
|
||||
|
||||
libxmp_mixer_setvol(ctx, voc, 0);
|
||||
|
||||
p->virt.virt_used--;
|
||||
p->virt.virt_channel[p->virt.voice_array[voc].root].count--;
|
||||
p->virt.virt_channel[chn].map = FREE;
|
||||
|
||||
vi = &p->virt.voice_array[voc];
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
paula = vi->paula;
|
||||
#endif
|
||||
memset(vi, 0, sizeof(struct mixer_voice));
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
vi->paula = paula;
|
||||
#endif
|
||||
vi->chn = vi->root = FREE;
|
||||
}
|
||||
|
||||
void libxmp_virt_setvol(struct context_data *ctx, int chn, int vol)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc, root;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
root = p->virt.voice_array[voc].root;
|
||||
if (root < XMP_MAX_CHANNELS && p->channel_mute[root]) {
|
||||
vol = 0;
|
||||
}
|
||||
|
||||
libxmp_mixer_setvol(ctx, voc, vol);
|
||||
|
||||
if (vol == 0 && chn >= p->virt.num_tracks) {
|
||||
libxmp_virt_resetvoice(ctx, voc, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void libxmp_virt_release(struct context_data *ctx, int chn, int rel)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
libxmp_mixer_release(ctx, voc, rel);
|
||||
}
|
||||
|
||||
void libxmp_virt_setpan(struct context_data *ctx, int chn, int pan)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
libxmp_mixer_setpan(ctx, voc, pan);
|
||||
}
|
||||
|
||||
void libxmp_virt_seteffect(struct context_data *ctx, int chn, int type, int val)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
libxmp_mixer_seteffect(ctx, voc, type, val);
|
||||
}
|
||||
|
||||
double libxmp_virt_getvoicepos(struct context_data *ctx, int chn)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return libxmp_mixer_getvoicepos(ctx, voc);
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
|
||||
void libxmp_virt_setsmp(struct context_data *ctx, int chn, int smp)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi;
|
||||
double pos;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
vi = &p->virt.voice_array[voc];
|
||||
if (vi->smp == smp) {
|
||||
return;
|
||||
}
|
||||
|
||||
pos = libxmp_mixer_getvoicepos(ctx, voc);
|
||||
libxmp_mixer_setpatch(ctx, voc, smp, 0);
|
||||
libxmp_mixer_voicepos(ctx, voc, pos, 0); /* Restore old position */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
|
||||
void libxmp_virt_setnna(struct context_data *ctx, int chn, int nna)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
p->virt.voice_array[voc].act = nna;
|
||||
}
|
||||
|
||||
static void check_dct(struct context_data *ctx, int i, int chn, int ins,
|
||||
int smp, int note, int nna, int dct, int dca)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[i];
|
||||
int voc;
|
||||
|
||||
voc = p->virt.virt_channel[chn].map;
|
||||
|
||||
if (vi->root == chn && vi->ins == ins) {
|
||||
|
||||
if (nna == XMP_INST_NNA_CUT) {
|
||||
libxmp_virt_resetvoice(ctx, i, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
vi->act = nna;
|
||||
|
||||
if ((dct == XMP_INST_DCT_INST) ||
|
||||
(dct == XMP_INST_DCT_SMP && vi->smp == smp) ||
|
||||
(dct == XMP_INST_DCT_NOTE && vi->note == note)) {
|
||||
|
||||
if (nna == XMP_INST_NNA_OFF && dca == XMP_INST_DCA_FADE) {
|
||||
vi->act = VIRT_ACTION_OFF;
|
||||
} else if (dca) {
|
||||
if (i != voc || vi->act) {
|
||||
vi->act = dca;
|
||||
}
|
||||
} else {
|
||||
libxmp_virt_resetvoice(ctx, i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* For note slides */
|
||||
void libxmp_virt_setnote(struct context_data *ctx, int chn, int note)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
libxmp_mixer_setnote(ctx, voc, note);
|
||||
}
|
||||
|
||||
int libxmp_virt_setpatch(struct context_data *ctx, int chn, int ins, int smp,
|
||||
int note, int nna, int dct, int dca)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc, vfree;
|
||||
|
||||
if ((uint32)chn >= p->virt.virt_channels) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ins < 0) {
|
||||
smp = -1;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
if (dct) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
check_dct(ctx, i, chn, ins, smp, note, nna, dct, dca);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
voc = p->virt.virt_channel[chn].map;
|
||||
|
||||
if (voc > FREE) {
|
||||
if (p->virt.voice_array[voc].act) {
|
||||
vfree = alloc_voice(ctx, chn);
|
||||
|
||||
if (vfree < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (chn = p->virt.num_tracks;
|
||||
p->virt.virt_channel[chn++].map > FREE;) ;
|
||||
|
||||
p->virt.voice_array[voc].chn = --chn;
|
||||
p->virt.virt_channel[chn].map = voc;
|
||||
voc = vfree;
|
||||
}
|
||||
} else {
|
||||
voc = alloc_voice(ctx, chn);
|
||||
if (voc < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (smp < 0) {
|
||||
libxmp_virt_resetvoice(ctx, voc, 1);
|
||||
return chn; /* was -1 */
|
||||
}
|
||||
|
||||
libxmp_mixer_setpatch(ctx, voc, smp, 1);
|
||||
libxmp_mixer_setnote(ctx, voc, note);
|
||||
p->virt.voice_array[voc].ins = ins;
|
||||
p->virt.voice_array[voc].act = nna;
|
||||
|
||||
return chn;
|
||||
}
|
||||
|
||||
void libxmp_virt_setperiod(struct context_data *ctx, int chn, double period)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
libxmp_mixer_setperiod(ctx, voc, period);
|
||||
}
|
||||
|
||||
void libxmp_virt_voicepos(struct context_data *ctx, int chn, double pos)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
libxmp_mixer_voicepos(ctx, voc, pos, 1);
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
|
||||
void libxmp_virt_pastnote(struct context_data *ctx, int chn, int act)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int c, voc;
|
||||
|
||||
for (c = p->virt.num_tracks; c < p->virt.virt_channels; c++) {
|
||||
if ((voc = map_virt_channel(p, c)) < 0)
|
||||
continue;
|
||||
|
||||
if (p->virt.voice_array[voc].root == chn) {
|
||||
switch (act) {
|
||||
case VIRT_ACTION_CUT:
|
||||
libxmp_virt_resetvoice(ctx, voc, 1);
|
||||
break;
|
||||
case VIRT_ACTION_OFF:
|
||||
libxmp_player_set_release(ctx, c);
|
||||
break;
|
||||
case VIRT_ACTION_FADE:
|
||||
libxmp_player_set_fadeout(ctx, c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int libxmp_virt_cstat(struct context_data *ctx, int chn)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return VIRT_INVALID;
|
||||
}
|
||||
|
||||
if (chn < p->virt.num_tracks) {
|
||||
return VIRT_ACTIVE;
|
||||
}
|
||||
|
||||
return p->virt.voice_array[voc].act;
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
#ifndef LIBXMP_VIRTUAL_H
|
||||
#define LIBXMP_VIRTUAL_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define VIRT_ACTION_CUT XMP_INST_NNA_CUT
|
||||
#define VIRT_ACTION_CONT XMP_INST_NNA_CONT
|
||||
#define VIRT_ACTION_OFF XMP_INST_NNA_OFF
|
||||
#define VIRT_ACTION_FADE XMP_INST_NNA_FADE
|
||||
|
||||
#define VIRT_ACTIVE 0x100
|
||||
#define VIRT_INVALID -1
|
||||
|
||||
int libxmp_virt_on (struct context_data *, int);
|
||||
void libxmp_virt_off (struct context_data *);
|
||||
int libxmp_virt_mute (struct context_data *, int, int);
|
||||
int libxmp_virt_setpatch (struct context_data *, int, int, int, int,
|
||||
int, int, int);
|
||||
int libxmp_virt_cvt8bit (void);
|
||||
void libxmp_virt_setnote (struct context_data *, int, int);
|
||||
void libxmp_virt_setsmp (struct context_data *, int, int);
|
||||
void libxmp_virt_setnna (struct context_data *, int, int);
|
||||
void libxmp_virt_pastnote (struct context_data *, int, int);
|
||||
void libxmp_virt_setvol (struct context_data *, int, int);
|
||||
void libxmp_virt_voicepos (struct context_data *, int, double);
|
||||
double libxmp_virt_getvoicepos (struct context_data *, int);
|
||||
void libxmp_virt_setperiod (struct context_data *, int, double);
|
||||
void libxmp_virt_setpan (struct context_data *, int, int);
|
||||
void libxmp_virt_seteffect (struct context_data *, int, int, int);
|
||||
int libxmp_virt_cstat (struct context_data *, int);
|
||||
int libxmp_virt_mapchannel (struct context_data *, int);
|
||||
void libxmp_virt_resetchannel(struct context_data *, int);
|
||||
void libxmp_virt_resetvoice (struct context_data *, int, int);
|
||||
void libxmp_virt_reset (struct context_data *);
|
||||
void libxmp_virt_release (struct context_data *, int, int);
|
||||
int libxmp_virt_getroot (struct context_data *, int);
|
||||
|
||||
#endif /* LIBXMP_VIRTUAL_H */
|
|
@ -1,34 +0,0 @@
|
|||
/* _[v]snprintf() from msvcrt.dll might not nul terminate */
|
||||
/* OpenWatcom-provided versions seem to behave the same... */
|
||||
|
||||
#if defined(_WIN32) || defined(__WATCOMC__)
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#undef snprintf
|
||||
#undef vsnprintf
|
||||
|
||||
int libxmp_vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
|
||||
{
|
||||
int rc = _vsnprintf(str, sz, fmt, ap);
|
||||
if (sz != 0) {
|
||||
if (rc < 0) rc = (int)sz;
|
||||
if ((size_t)rc >= sz) str[sz - 1] = '\0';
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libxmp_snprintf (char *str, size_t sz, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int rc;
|
||||
|
||||
va_start (ap, fmt);
|
||||
rc = _vsnprintf(str, sz, fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,101 +0,0 @@
|
|||
#ifndef LIBXMP_LOADERS_XM_H
|
||||
#define LIBXMP_LOADERS_XM_H
|
||||
|
||||
#define XM_EVENT_PACKING 0x80
|
||||
#define XM_EVENT_PACK_MASK 0x7f
|
||||
#define XM_EVENT_NOTE_FOLLOWS 0x01
|
||||
#define XM_EVENT_INSTRUMENT_FOLLOWS 0x02
|
||||
#define XM_EVENT_VOLUME_FOLLOWS 0x04
|
||||
#define XM_EVENT_FXTYPE_FOLLOWS 0x08
|
||||
#define XM_EVENT_FXPARM_FOLLOWS 0x10
|
||||
#define XM_LINEAR_FREQ 0x01
|
||||
#define XM_LOOP_MASK 0x03
|
||||
#define XM_LOOP_NONE 0
|
||||
#define XM_LOOP_FORWARD 1
|
||||
#define XM_LOOP_PINGPONG 2
|
||||
#define XM_SAMPLE_16BIT 0x10
|
||||
#define XM_ENVELOPE_ON 0x01
|
||||
#define XM_ENVELOPE_SUSTAIN 0x02
|
||||
#define XM_ENVELOPE_LOOP 0x04
|
||||
#define XM_LINEAR_PERIOD_MODE 0x01
|
||||
|
||||
|
||||
struct xm_file_header {
|
||||
uint8 id[17]; /* ID text: "Extended module: " */
|
||||
uint8 name[20]; /* Module name, padded with zeroes */
|
||||
uint8 doseof; /* 0x1a */
|
||||
uint8 tracker[20]; /* Tracker name */
|
||||
uint16 version; /* Version number, minor-major */
|
||||
uint32 headersz; /* Header size */
|
||||
uint16 songlen; /* Song length (in patten order table) */
|
||||
uint16 restart; /* Restart position */
|
||||
uint16 channels; /* Number of channels (2,4,6,8,10,...,32) */
|
||||
uint16 patterns; /* Number of patterns (max 256) */
|
||||
uint16 instruments; /* Number of instruments (max 128) */
|
||||
uint16 flags; /* bit 0: 0=Amiga freq table, 1=Linear */
|
||||
uint16 tempo; /* Default tempo */
|
||||
uint16 bpm; /* Default BPM */
|
||||
uint8 order[256]; /* Pattern order table */
|
||||
};
|
||||
|
||||
struct xm_pattern_header {
|
||||
uint32 length; /* Pattern header length */
|
||||
uint8 packing; /* Packing type (always 0) */
|
||||
uint16 rows; /* Number of rows in pattern (1..256) */
|
||||
uint16 datasize; /* Packed patterndata size */
|
||||
};
|
||||
|
||||
struct xm_instrument_header {
|
||||
uint32 size; /* Instrument size */
|
||||
uint8 name[22]; /* Instrument name */
|
||||
uint8 type; /* Instrument type (always 0) */
|
||||
uint16 samples; /* Number of samples in instrument */
|
||||
uint32 sh_size; /* Sample header size */
|
||||
};
|
||||
|
||||
struct xm_instrument {
|
||||
uint8 sample[96]; /* Sample number for all notes */
|
||||
uint16 v_env[24]; /* Points for volume envelope */
|
||||
uint16 p_env[24]; /* Points for panning envelope */
|
||||
uint8 v_pts; /* Number of volume points */
|
||||
uint8 p_pts; /* Number of panning points */
|
||||
uint8 v_sus; /* Volume sustain point */
|
||||
uint8 v_start; /* Volume loop start point */
|
||||
uint8 v_end; /* Volume loop end point */
|
||||
uint8 p_sus; /* Panning sustain point */
|
||||
uint8 p_start; /* Panning loop start point */
|
||||
uint8 p_end; /* Panning loop end point */
|
||||
uint8 v_type; /* Bit 0: On; 1: Sustain; 2: Loop */
|
||||
uint8 p_type; /* Bit 0: On; 1: Sustain; 2: Loop */
|
||||
uint8 y_wave; /* Vibrato waveform */
|
||||
uint8 y_sweep; /* Vibrato sweep */
|
||||
uint8 y_depth; /* Vibrato depth */
|
||||
uint8 y_rate; /* Vibrato rate */
|
||||
uint16 v_fade; /* Volume fadeout */
|
||||
#if 0
|
||||
uint8 reserved[22]; /* Reserved; 2 bytes in specs, 22 in 1.04 */
|
||||
#endif
|
||||
};
|
||||
|
||||
struct xm_sample_header {
|
||||
uint32 length; /* Sample length */
|
||||
uint32 loop_start; /* Sample loop start */
|
||||
uint32 loop_length; /* Sample loop length */
|
||||
uint8 volume; /* Volume */
|
||||
int8 finetune; /* Finetune (signed byte -128..+127) */
|
||||
uint8 type; /* 0=No loop,1=Fwd loop,2=Ping-pong,16-bit */
|
||||
uint8 pan; /* Panning (0-255) */
|
||||
int8 relnote; /* Relative note number (signed byte) */
|
||||
uint8 reserved; /* Reserved */
|
||||
uint8 name[22]; /* Sample_name */
|
||||
};
|
||||
|
||||
struct xm_event {
|
||||
uint8 note; /* Note (0-71, 0 = C-0) */
|
||||
uint8 instrument; /* Instrument (0-128) */
|
||||
uint8 volume; /* Volume column byte */
|
||||
uint8 fx_type; /* Effect type */
|
||||
uint8 fx_parm; /* Effect parameter */
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,789 +0,0 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2018 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fri, 26 Jun 1998 17:45:59 +1000 Andrew Leahy <alf@cit.nepean.uws.edu.au>
|
||||
* Finally got it working on the DEC Alpha running DEC UNIX! In the pattern
|
||||
* reading loop I found I was getting "0" for (p-patbuf) and "0" for
|
||||
* xph.datasize, the next if statement (where it tries to read the patbuf)
|
||||
* would then cause a seg_fault.
|
||||
*
|
||||
* Sun Sep 27 12:07:12 EST 1998 Claudio Matsuoka <claudio@pos.inf.ufpr.br>
|
||||
* Extended Module 1.02 stores data in a different order, we must handle
|
||||
* this accordingly. MAX_SAMP used as a workaround to check the number of
|
||||
* samples recognized by the player.
|
||||
*/
|
||||
|
||||
#include "loader.h"
|
||||
#include "xm.h"
|
||||
|
||||
static int xm_test(HIO_HANDLE *, char *, const int);
|
||||
static int xm_load(struct module_data *, HIO_HANDLE *, const int);
|
||||
|
||||
extern const struct format_loader libxmp_loader_xm;
|
||||
const struct format_loader libxmp_loader_xm = {
|
||||
"Fast Tracker II",
|
||||
xm_test,
|
||||
xm_load
|
||||
};
|
||||
|
||||
static int xm_test(HIO_HANDLE *f, char *t, const int start)
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
if (hio_read(buf, 1, 17, f) < 17) /* ID text */
|
||||
return -1;
|
||||
|
||||
if (memcmp(buf, "Extended Module: ", 17))
|
||||
return -1;
|
||||
|
||||
libxmp_read_title(f, t, 20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_xm_pattern(struct module_data *m, int num, int version, HIO_HANDLE *f)
|
||||
{
|
||||
const int headsize = version > 0x0102 ? 9 : 8;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xm_pattern_header xph;
|
||||
struct xmp_event *event;
|
||||
uint8 *patbuf, *pat, b;
|
||||
int j, r;
|
||||
int size;
|
||||
|
||||
xph.length = hio_read32l(f);
|
||||
xph.packing = hio_read8(f);
|
||||
xph.rows = version > 0x0102 ? hio_read16l(f) : hio_read8(f) + 1;
|
||||
|
||||
/* Sanity check */
|
||||
if (xph.rows > 256) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
xph.datasize = hio_read16l(f);
|
||||
hio_seek(f, xph.length - headsize, SEEK_CUR);
|
||||
if (hio_error(f)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = xph.rows;
|
||||
if (r == 0) {
|
||||
r = 0x100;
|
||||
}
|
||||
|
||||
if (libxmp_alloc_pattern_tracks(mod, num, r) < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (xph.datasize == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = xph.datasize;
|
||||
|
||||
pat = patbuf = (uint8 *)calloc(1, size);
|
||||
if (patbuf == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
hio_read(patbuf, 1, size, f);
|
||||
for (j = 0; j < (mod->chn * r); j++) {
|
||||
|
||||
/*if ((pat - patbuf) >= xph.datasize)
|
||||
break; */
|
||||
|
||||
event = &EVENT(num, j % mod->chn, j / mod->chn);
|
||||
|
||||
if (--size < 0) {
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if ((b = *pat++) & XM_EVENT_PACKING) {
|
||||
if (b & XM_EVENT_NOTE_FOLLOWS) {
|
||||
if (--size < 0)
|
||||
goto err2;
|
||||
event->note = *pat++;
|
||||
}
|
||||
if (b & XM_EVENT_INSTRUMENT_FOLLOWS) {
|
||||
if (--size < 0)
|
||||
goto err2;
|
||||
event->ins = *pat++;
|
||||
}
|
||||
if (b & XM_EVENT_VOLUME_FOLLOWS) {
|
||||
if (--size < 0)
|
||||
goto err2;
|
||||
event->vol = *pat++;
|
||||
}
|
||||
if (b & XM_EVENT_FXTYPE_FOLLOWS) {
|
||||
if (--size < 0)
|
||||
goto err2;
|
||||
event->fxt = *pat++;
|
||||
}
|
||||
if (b & XM_EVENT_FXPARM_FOLLOWS) {
|
||||
if (--size < 0)
|
||||
goto err2;
|
||||
event->fxp = *pat++;
|
||||
}
|
||||
} else {
|
||||
size -= 4;
|
||||
if (size < 0)
|
||||
goto err2;
|
||||
event->note = b;
|
||||
event->ins = *pat++;
|
||||
event->vol = *pat++;
|
||||
event->fxt = *pat++;
|
||||
event->fxp = *pat++;
|
||||
}
|
||||
|
||||
/* Sanity check */
|
||||
switch (event->fxt) {
|
||||
case 18:
|
||||
case 19:
|
||||
case 22:
|
||||
case 23:
|
||||
case 24:
|
||||
case 26:
|
||||
case 28:
|
||||
case 30:
|
||||
case 31:
|
||||
case 32:
|
||||
event->fxt = 0;
|
||||
}
|
||||
if (event->fxt > 34) {
|
||||
event->fxt = 0;
|
||||
}
|
||||
|
||||
if (event->note == 0x61) {
|
||||
/* See OpenMPT keyoff+instr.xm test case */
|
||||
if (event->fxt == 0x0e && MSN(event->fxp) == 0x0d) {
|
||||
event->note = XMP_KEY_OFF;
|
||||
} else {
|
||||
event->note =
|
||||
event->ins ? XMP_KEY_FADE : XMP_KEY_OFF;
|
||||
}
|
||||
} else if (event->note > 0) {
|
||||
event->note += 12;
|
||||
}
|
||||
|
||||
if (event->fxt == 0x0e) {
|
||||
if (MSN(event->fxp) == EX_FINETUNE) {
|
||||
unsigned char val = (LSN(event->fxp) - 8) & 0xf;
|
||||
event->fxp = (EX_FINETUNE << 4) | val;
|
||||
}
|
||||
switch (event->fxp) {
|
||||
case 0x43:
|
||||
case 0x73:
|
||||
event->fxp--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!event->vol) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Volume set */
|
||||
if ((event->vol >= 0x10) && (event->vol <= 0x50)) {
|
||||
event->vol -= 0x0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Volume column effects */
|
||||
switch (event->vol >> 4) {
|
||||
case 0x06: /* Volume slide down */
|
||||
event->f2t = FX_VOLSLIDE_2;
|
||||
event->f2p = event->vol - 0x60;
|
||||
break;
|
||||
case 0x07: /* Volume slide up */
|
||||
event->f2t = FX_VOLSLIDE_2;
|
||||
event->f2p = (event->vol - 0x70) << 4;
|
||||
break;
|
||||
case 0x08: /* Fine volume slide down */
|
||||
event->f2t = FX_EXTENDED;
|
||||
event->f2p =
|
||||
(EX_F_VSLIDE_DN << 4) | (event->vol - 0x80);
|
||||
break;
|
||||
case 0x09: /* Fine volume slide up */
|
||||
event->f2t = FX_EXTENDED;
|
||||
event->f2p =
|
||||
(EX_F_VSLIDE_UP << 4) | (event->vol - 0x90);
|
||||
break;
|
||||
case 0x0a: /* Set vibrato speed */
|
||||
event->f2t = FX_VIBRATO;
|
||||
event->f2p = (event->vol - 0xa0) << 4;
|
||||
break;
|
||||
case 0x0b: /* Vibrato */
|
||||
event->f2t = FX_VIBRATO;
|
||||
event->f2p = event->vol - 0xb0;
|
||||
break;
|
||||
case 0x0c: /* Set panning */
|
||||
event->f2t = FX_SETPAN;
|
||||
event->f2p = (event->vol - 0xc0) << 4;
|
||||
break;
|
||||
case 0x0d: /* Pan slide left */
|
||||
event->f2t = FX_PANSL_NOMEM;
|
||||
event->f2p = (event->vol - 0xd0) << 4;
|
||||
break;
|
||||
case 0x0e: /* Pan slide right */
|
||||
event->f2t = FX_PANSL_NOMEM;
|
||||
event->f2p = event->vol - 0xe0;
|
||||
break;
|
||||
case 0x0f: /* Tone portamento */
|
||||
event->f2t = FX_TONEPORTA;
|
||||
event->f2p = (event->vol - 0xf0) << 4;
|
||||
|
||||
/* From OpenMPT TonePortamentoMemory.xm:
|
||||
* "Another nice bug (...) is the combination of both
|
||||
* portamento commands (Mx and 3xx) in the same cell:
|
||||
* The 3xx parameter is ignored completely, and the Mx
|
||||
* parameter is doubled. (M2 3FF is the same as M4 000)
|
||||
*/
|
||||
if (event->fxt == FX_TONEPORTA
|
||||
|| event->fxt == FX_TONE_VSLIDE) {
|
||||
if (event->fxt == FX_TONEPORTA) {
|
||||
event->fxt = 0;
|
||||
} else {
|
||||
event->fxt = FX_VOLSLIDE;
|
||||
}
|
||||
event->fxp = 0;
|
||||
|
||||
if (event->f2p < 0x80) {
|
||||
event->f2p <<= 1;
|
||||
} else {
|
||||
event->f2p = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/* From OpenMPT porta-offset.xm:
|
||||
* "If there is a portamento command next to an offset
|
||||
* command, the offset command is ignored completely. In
|
||||
* particular, the offset parameter is not memorized."
|
||||
*/
|
||||
if (event->fxt == FX_OFFSET
|
||||
&& event->f2t == FX_TONEPORTA) {
|
||||
event->fxt = event->fxp = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
event->vol = 0;
|
||||
}
|
||||
free(patbuf);
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
free(patbuf);
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int load_patterns(struct module_data *m, int version, HIO_HANDLE *f)
|
||||
{
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, j;
|
||||
|
||||
mod->pat++;
|
||||
if (libxmp_init_pattern(mod) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
D_(D_INFO "Stored patterns: %d", mod->pat - 1);
|
||||
|
||||
for (i = 0; i < mod->pat - 1; i++) {
|
||||
if (load_xm_pattern(m, i, version, f) < 0) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Alloc one extra pattern */
|
||||
{
|
||||
int t = i * mod->chn;
|
||||
|
||||
if (libxmp_alloc_pattern(mod, i) < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
mod->xxp[i]->rows = 64;
|
||||
|
||||
if (libxmp_alloc_track(mod, t, 64) < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (j = 0; j < mod->chn; j++) {
|
||||
mod->xxp[i]->index[j] = t;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Packed structures size */
|
||||
#define XM_INST_HEADER_SIZE 33
|
||||
#define XM_INST_SIZE 208
|
||||
|
||||
static int load_instruments(struct module_data *m, int version, HIO_HANDLE * f)
|
||||
{
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xm_instrument_header xih;
|
||||
struct xm_instrument xi;
|
||||
struct xm_sample_header xsh[16];
|
||||
int sample_num = 0;
|
||||
long total_sample_size;
|
||||
int i, j;
|
||||
uint8 buf[208];
|
||||
|
||||
D_(D_INFO "Instruments: %d", mod->ins);
|
||||
|
||||
/* ESTIMATED value! We don't know the actual value at this point */
|
||||
mod->smp = MAX_SAMPLES;
|
||||
|
||||
if (libxmp_init_instrument(m) < 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
long instr_pos = hio_tell(f);
|
||||
struct xmp_instrument *xxi = &mod->xxi[i];
|
||||
|
||||
/* Modules converted with MOD2XM 1.0 always say we have 31
|
||||
* instruments, but file may end abruptly before that. Also covers
|
||||
* XMLiTE stripped modules and truncated files. This test will not
|
||||
* work if file has trailing garbage.
|
||||
*/
|
||||
if (hio_read(buf, 33, 1, f) != 1) {
|
||||
D_(D_WARN "short read in instrument header data");
|
||||
break;
|
||||
}
|
||||
|
||||
xih.size = readmem32l(buf); /* Instrument size */
|
||||
memcpy(xih.name, buf + 4, 22); /* Instrument name */
|
||||
xih.type = buf[26]; /* Instrument type (always 0) */
|
||||
xih.samples = readmem16l(buf + 27); /* Number of samples */
|
||||
xih.sh_size = readmem32l(buf + 29); /* Sample header size */
|
||||
|
||||
/* Sanity check */
|
||||
if (xih.samples > 0x10 || (xih.samples > 0 && xih.sh_size > 0x100)) {
|
||||
D_(D_CRIT "Sanity check: %d %d", xih.samples, xih.sh_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
libxmp_instrument_name(mod, i, xih.name, 22);
|
||||
|
||||
xxi->nsm = xih.samples;
|
||||
|
||||
D_(D_INFO "[%2X] %-22.22s %2d", i, xxi->name, xxi->nsm);
|
||||
|
||||
if (xxi->nsm == 0) {
|
||||
/* Sample size should be in struct xm_instrument according to
|
||||
* the official format description, but FT2 actually puts it in
|
||||
* struct xm_instrument header. There's a tracker or converter
|
||||
* that follow the specs, so we must handle both cases (see
|
||||
* "Braintomb" by Jazztiz/ART).
|
||||
*/
|
||||
|
||||
/* Umm, Cyke O'Path <cyker@heatwave.co.uk> sent me a couple of
|
||||
* mods ("Breath of the Wind" and "Broken Dimension") that
|
||||
* reserve the instrument data space after the instrument header
|
||||
* even if the number of instruments is set to 0. In these modules
|
||||
* the instrument header size is marked as 263. The following
|
||||
* generalization should take care of both cases.
|
||||
*/
|
||||
|
||||
if (hio_seek(f, (int)xih.size - XM_INST_HEADER_SIZE, SEEK_CUR) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (libxmp_alloc_subinstrument(mod, i, xxi->nsm) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (xih.size < XM_INST_HEADER_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* for BoobieSqueezer (see http://boobie.rotfl.at/)
|
||||
* It works pretty much the same way as Impulse Tracker's sample
|
||||
* only mode, where it will strip off the instrument data.
|
||||
*/
|
||||
if (xih.size < XM_INST_HEADER_SIZE + XM_INST_SIZE) {
|
||||
memset(&xi, 0, sizeof(struct xm_instrument));
|
||||
hio_seek(f, xih.size - XM_INST_HEADER_SIZE, SEEK_CUR);
|
||||
} else {
|
||||
uint8 *b = buf;
|
||||
|
||||
if (hio_read(buf, 208, 1, f) != 1) {
|
||||
D_(D_CRIT "short read in instrument data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(xi.sample, b, 96); /* Sample map */
|
||||
b += 96;
|
||||
|
||||
for (j = 0; j < 24; j++) {
|
||||
xi.v_env[j] = readmem16l(b); /* Points for volume envelope */
|
||||
b += 2;
|
||||
}
|
||||
|
||||
for (j = 0; j < 24; j++) {
|
||||
xi.p_env[j] = readmem16l(b); /* Points for pan envelope */
|
||||
b += 2;
|
||||
}
|
||||
|
||||
xi.v_pts = *b++; /* Number of volume points */
|
||||
xi.p_pts = *b++; /* Number of pan points */
|
||||
xi.v_sus = *b++; /* Volume sustain point */
|
||||
xi.v_start = *b++; /* Volume loop start point */
|
||||
xi.v_end = *b++; /* Volume loop end point */
|
||||
xi.p_sus = *b++; /* Pan sustain point */
|
||||
xi.p_start = *b++; /* Pan loop start point */
|
||||
xi.p_end = *b++; /* Pan loop end point */
|
||||
xi.v_type = *b++; /* Bit 0:On 1:Sustain 2:Loop */
|
||||
xi.p_type = *b++; /* Bit 0:On 1:Sustain 2:Loop */
|
||||
xi.y_wave = *b++; /* Vibrato waveform */
|
||||
xi.y_sweep = *b++; /* Vibrato sweep */
|
||||
xi.y_depth = *b++; /* Vibrato depth */
|
||||
xi.y_rate = *b++; /* Vibrato rate */
|
||||
xi.v_fade = readmem16l(b); /* Volume fadeout */
|
||||
|
||||
/* Skip reserved space */
|
||||
if (hio_seek(f, (int)xih.size - (XM_INST_HEADER_SIZE + XM_INST_SIZE), SEEK_CUR) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Envelope */
|
||||
xxi->rls = xi.v_fade << 1;
|
||||
xxi->aei.npt = xi.v_pts;
|
||||
xxi->aei.sus = xi.v_sus;
|
||||
xxi->aei.lps = xi.v_start;
|
||||
xxi->aei.lpe = xi.v_end;
|
||||
xxi->aei.flg = xi.v_type;
|
||||
xxi->pei.npt = xi.p_pts;
|
||||
xxi->pei.sus = xi.p_sus;
|
||||
xxi->pei.lps = xi.p_start;
|
||||
xxi->pei.lpe = xi.p_end;
|
||||
xxi->pei.flg = xi.p_type;
|
||||
|
||||
if (xxi->aei.npt <= 0 || xxi->aei.npt > 12 /*XMP_MAX_ENV_POINTS */ ) {
|
||||
xxi->aei.flg &= ~XMP_ENVELOPE_ON;
|
||||
} else {
|
||||
memcpy(xxi->aei.data, xi.v_env, xxi->aei.npt * 4);
|
||||
}
|
||||
|
||||
if (xxi->pei.npt <= 0 || xxi->pei.npt > 12 /*XMP_MAX_ENV_POINTS */ ) {
|
||||
xxi->pei.flg &= ~XMP_ENVELOPE_ON;
|
||||
} else {
|
||||
memcpy(xxi->pei.data, xi.p_env, xxi->pei.npt * 4);
|
||||
}
|
||||
|
||||
for (j = 12; j < 108; j++) {
|
||||
xxi->map[j].ins = xi.sample[j - 12];
|
||||
if (xxi->map[j].ins >= xxi->nsm)
|
||||
xxi->map[j].ins = -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < xxi->nsm; j++, sample_num++) {
|
||||
struct xmp_subinstrument *sub = &xxi->sub[j];
|
||||
struct xmp_sample *xxs;
|
||||
uint8 *b = buf;
|
||||
|
||||
if (sample_num >= mod->smp) {
|
||||
mod->xxs = libxmp_realloc_samples(mod->xxs, &mod->smp, mod->smp * 3 / 2);
|
||||
if (mod->xxs == NULL)
|
||||
return -1;
|
||||
}
|
||||
xxs = &mod->xxs[sample_num];
|
||||
|
||||
if (hio_read(buf, 40, 1, f) != 1) {
|
||||
D_(D_CRIT "short read in sample data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
xsh[j].length = readmem32l(b); /* Sample length */
|
||||
b += 4;
|
||||
|
||||
/* Sanity check */
|
||||
if (xsh[j].length > MAX_SAMPLE_SIZE) {
|
||||
D_(D_CRIT "sanity check: %d: bad sample size", j);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xsh[j].loop_start = readmem32l(b); /* Sample loop start */
|
||||
b += 4;
|
||||
xsh[j].loop_length = readmem32l(b); /* Sample loop length */
|
||||
b += 4;
|
||||
xsh[j].volume = *b++; /* Volume */
|
||||
xsh[j].finetune = *b++; /* Finetune (-128..+127) */
|
||||
xsh[j].type = *b++; /* Flags */
|
||||
xsh[j].pan = *b++; /* Panning (0-255) */
|
||||
xsh[j].relnote = *(int8 *) b++; /* Relative note number */
|
||||
xsh[j].reserved = *b++;
|
||||
memcpy(xsh[j].name, b, 22);
|
||||
|
||||
sub->vol = xsh[j].volume;
|
||||
sub->pan = xsh[j].pan;
|
||||
sub->xpo = xsh[j].relnote;
|
||||
sub->fin = xsh[j].finetune;
|
||||
sub->vwf = xi.y_wave;
|
||||
sub->vde = xi.y_depth << 2;
|
||||
sub->vra = xi.y_rate;
|
||||
sub->vsw = xi.y_sweep;
|
||||
sub->sid = sample_num;
|
||||
|
||||
libxmp_copy_adjust(xxs->name, xsh[j].name, 22);
|
||||
|
||||
xxs->len = xsh[j].length;
|
||||
xxs->lps = xsh[j].loop_start;
|
||||
xxs->lpe = xsh[j].loop_start + xsh[j].loop_length;
|
||||
|
||||
xxs->flg = 0;
|
||||
if (xsh[j].type & XM_SAMPLE_16BIT) {
|
||||
xxs->flg |= XMP_SAMPLE_16BIT;
|
||||
xxs->len >>= 1;
|
||||
xxs->lps >>= 1;
|
||||
xxs->lpe >>= 1;
|
||||
}
|
||||
|
||||
xxs->flg |= xsh[j].type & XM_LOOP_FORWARD ? XMP_SAMPLE_LOOP : 0;
|
||||
xxs->flg |= xsh[j].type & XM_LOOP_PINGPONG ? XMP_SAMPLE_LOOP | XMP_SAMPLE_LOOP_BIDIR : 0;
|
||||
}
|
||||
|
||||
total_sample_size = 0;
|
||||
for (j = 0; j < xxi->nsm; j++) {
|
||||
struct xmp_subinstrument *sub = &xxi->sub[j];
|
||||
int flags;
|
||||
|
||||
D_(D_INFO " %1x: %06x%c%06x %06x %c V%02x F%+04d P%02x R%+03d",
|
||||
j, mod->xxs[sub->sid].len,
|
||||
mod->xxs[sub->sid].flg & XMP_SAMPLE_16BIT ? '+' : ' ',
|
||||
mod->xxs[sub->sid].lps,
|
||||
mod->xxs[sub->sid].lpe,
|
||||
mod->xxs[sub->sid].flg & XMP_SAMPLE_LOOP_BIDIR ? 'B' :
|
||||
mod->xxs[sub->sid].flg & XMP_SAMPLE_LOOP ? 'L' : ' ',
|
||||
sub->vol, sub->fin, sub->pan, sub->xpo);
|
||||
|
||||
flags = SAMPLE_FLAG_DIFF;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (xsh[j].reserved == 0xad) {
|
||||
flags = SAMPLE_FLAG_ADPCM;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (version > 0x0103) {
|
||||
if (libxmp_load_sample(m, f, flags, &mod->xxs[sub->sid], NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (flags & SAMPLE_FLAG_ADPCM) {
|
||||
total_sample_size += 16 + ((xsh[j].length + 1) >> 1);
|
||||
} else {
|
||||
total_sample_size += xsh[j].length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reposition correctly in case of 16-bit sample having odd in-file length.
|
||||
* See "Lead Lined for '99", reported by Dennis Mulleneers.
|
||||
*/
|
||||
if (hio_seek(f, instr_pos + xih.size + 40 * xih.samples + total_sample_size, SEEK_SET) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Final sample number adjustment */
|
||||
mod->xxs = libxmp_realloc_samples(mod->xxs, &mod->smp, sample_num);
|
||||
if (mod->xxs == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xm_load(struct module_data *m, HIO_HANDLE * f, const int start)
|
||||
{
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, j;
|
||||
struct xm_file_header xfh;
|
||||
char tracker_name[21];
|
||||
int len;
|
||||
uint8 buf[80];
|
||||
|
||||
LOAD_INIT();
|
||||
|
||||
if (hio_read(buf, 80, 1, f) != 1) {
|
||||
D_(D_CRIT "error reading header");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(xfh.id, buf, 17); /* ID text */
|
||||
memcpy(xfh.name, buf + 17, 20); /* Module name */
|
||||
/* */ /* skip 0x1a */
|
||||
memcpy(xfh.tracker, buf + 38, 20); /* Tracker name */
|
||||
xfh.version = readmem16l(buf + 58); /* Version number, minor-major */
|
||||
xfh.headersz = readmem32l(buf + 60); /* Header size */
|
||||
xfh.songlen = readmem16l(buf + 64); /* Song length */
|
||||
xfh.restart = readmem16l(buf + 66); /* Restart position */
|
||||
xfh.channels = readmem16l(buf + 68); /* Number of channels */
|
||||
xfh.patterns = readmem16l(buf + 70); /* Number of patterns */
|
||||
xfh.instruments = readmem16l(buf + 72); /* Number of instruments */
|
||||
xfh.flags = readmem16l(buf + 74); /* 0=Amiga freq table, 1=Linear */
|
||||
xfh.tempo = readmem16l(buf + 76); /* Default tempo */
|
||||
xfh.bpm = readmem16l(buf + 78); /* Default BPM */
|
||||
|
||||
/* Sanity checks */
|
||||
if (xfh.songlen > 256 || xfh.patterns > 256 || xfh.instruments > 255) {
|
||||
D_(D_CRIT "Sanity check: %d %d %d", xfh.songlen, xfh.patterns, xfh.instruments);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (xfh.restart > 255 || xfh.channels > XMP_MAX_CHANNELS) {
|
||||
D_(D_CRIT "Sanity check: %d %d", xfh.restart, xfh.channels);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (xfh.tempo >= 32 || xfh.bpm < 32 || xfh.bpm > 255) {
|
||||
if (memcmp("MED2XM", xfh.tracker, 6)) {
|
||||
D_(D_CRIT "Sanity check: %d %d", xfh.tempo, xfh.bpm);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Honor header size -- needed by BoobieSqueezer XMs */
|
||||
len = xfh.headersz - 0x14;
|
||||
if (len < 0 || len > 256) {
|
||||
D_(D_CRIT "Sanity check: %d", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hio_read(&xfh.order, len, 1, f) != 1) { /* Pattern order table */
|
||||
D_(D_CRIT "error reading orders");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(mod->name, (char *)xfh.name, 20);
|
||||
|
||||
mod->len = xfh.songlen;
|
||||
mod->chn = xfh.channels;
|
||||
mod->pat = xfh.patterns;
|
||||
mod->ins = xfh.instruments;
|
||||
mod->rst = xfh.restart;
|
||||
mod->spd = xfh.tempo;
|
||||
mod->bpm = xfh.bpm;
|
||||
mod->trk = mod->chn * mod->pat + 1;
|
||||
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->period_type = xfh.flags & XM_LINEAR_PERIOD_MODE ? PERIOD_LINEAR : PERIOD_AMIGA;
|
||||
|
||||
memcpy(mod->xxo, xfh.order, mod->len);
|
||||
/*tracker_name[20] = 0;*/
|
||||
snprintf(tracker_name, 21, "%-20.20s", xfh.tracker);
|
||||
for (i = 20; i >= 0; i--) {
|
||||
if (tracker_name[i] == 0x20)
|
||||
tracker_name[i] = 0;
|
||||
if (tracker_name[i])
|
||||
break;
|
||||
}
|
||||
|
||||
/* OpenMPT accurately emulates weird FT2 bugs */
|
||||
if (!strncmp(tracker_name, "FastTracker v2.00", 17) ||
|
||||
!strncmp(tracker_name, "OpenMPT ", 8)) {
|
||||
m->quirk |= QUIRK_FT2BUGS;
|
||||
}
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (xfh.headersz == 0x0113) {
|
||||
strcpy(tracker_name, "unknown tracker");
|
||||
m->quirk &= ~QUIRK_FT2BUGS;
|
||||
} else if (*tracker_name == 0) {
|
||||
strcpy(tracker_name, "Digitrakker"); /* best guess */
|
||||
m->quirk &= ~QUIRK_FT2BUGS;
|
||||
}
|
||||
|
||||
/* See MMD1 loader for explanation */
|
||||
if (!strncmp(tracker_name, "MED2XM by J.Pynnone", 19)) {
|
||||
if (mod->bpm <= 10) {
|
||||
mod->bpm = 125 * (0x35 - mod->bpm * 2) / 33;
|
||||
}
|
||||
m->quirk &= ~QUIRK_FT2BUGS;
|
||||
}
|
||||
|
||||
if (!strncmp(tracker_name, "FastTracker v 2.00", 18)) {
|
||||
strcpy(tracker_name, "old ModPlug Tracker");
|
||||
m->quirk &= ~QUIRK_FT2BUGS;
|
||||
}
|
||||
|
||||
libxmp_set_type(m, "%s XM %d.%02d", tracker_name, xfh.version >> 8, xfh.version & 0xff);
|
||||
#else
|
||||
libxmp_set_type(m, tracker_name);
|
||||
#endif
|
||||
|
||||
MODULE_INFO();
|
||||
|
||||
/* Honor header size */
|
||||
if (hio_seek(f, start + xfh.headersz + 60, SEEK_SET) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* XM 1.02/1.03 has a different patterns and instruments order */
|
||||
if (xfh.version <= 0x0103) {
|
||||
if (load_instruments(m, xfh.version, f) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (load_patterns(m, xfh.version, f) < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (load_patterns(m, xfh.version, f) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (load_instruments(m, xfh.version, f) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
D_(D_INFO "Stored samples: %d", mod->smp);
|
||||
|
||||
/* XM 1.02 stores all samples after the patterns */
|
||||
if (xfh.version <= 0x0103) {
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
for (j = 0; j < mod->xxi[i].nsm; j++) {
|
||||
int sid = mod->xxi[i].sub[j].sid;
|
||||
if (libxmp_load_sample(m, f, SAMPLE_FLAG_DIFF, &mod->xxs[sid], NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < mod->chn; i++) {
|
||||
mod->xxc[i].pan = 0x80;
|
||||
}
|
||||
|
||||
m->quirk |= QUIRKS_FT2;
|
||||
m->read_event_type = READ_EVENT_FT2;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue