- removed libxmp.

This commit is contained in:
Christoph Oelckers 2019-11-11 19:12:04 +01:00
parent ec6ce8b1ec
commit 9782b8180a
47 changed files with 0 additions and 17726 deletions

View file

@ -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.

View file

@ -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 */

View file

@ -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);
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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 vibratos 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;
}

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 Trackers 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;
}

View file

@ -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 */

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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 */

View file

@ -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

View file

@ -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

View file

@ -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;
}