mirror of
https://github.com/Fledge68/WiiFlow_Lite.git
synced 2024-12-29 13:21:52 +01:00
770 lines
20 KiB
C
770 lines
20 KiB
C
|
/*
|
||
|
* Copyright (c) 2002, 2003, 2004, 2005, 2007 by Christian Nowak <chnowak@web.de>
|
||
|
* Last update: 20th October, 2007
|
||
|
*/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <math.h>
|
||
|
|
||
|
#include "modplay.h"
|
||
|
#include "effects.h"
|
||
|
#include "xm.h"
|
||
|
|
||
|
|
||
|
#define DESCRIPTION "Triton FastTracker II Extended Module"
|
||
|
#define AUTHOR "Christian Nowak <chnowak@web.de>, http://chn.roarvgm.com/"
|
||
|
#define VERSION "v0.01b"
|
||
|
#define COPYRIGHT "Copyright (c) 2003, 2007"
|
||
|
|
||
|
|
||
|
|
||
|
#define SAFE_MALLOC(dest, a) \
|
||
|
dest = malloc(a); \
|
||
|
if (dest == NULL) { \
|
||
|
MODFILE_Free(xm); \
|
||
|
return -2; \
|
||
|
}
|
||
|
|
||
|
static int xmfinetab[] = {
|
||
|
|
||
|
7893, 7897, 7900, 7904, 7907, 7911, 7915, 7918, 7922, 7925, 7929, 7932, 7936, 7940, 7943, 7947,
|
||
|
7950, 7954, 7958, 7961, 7965, 7968, 7972, 7975, 7979, 7983, 7986, 7990, 7993, 7997, 8001, 8004,
|
||
|
8008, 8012, 8015, 8019, 8022, 8026, 8030, 8033, 8037, 8041, 8044, 8048, 8051, 8055, 8059, 8062,
|
||
|
8066, 8070, 8073, 8077, 8081, 8084, 8088, 8091, 8095, 8099, 8102, 8106, 8110, 8113, 8117, 8121,
|
||
|
8124, 8128, 8132, 8135, 8139, 8143, 8146, 8150, 8154, 8157, 8161, 8165, 8169, 8172, 8176, 8180,
|
||
|
8183, 8187, 8191, 8194, 8198, 8202, 8205, 8209, 8213, 8217, 8220, 8224, 8228, 8231, 8235, 8239,
|
||
|
8243, 8246, 8250, 8254, 8257, 8261, 8265, 8269, 8272, 8276, 8280, 8284, 8287, 8291, 8295, 8299,
|
||
|
8302, 8306, 8310, 8314, 8317, 8321, 8325, 8329, 8332, 8336, 8340, 8344, 8347, 8351, 8355, 8359,
|
||
|
8363, 8366, 8370, 8374, 8378, 8381, 8385, 8389, 8393, 8397, 8400, 8404, 8408, 8412, 8416, 8419,
|
||
|
8423, 8427, 8431, 8435, 8438, 8442, 8446, 8450, 8454, 8457, 8461, 8465, 8469, 8473, 8476, 8480,
|
||
|
8484, 8488, 8492, 8496, 8499, 8503, 8507, 8511, 8515, 8519, 8523, 8526, 8530, 8534, 8538, 8542,
|
||
|
8546, 8549, 8553, 8557, 8561, 8565, 8569, 8573, 8577, 8580, 8584, 8588, 8592, 8596, 8600, 8604,
|
||
|
8608, 8611, 8615, 8619, 8623, 8627, 8631, 8635, 8639, 8643, 8646, 8650, 8654, 8658, 8662, 8666,
|
||
|
8670, 8674, 8678, 8682, 8686, 8690, 8693, 8697, 8701, 8705, 8709, 8713, 8717, 8721, 8725, 8729,
|
||
|
8733, 8737, 8741, 8745, 8749, 8752, 8756, 8760, 8764, 8768, 8772, 8776, 8780, 8784, 8788, 8792,
|
||
|
8796, 8800, 8804, 8808, 8812, 8816, 8820, 8824, 8828, 8832, 8836, 8840, 8844, 8848, 8852, 8856
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
static u32 getu32(u8 *d) {
|
||
|
|
||
|
return d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
|
||
|
}
|
||
|
|
||
|
static u16 getu16(u8 *d) {
|
||
|
|
||
|
return d[0] | (d[1] << 8);
|
||
|
}
|
||
|
|
||
|
static int xmgetfinefreq(int fine) {
|
||
|
|
||
|
/* double fact = pow(2.0, 2.0 / 12.0);*/
|
||
|
|
||
|
return xmfinetab[fine + 128];
|
||
|
/* return (int)(8363.0 * pow(fact, (double)fine / (double)steps));*/
|
||
|
/*return 8363;*/
|
||
|
}
|
||
|
|
||
|
static void convertXMVolume(u8 v, u16 *e, u8 *o) {
|
||
|
|
||
|
switch (v >> 4) {
|
||
|
|
||
|
case 0x06: /* Volume slide down */
|
||
|
*e = EFFECT_XMa0;
|
||
|
*o = v & 0x0f;
|
||
|
break;
|
||
|
|
||
|
case 0x07: /* Volume slide up */
|
||
|
*e = EFFECT_XMa0;
|
||
|
*o = (v & 0x0f) << 4;
|
||
|
break;
|
||
|
|
||
|
case 0x08: /* Fine volume slide down */
|
||
|
*e = EFFECT_STeb;
|
||
|
*o = v & 0x0f;
|
||
|
break;
|
||
|
|
||
|
case 0x09: /* Fine volume slide up */
|
||
|
*e = EFFECT_STea;
|
||
|
*o = v & 0x0f;
|
||
|
break;
|
||
|
|
||
|
case 0x0c: /* Set panning */
|
||
|
*e = EFFECT_ST80;
|
||
|
*o = (v & 0x0f) << 4;
|
||
|
break;
|
||
|
|
||
|
case 0x0d: /* Panning slide left */
|
||
|
*e = EFFECT_XM19;
|
||
|
*o = v & 0x0f;
|
||
|
break;
|
||
|
|
||
|
case 0x0e: /* Panning slide right */
|
||
|
*e = EFFECT_XM19;
|
||
|
*o = (v & 0x0f) << 4;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void convertXMEffects(MODFILE *mod, int pattern, int pline, u8 effect, u8 operand, u16 *e, u8 *o) {
|
||
|
|
||
|
if ((e == NULL) || (o == NULL))
|
||
|
return;
|
||
|
|
||
|
*o = operand;
|
||
|
|
||
|
switch (effect) {
|
||
|
|
||
|
case 0x00: /* Arpeggio */
|
||
|
if (operand != 0)
|
||
|
*e = EFFECT_ST00;
|
||
|
else
|
||
|
*e = EFFECT_NONE;
|
||
|
break;
|
||
|
case 0x01: /* Porta up */
|
||
|
*e = EFFECT_XM01;
|
||
|
break;
|
||
|
case 0x02: /* Porta down */
|
||
|
*e = EFFECT_XM02;
|
||
|
break;
|
||
|
case 0x03: /* Porta to note */
|
||
|
*e = EFFECT_ST30;
|
||
|
break;
|
||
|
case 0x04: /* Vibrato */
|
||
|
*e = EFFECT_ST40;
|
||
|
break;
|
||
|
case 0x05: /* Porta + volume slide */
|
||
|
*e = EFFECT_ST50;
|
||
|
break;
|
||
|
case 0x06: /* Vibrato + volume slide */
|
||
|
*e = EFFECT_ST60;
|
||
|
break;
|
||
|
case 0x07: /* Tremolo */
|
||
|
*e = EFFECT_ST70;
|
||
|
break;
|
||
|
case 0x08: /* Panning */
|
||
|
*e = EFFECT_ST80;
|
||
|
break;
|
||
|
case 0x09: /* Sample offset */
|
||
|
*e = EFFECT_ST90;
|
||
|
break;
|
||
|
case 0x0a: /* Volume slide */
|
||
|
*e = EFFECT_XMa0;
|
||
|
break;
|
||
|
case 0x0b: /* Pattern jump */
|
||
|
mod->patterns[pattern][(pline * mod->nChannels) + mod->nChannels - 1].effect[0] = EFFECT_STb0;
|
||
|
mod->patterns[pattern][(pline * mod->nChannels) + mod->nChannels - 1].operand[0] = operand;
|
||
|
effect = EFFECT_NONE;
|
||
|
break;
|
||
|
case 0x0c: /* Set volume */
|
||
|
*e = EFFECT_STc0;
|
||
|
if (operand > 64)
|
||
|
operand = 64;
|
||
|
*o = operand;
|
||
|
break;
|
||
|
case 0x0d: /* Pattern break */
|
||
|
operand = ((operand >> 4) * 10) + (operand & 0x0f);
|
||
|
mod->patterns[pattern][(pline * mod->nChannels) + mod->nChannels - 1].effect[0] = EFFECT_STd0;
|
||
|
mod->patterns[pattern][(pline * mod->nChannels) + mod->nChannels - 1].operand[0] = operand;
|
||
|
*e = EFFECT_NONE;
|
||
|
break;
|
||
|
case 0x0e:
|
||
|
switch (operand >> 4) {
|
||
|
|
||
|
int temp;
|
||
|
|
||
|
case 0x01: /* Fine porta up */
|
||
|
*e = EFFECT_STe1;
|
||
|
*o = operand & 0x0f;
|
||
|
break;
|
||
|
case 0x02: /* Fine porta down */
|
||
|
*e = EFFECT_STe2;
|
||
|
*o = operand & 0x0f;
|
||
|
break;
|
||
|
case 0x04: /* Set vibrato waveform */
|
||
|
*e = EFFECT_STe4;
|
||
|
*o = operand & 0x0f;
|
||
|
break;
|
||
|
case 0x05: /* Set finetune */
|
||
|
*e = EFFECT_STe5;
|
||
|
temp = operand & 0x0f;
|
||
|
if (temp > 7) temp -= 16;
|
||
|
temp += 8;
|
||
|
*o = operand & 0x0f;
|
||
|
break;
|
||
|
case 0x06: /* Pattern loop */
|
||
|
operand = operand & 0x0f;
|
||
|
mod->patterns[pattern][(pline * mod->nChannels) + mod->nChannels - 1].effect[0] = EFFECT_STe6;
|
||
|
mod->patterns[pattern][(pline * mod->nChannels) + mod->nChannels - 1].operand[0] = operand;
|
||
|
*e = EFFECT_NONE;
|
||
|
*o = 0;
|
||
|
break;
|
||
|
case 0x07: /* Set tremolo waveform */
|
||
|
*e = EFFECT_STe7;
|
||
|
*o = operand & 0x0f;
|
||
|
break;
|
||
|
case 0x08: /* Panning */
|
||
|
*e = EFFECT_STe8;
|
||
|
*o = operand & 0x0f;
|
||
|
break;
|
||
|
case 0x09: /* Retrig */
|
||
|
*e = EFFECT_STe9;
|
||
|
*o = operand & 0x0f;
|
||
|
break;
|
||
|
case 0x0a: /* Fine volume slide up */
|
||
|
*e = EFFECT_STea;
|
||
|
*o = operand & 0x0f;
|
||
|
break;
|
||
|
case 0x0b: /* Fine volume slide down */
|
||
|
*e = EFFECT_STeb;
|
||
|
*o = operand & 0x0f;
|
||
|
break;
|
||
|
case 0x0c: /* Note cut */
|
||
|
*e = EFFECT_STec;
|
||
|
*o = operand & 0x0f;
|
||
|
break;
|
||
|
case 0x0d: /* Note delay */
|
||
|
*e = EFFECT_STed;
|
||
|
*o = operand & 0x0f;
|
||
|
break;
|
||
|
case 0x0e: /* Pattern delay */
|
||
|
operand = operand & 0x0f;
|
||
|
mod->patterns[pattern][(pline * mod->nChannels) + mod->nChannels - 1].effect[0] = EFFECT_STee;
|
||
|
mod->patterns[pattern][(pline * mod->nChannels) + mod->nChannels - 1].operand[0] = operand;
|
||
|
*e = EFFECT_NONE;
|
||
|
*o = 0;
|
||
|
break;
|
||
|
default:
|
||
|
*e = EFFECT_NONE;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 0x0f: /* Set speed/tempo */
|
||
|
*e = EFFECT_STf0;
|
||
|
break;
|
||
|
case 0x10: /* Global volume */
|
||
|
*e = EFFECT_XM10;
|
||
|
break;
|
||
|
case 0x11: /* Global volume slide */
|
||
|
*e = EFFECT_XM11;
|
||
|
break;
|
||
|
case 0x19: /* Panning slide */
|
||
|
*e = EFFECT_XM19;
|
||
|
break;
|
||
|
default:
|
||
|
*e = EFFECT_NONE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int MODFILE_SetXM(u8 *xmfile, int xmlength, MODFILE *xm) {
|
||
|
|
||
|
int ofs = 0;
|
||
|
int bak;
|
||
|
int headersize;
|
||
|
int nSamples = 0;
|
||
|
int i;
|
||
|
int sampleOfs;
|
||
|
|
||
|
if (!MODFILE_IsXM(xmfile, xmlength))
|
||
|
return -1;
|
||
|
|
||
|
memcpy(xm->songname, &xmfile[17], 20);
|
||
|
xm->songname[17] = '\0';
|
||
|
|
||
|
ofs = 60;
|
||
|
headersize = getu32(&xmfile[ofs]);
|
||
|
xm->songlength = getu16(&xmfile[ofs + 4]);
|
||
|
xm->restart_position = getu16(&xmfile[ofs + 6]);
|
||
|
xm->nChannels = getu16(&xmfile[ofs + 8]);
|
||
|
xm->nChannels++;
|
||
|
xm->nPatterns = getu16(&xmfile[ofs + 10]);
|
||
|
xm->nInstruments = getu16(&xmfile[ofs + 12]);
|
||
|
if (getu16(&xmfile[ofs + 14]) & 1)
|
||
|
xm->period_type = 1;
|
||
|
else
|
||
|
xm->period_type = 0;
|
||
|
xm->start_tempo = getu16(&xmfile[ofs + 18]);
|
||
|
xm->start_speed = getu16(&xmfile[ofs + 16]);
|
||
|
memcpy(xm->playlist, &xmfile[ofs + 20], 256);
|
||
|
|
||
|
ofs += headersize;
|
||
|
|
||
|
/* Load patterns */
|
||
|
SAFE_MALLOC(xm->patterns, sizeof(MOD_Note*) * xm->nPatterns);
|
||
|
SAFE_MALLOC(xm->patternLengths, sizeof(int) * xm->nPatterns);
|
||
|
/* xm->patterns = malloc(sizeof(MOD_Note*) * xm->nPatterns);
|
||
|
xm->patternLengths = malloc(sizeof(int) * xm->nPatterns);*/
|
||
|
|
||
|
for (i = 0; i < xm->nPatterns; i++) {
|
||
|
|
||
|
int packedSize;
|
||
|
|
||
|
headersize = getu32(&xmfile[ofs]);
|
||
|
xm->patternLengths[i] = getu16(&xmfile[ofs + 5]);
|
||
|
packedSize = getu16(&xmfile[ofs + 7]);
|
||
|
ofs += headersize;
|
||
|
|
||
|
SAFE_MALLOC(xm->patterns[i], xm->patternLengths[i] * xm->nChannels * sizeof(MOD_Note));
|
||
|
/* xm->patterns[i] = malloc(xm->patternLengths[i] * xm->nChannels * sizeof(MOD_Note));*/
|
||
|
MODFILE_ClearPattern(xm, i);
|
||
|
|
||
|
if (packedSize != 0) { /* There is patterndata */
|
||
|
|
||
|
int ppt = ofs;
|
||
|
int pline, pchannel;
|
||
|
|
||
|
for (pline = 0; pline < xm->patternLengths[i]; pline++) {
|
||
|
|
||
|
for (pchannel = 0; pchannel < xm->nChannels - 1; pchannel++) {
|
||
|
|
||
|
MOD_Note *destNote = &xm->patterns[i][(pline * xm->nChannels) + pchannel];
|
||
|
|
||
|
if (xmfile[ppt] & 0x80) { /* A packed note */
|
||
|
|
||
|
u8 t = xmfile[ppt++];
|
||
|
u8 effect = 0x00;
|
||
|
u8 operand = 0x00;
|
||
|
|
||
|
if (t & 1) {
|
||
|
|
||
|
u8 note = xmfile[ppt++];
|
||
|
|
||
|
if (note == 97) { /* A key off */
|
||
|
|
||
|
destNote->note = 0xfe;
|
||
|
} else {
|
||
|
|
||
|
note--;
|
||
|
destNote->note = ((note / 12) << 4) | (note % 12);
|
||
|
}
|
||
|
}
|
||
|
if (t & 2) {
|
||
|
|
||
|
u8 instrument = xmfile[ppt++];
|
||
|
destNote->instrument = instrument;
|
||
|
}
|
||
|
if (t & 4) {
|
||
|
|
||
|
u8 volume = xmfile[ppt++];
|
||
|
if (volume == 0)
|
||
|
destNote->volume = 0xff;
|
||
|
else
|
||
|
if (volume < 0x10 || volume > 0x50) {
|
||
|
|
||
|
destNote->volume = 0xff;
|
||
|
convertXMVolume(volume, &destNote->effect[0], &destNote->operand[0]);
|
||
|
} else {
|
||
|
|
||
|
destNote->volume = volume - 0x10;
|
||
|
}
|
||
|
}
|
||
|
if (t & 8) {
|
||
|
|
||
|
effect = xmfile[ppt++];
|
||
|
}
|
||
|
if (t & 16) {
|
||
|
|
||
|
operand = xmfile[ppt++];
|
||
|
}
|
||
|
|
||
|
convertXMEffects(xm, i, pline, effect, operand, &destNote->effect[1], &destNote->operand[1]);
|
||
|
|
||
|
} else { /* Not a packed note */
|
||
|
|
||
|
u8 t;
|
||
|
u8 t2;
|
||
|
|
||
|
t = xmfile[ppt++];
|
||
|
|
||
|
if (t == 97) { /* A key off */
|
||
|
|
||
|
destNote->note = 0xfe;
|
||
|
} else {
|
||
|
|
||
|
t--;
|
||
|
destNote->note = ((t / 12) << 4) | (t % 12);
|
||
|
}
|
||
|
|
||
|
destNote->instrument = xmfile[ppt++];
|
||
|
|
||
|
t = xmfile[ppt++];
|
||
|
if (t == 0)
|
||
|
destNote->volume = 0xff;
|
||
|
else
|
||
|
if (t < 0x10 || t > 0x50) {
|
||
|
|
||
|
destNote->volume = 0xff;
|
||
|
convertXMVolume(t, &destNote->effect[0], &destNote->operand[0]);
|
||
|
} else {
|
||
|
|
||
|
destNote->volume = t - 0x10;
|
||
|
}
|
||
|
|
||
|
t = xmfile[ppt++];
|
||
|
t2 = xmfile[ppt++];
|
||
|
convertXMEffects(xm, i, pline, t, t2, &destNote->effect[1], &destNote->operand[1]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
ofs += packedSize;
|
||
|
}
|
||
|
|
||
|
/* Calculate number of samples */
|
||
|
bak = ofs;
|
||
|
nSamples = 0;
|
||
|
for (i = 0; i < xm->nInstruments; i++) {
|
||
|
|
||
|
int sheadersize = 0;
|
||
|
int samplesininstr;
|
||
|
int sampledatasize = 0;
|
||
|
|
||
|
headersize = getu32(&xmfile[ofs]);
|
||
|
samplesininstr = getu16(&xmfile[ofs + 27]);
|
||
|
|
||
|
if (samplesininstr > 0)
|
||
|
sheadersize = getu32(&xmfile[ofs + 29]);
|
||
|
|
||
|
ofs += headersize;
|
||
|
|
||
|
if (samplesininstr > 0) {
|
||
|
|
||
|
int j;
|
||
|
|
||
|
nSamples += samplesininstr;
|
||
|
|
||
|
for (j = 0; j < samplesininstr; j++) {
|
||
|
|
||
|
int ssize = getu32(&xmfile[ofs + 0]);
|
||
|
sampledatasize += ssize;
|
||
|
/* if (ssize == 0)
|
||
|
nSamples--;*/
|
||
|
|
||
|
ofs += sheadersize;
|
||
|
}
|
||
|
}
|
||
|
ofs += sampledatasize;
|
||
|
}
|
||
|
ofs = bak;
|
||
|
|
||
|
xm->nSamples = nSamples;
|
||
|
|
||
|
/* Load instruments */
|
||
|
/* xm->samples = malloc(xm->nSamples * sizeof(MOD_Sample));*/
|
||
|
SAFE_MALLOC(xm->samples, xm->nSamples * sizeof(MOD_Sample));
|
||
|
memset(xm->samples, 0, xm->nSamples * sizeof(MOD_Sample));
|
||
|
/* xm->instruments = malloc(xm->nInstruments * sizeof(MOD_Instrument));*/
|
||
|
SAFE_MALLOC(xm->instruments, xm->nInstruments * sizeof(MOD_Instrument));
|
||
|
memset(xm->instruments, 0, xm->nInstruments * sizeof(MOD_Instrument));
|
||
|
|
||
|
sampleOfs = 0;
|
||
|
|
||
|
for (i = 0; i < xm->nInstruments; i++) {
|
||
|
|
||
|
int sheadersize = 0;
|
||
|
int samplesininstr;
|
||
|
int j;
|
||
|
|
||
|
headersize = getu32(&xmfile[ofs]);
|
||
|
samplesininstr = getu16(&xmfile[ofs + 27]);
|
||
|
memcpy(xm->instruments[i].name, &xmfile[ofs + 4], 22);
|
||
|
xm->instruments[i].name[22] = '\0';
|
||
|
|
||
|
/* Instrument note -> Sample note mapping */
|
||
|
for (j = 0; j < 256; j++) {
|
||
|
|
||
|
xm->instruments[i].note[j] = j;
|
||
|
}
|
||
|
|
||
|
/* Sample number for all notes */
|
||
|
for (j = 0; j < 256; j++) {
|
||
|
|
||
|
xm->instruments[i].samples[j] = NULL;
|
||
|
}
|
||
|
|
||
|
if (samplesininstr > 0) {
|
||
|
|
||
|
sheadersize = getu32(&xmfile[ofs + 29]);
|
||
|
|
||
|
/* Volume Fade */
|
||
|
xm->instruments[i].volumeFade = getu16(&xmfile[ofs + 239]);
|
||
|
|
||
|
/* Sample number for all notes */
|
||
|
for (j = 0; j < 96; j++) {
|
||
|
|
||
|
u8 dnote = ((j / 12) << 4) | (j % 12);
|
||
|
|
||
|
xm->instruments[i].samples[dnote] = &xm->samples[(int)(unsigned int)xmfile[ofs + 33 + j] + sampleOfs];
|
||
|
}
|
||
|
|
||
|
/* Volume envelope */
|
||
|
if ((xmfile[ofs + 233] & 1) && (xmfile[ofs + 225] > 0)) {
|
||
|
|
||
|
xm->instruments[i].envVolume.enabled = TRUE;
|
||
|
xm->instruments[i].envVolume.numPoints = xmfile[ofs + 225];
|
||
|
|
||
|
/* Looping */
|
||
|
if (xmfile[ofs + 233] & 4) {
|
||
|
|
||
|
xm->instruments[i].envVolume.loop_start = xmfile[ofs + 228];
|
||
|
xm->instruments[i].envVolume.loop_end = xmfile[ofs + 229];
|
||
|
} else {
|
||
|
|
||
|
xm->instruments[i].envVolume.loop_start = 255;
|
||
|
xm->instruments[i].envVolume.loop_end = 255;
|
||
|
}
|
||
|
|
||
|
/* Sustain */
|
||
|
if (xmfile[ofs + 233] & 2) {
|
||
|
|
||
|
xm->instruments[i].envVolume.sustain = xmfile[ofs + 227];
|
||
|
} else {
|
||
|
|
||
|
xm->instruments[i].envVolume.sustain = 255;
|
||
|
}
|
||
|
|
||
|
/* Envelope points */
|
||
|
xm->instruments[i].envVolume.envPoints = malloc(sizeof(EnvPoint) * (int)xm->instruments[i].envVolume.numPoints);
|
||
|
for (j = 0; j < xm->instruments[i].envVolume.numPoints; j++) {
|
||
|
|
||
|
xm->instruments[i].envVolume.envPoints[j].x = getu16(&xmfile[ofs + 129 + (j * 4)]);
|
||
|
xm->instruments[i].envVolume.envPoints[j].y = getu16(&xmfile[ofs + 129 + (j * 4) + 2]);
|
||
|
}
|
||
|
} else {
|
||
|
|
||
|
xm->instruments[i].envVolume.enabled = FALSE;
|
||
|
}
|
||
|
|
||
|
/* Panning envelope */
|
||
|
if ((xmfile[ofs + 234] & 1) && (xmfile[ofs + 226] > 0)) {
|
||
|
|
||
|
xm->instruments[i].envPanning.enabled = TRUE;
|
||
|
xm->instruments[i].envPanning.numPoints = xmfile[ofs + 226];
|
||
|
|
||
|
/* Looping */
|
||
|
if (xmfile[ofs + 234] & 4) {
|
||
|
|
||
|
xm->instruments[i].envPanning.loop_start = xmfile[ofs + 231];
|
||
|
xm->instruments[i].envPanning.loop_end = xmfile[ofs + 232];
|
||
|
} else {
|
||
|
|
||
|
xm->instruments[i].envPanning.loop_start = 255;
|
||
|
xm->instruments[i].envPanning.loop_end = 255;
|
||
|
}
|
||
|
|
||
|
/* Sustain */
|
||
|
if (xmfile[ofs + 234] & 2) {
|
||
|
|
||
|
xm->instruments[i].envPanning.sustain = xmfile[ofs + 230];
|
||
|
} else {
|
||
|
|
||
|
xm->instruments[i].envPanning.sustain = 255;
|
||
|
}
|
||
|
|
||
|
/* Envelope points */
|
||
|
xm->instruments[i].envPanning.envPoints = malloc(sizeof(EnvPoint) * (int)xm->instruments[i].envPanning.numPoints);
|
||
|
for (j = 0; j < xm->instruments[i].envPanning.numPoints; j++) {
|
||
|
|
||
|
xm->instruments[i].envPanning.envPoints[j].x = getu16(&xmfile[ofs + 177 + (j * 4)]);
|
||
|
xm->instruments[i].envPanning.envPoints[j].y = getu16(&xmfile[ofs + 177 + (j * 4) + 2]);
|
||
|
}
|
||
|
} else {
|
||
|
|
||
|
xm->instruments[i].envPanning.enabled = FALSE;
|
||
|
}
|
||
|
|
||
|
ofs += headersize; /* Go to the sample headers */
|
||
|
|
||
|
/* Read sample headers */
|
||
|
for (j = 0; j < samplesininstr; j++) {
|
||
|
|
||
|
u8 flag = xmfile[ofs + 14];
|
||
|
|
||
|
xm->samples[sampleOfs + j].default_volume = 64;
|
||
|
xm->samples[sampleOfs + j].middle_c =
|
||
|
xm->samples[sampleOfs + j].default_middle_c = xmgetfinefreq((int)(s8)xmfile[ofs + 13]);
|
||
|
xm->samples[sampleOfs + j].finetune = (s8)xmfile[ofs + 13];
|
||
|
|
||
|
xm->samples[sampleOfs + j].panning = xmfile[ofs + 15] >> 2;
|
||
|
xm->samples[sampleOfs + j].default_volume =
|
||
|
xm->samples[sampleOfs + j].volume = xmfile[ofs + 12];
|
||
|
memcpy(xm->samples[sampleOfs + j].name, &xmfile[ofs + 18], 22);
|
||
|
xm->samples[sampleOfs + j].name[22] = '\0';
|
||
|
xm->samples[sampleOfs + j].relative_note = xmfile[ofs + 16];
|
||
|
|
||
|
xm->samples[sampleOfs + j].sampleInfo.length = getu32(&xmfile[ofs + 0]);
|
||
|
xm->samples[sampleOfs + j].sampleInfo.loop_start = getu32(&xmfile[ofs + 4]);
|
||
|
xm->samples[sampleOfs + j].sampleInfo.loop_end = getu32(&xmfile[ofs + 8]);
|
||
|
|
||
|
xm->samples[sampleOfs + j].sampleInfo.stereo = FALSE;
|
||
|
xm->samples[sampleOfs + j].sampleInfo.bit_16 = (flag & 16) != 0;
|
||
|
|
||
|
if (xm->samples[sampleOfs + j].sampleInfo.bit_16) {
|
||
|
|
||
|
xm->samples[sampleOfs + j].sampleInfo.length /= 2;
|
||
|
xm->samples[sampleOfs + j].sampleInfo.loop_start /= 2;
|
||
|
xm->samples[sampleOfs + j].sampleInfo.loop_end /= 2;
|
||
|
}
|
||
|
|
||
|
flag &= 0x03;
|
||
|
if ((flag == 0) || (flag == 3)) {
|
||
|
|
||
|
xm->samples[sampleOfs + j].sampleInfo.looped = FALSE;
|
||
|
xm->samples[sampleOfs + j].sampleInfo.pingpong = FALSE;
|
||
|
} else if (flag == 1) {
|
||
|
|
||
|
xm->samples[sampleOfs + j].sampleInfo.looped = TRUE;
|
||
|
xm->samples[sampleOfs + j].sampleInfo.pingpong = FALSE;
|
||
|
} else if (flag == 2) {
|
||
|
|
||
|
xm->samples[sampleOfs + j].sampleInfo.looped = TRUE;
|
||
|
xm->samples[sampleOfs + j].sampleInfo.pingpong = TRUE;
|
||
|
}
|
||
|
|
||
|
if (xm->samples[sampleOfs + j].sampleInfo.loop_end == 0) {
|
||
|
|
||
|
xm->samples[sampleOfs + j].sampleInfo.looped = FALSE;
|
||
|
xm->samples[sampleOfs + j].sampleInfo.pingpong = FALSE;
|
||
|
}
|
||
|
|
||
|
if (xm->samples[sampleOfs + j].sampleInfo.looped) {
|
||
|
|
||
|
xm->samples[sampleOfs + j].sampleInfo.loop_end +=
|
||
|
xm->samples[sampleOfs + j].sampleInfo.loop_start;
|
||
|
} else {
|
||
|
|
||
|
xm->samples[sampleOfs + j].sampleInfo.loop_start =
|
||
|
xm->samples[sampleOfs + j].sampleInfo.loop_end =
|
||
|
xm->samples[sampleOfs + j].sampleInfo.length - 1;
|
||
|
}
|
||
|
|
||
|
ofs += sheadersize;
|
||
|
} /* for (j = 0; j < samplesininstr; j++) */
|
||
|
|
||
|
/* Read sample data */
|
||
|
for (j = 0; j < samplesininstr; j++) {
|
||
|
|
||
|
if (xm->samples[sampleOfs + j].sampleInfo.length != 0) {
|
||
|
|
||
|
u32 length = xm->samples[sampleOfs + j].sampleInfo.length;
|
||
|
|
||
|
if (xm->samples[sampleOfs + j].sampleInfo.bit_16) {
|
||
|
|
||
|
s16 *d;
|
||
|
s16 old, new;
|
||
|
u32 k;
|
||
|
|
||
|
d = malloc(length * 2);
|
||
|
memcpy(d, &xmfile[ofs], length * 2);
|
||
|
xm->samples[sampleOfs + j].sampleInfo.sampledata = d;
|
||
|
ofs += length * 2;
|
||
|
|
||
|
/* Convert the sampledata */
|
||
|
old = 0;
|
||
|
for (k = 0; k < length; k++) {
|
||
|
|
||
|
new = getu16((u8*)&d[k]) + old;
|
||
|
d[k] = new;
|
||
|
old = new;
|
||
|
}
|
||
|
} else {
|
||
|
|
||
|
s8 * d;
|
||
|
s8 old, new;
|
||
|
u32 k;
|
||
|
|
||
|
d = malloc(length);
|
||
|
memcpy(d, &xmfile[ofs], length);
|
||
|
xm->samples[sampleOfs + j].sampleInfo.sampledata = d;
|
||
|
ofs += length;
|
||
|
|
||
|
/* Convert the sampledata */
|
||
|
old = 0;
|
||
|
for (k = 0; k < length; k++) {
|
||
|
|
||
|
new = d[k] + old;
|
||
|
d[k] = new;
|
||
|
old = new;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sampleOfs += samplesininstr;
|
||
|
|
||
|
} else {/* if (samplesininstr > 0) */
|
||
|
|
||
|
ofs += headersize;
|
||
|
}
|
||
|
} /* for (i = 0; i < xm->nInstruments; i++) */
|
||
|
|
||
|
xm->unsigned_samples = FALSE;
|
||
|
xm->master_volume = 64;
|
||
|
xm->filetype = MODULE_XM;
|
||
|
|
||
|
for (i = 0; i < xm->nChannels; i++) {
|
||
|
|
||
|
xm->channels[i].voiceInfo.enabled = TRUE;
|
||
|
xm->channels[i].default_panning = 128;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
BOOL MODFILE_IsXM(u8 *xmfile, int xmlength) {
|
||
|
|
||
|
if ((xmfile == NULL) || (xmlength < 1024))
|
||
|
return FALSE;
|
||
|
|
||
|
if (memcmp(&xmfile[0], "Extended Module: ", 17) != 0)
|
||
|
return FALSE;
|
||
|
|
||
|
if (xmfile[37] != 0x1a)
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
int MODFILE_XMGetFormatID(void) {
|
||
|
|
||
|
return MODULE_XM;
|
||
|
}
|
||
|
|
||
|
|
||
|
char *MODFILE_XMGetDescription(void) {
|
||
|
|
||
|
return DESCRIPTION;
|
||
|
}
|
||
|
|
||
|
|
||
|
char *MODFILE_XMGetAuthor(void) {
|
||
|
|
||
|
return AUTHOR;
|
||
|
}
|
||
|
|
||
|
|
||
|
char *MODFILE_XMGetVersion(void) {
|
||
|
|
||
|
return VERSION;
|
||
|
}
|
||
|
|
||
|
|
||
|
char *MODFILE_XMGetCopyright(void) {
|
||
|
|
||
|
return COPYRIGHT;
|
||
|
}
|