mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-17 18:01:13 +00:00
265 lines
6.7 KiB
C
265 lines
6.7 KiB
C
|
/* 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 "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);
|
||
|
|
||
|
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;
|
||
|
}
|