mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-13 18:17:39 -04:00
FS#13539: Resync mikmod plugin with upstream
Brings it up to libmikmod 3.3.12, relased 2024-12-31 Also fix a segfault that only happened on simulators when using non-default samplerates. Change-Id: I2ade2d72a00edab5395328fe76a88a88516aac72
This commit is contained in:
parent
08c32cee7c
commit
af7ed73f31
29 changed files with 1860 additions and 706 deletions
12
apps/plugins/mikmod/README.rockbox
Normal file
12
apps/plugins/mikmod/README.rockbox
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
mikmod (https://mikmod.sourceforge.net/)
|
||||||
|
|
||||||
|
Based on upstream commit 72424e1bebab470fbf8a2914dcd7903b742205e6
|
||||||
|
corresponding to mikmod 3.2.9 / libmikmod 3.3.12
|
||||||
|
|
||||||
|
Heavily customized for rockbox use:
|
||||||
|
|
||||||
|
* converted most BOOL/INTs in function prototypes to 'int'
|
||||||
|
* converted BOOL/INT in option enums to RB_BOOL / RB_INT
|
||||||
|
* Silenced a _ton_ of "unused parameter" options
|
||||||
|
* Custom player frontend that is fully i18n'd
|
||||||
|
* Settings for mixer freq, quality, and other parameters
|
|
@ -20,8 +20,6 @@
|
||||||
|
|
||||||
/*==============================================================================
|
/*==============================================================================
|
||||||
|
|
||||||
$Id: $
|
|
||||||
|
|
||||||
Composer 669 module loader
|
Composer 669 module loader
|
||||||
|
|
||||||
==============================================================================*/
|
==============================================================================*/
|
||||||
|
@ -321,7 +319,8 @@ static int S69_Load(int curious)
|
||||||
sample.length=_mm_read_I_SLONG(modreader);
|
sample.length=_mm_read_I_SLONG(modreader);
|
||||||
sample.loopbeg=_mm_read_I_SLONG(modreader);
|
sample.loopbeg=_mm_read_I_SLONG(modreader);
|
||||||
sample.loopend=_mm_read_I_SLONG(modreader);
|
sample.loopend=_mm_read_I_SLONG(modreader);
|
||||||
if (sample.loopend==0xfffff) sample.loopend=0;
|
/* Note: 'Lost in Germany' has 0xf0ffff as marker */
|
||||||
|
if (sample.loopend>=0xfffff) sample.loopend=0;
|
||||||
|
|
||||||
if((sample.length<0)||(sample.loopbeg<-1)||(sample.loopend<-1)) {
|
if((sample.length<0)||(sample.loopbeg<-1)||(sample.loopend<-1)) {
|
||||||
_mm_errno = MMERR_LOADING_HEADER;
|
_mm_errno = MMERR_LOADING_HEADER;
|
||||||
|
@ -330,7 +329,7 @@ static int S69_Load(int curious)
|
||||||
|
|
||||||
current->samplename=DupStr(sample.filename,13,1);
|
current->samplename=DupStr(sample.filename,13,1);
|
||||||
current->seekpos=0;
|
current->seekpos=0;
|
||||||
current->speed=0;
|
current->speed=128; /* Used as finetune when UF_XMPERIODS is enabled; 128 is centered. */
|
||||||
current->length=sample.length;
|
current->length=sample.length;
|
||||||
current->loopstart=sample.loopbeg;
|
current->loopstart=sample.loopbeg;
|
||||||
current->loopend=sample.loopend;
|
current->loopend=sample.loopend;
|
||||||
|
|
|
@ -94,7 +94,7 @@ static int AMF_Test(void)
|
||||||
if(memcmp(id,"AMF",3)) return 0;
|
if(memcmp(id,"AMF",3)) return 0;
|
||||||
|
|
||||||
ver=_mm_read_UBYTE(modreader);
|
ver=_mm_read_UBYTE(modreader);
|
||||||
if((ver>=10)&&(ver<=14)) return 1;
|
if((ver>=8)&&(ver<=14)) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,48 @@ static void AMF_Cleanup(void)
|
||||||
track=NULL;
|
track=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int AMF_UnpackTrack(MREADER* r)
|
/* Some older version 1.0 AMFs contain an anomaly where the sample length is
|
||||||
|
* a DWORD, the loop start is a WORD, and the loop end is missing. Later AMF
|
||||||
|
* 1.0 modules and up contain all three as DWORDs, and earlier versions have
|
||||||
|
* all three as WORDs. This function tries to detect this edge case in the
|
||||||
|
* instruments table. This should only be called on 1.0 AMFs.
|
||||||
|
*/
|
||||||
|
static int AMF_ScanV10Instruments(MREADER *r, unsigned int numins)
|
||||||
|
{
|
||||||
|
SLONG resetpos;
|
||||||
|
int res = 0;
|
||||||
|
char str[32];
|
||||||
|
ULONG idx, len, start, end;
|
||||||
|
UBYTE type, vol;
|
||||||
|
UWORD c2spd;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
resetpos = _mm_ftell(r);
|
||||||
|
if(resetpos < 0) return 0;
|
||||||
|
|
||||||
|
for(i = 0; i < numins; i++) {
|
||||||
|
type = _mm_read_UBYTE(r); /* type: should be 0 or 1 */
|
||||||
|
_mm_read_string(str, 32, r); /* name */
|
||||||
|
_mm_read_string(str, 13, r); /* filename */
|
||||||
|
idx = _mm_read_I_ULONG(r); /* index (should be <= numins) */
|
||||||
|
len = _mm_read_I_ULONG(r);
|
||||||
|
c2spd = _mm_read_I_UWORD(r); /* should be > 0 */
|
||||||
|
vol = _mm_read_UBYTE(r); /* should be [0,0x40] */
|
||||||
|
start = _mm_read_I_ULONG(r); /* should be <= len */
|
||||||
|
end = _mm_read_I_ULONG(r); /* should be <= len */
|
||||||
|
|
||||||
|
if((type != 0 && type != 1) || (idx > numins) || (c2spd == 0) ||
|
||||||
|
(vol > 0x40) || (start > len) || (end > len)) {
|
||||||
|
res = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
_mm_fseek(r, resetpos, SEEK_SET);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int AMF_UnpackTrack(MREADER *r)
|
||||||
{
|
{
|
||||||
ULONG tracksize;
|
ULONG tracksize;
|
||||||
UBYTE row,cmd;
|
UBYTE row,cmd;
|
||||||
|
@ -126,7 +167,12 @@ static int AMF_UnpackTrack(MREADER* r)
|
||||||
/* read packed track */
|
/* read packed track */
|
||||||
if (r) {
|
if (r) {
|
||||||
tracksize=_mm_read_I_UWORD(r);
|
tracksize=_mm_read_I_UWORD(r);
|
||||||
tracksize+=((ULONG)_mm_read_UBYTE(r))<<16;
|
|
||||||
|
/* The original code in DSMI library read the byte,
|
||||||
|
but it is not used, so we won't either */
|
||||||
|
// tracksize+=((ULONG)_mm_read_UBYTE(r))<<16;
|
||||||
|
(void)_mm_read_UBYTE(r);
|
||||||
|
|
||||||
if (tracksize)
|
if (tracksize)
|
||||||
while(tracksize--) {
|
while(tracksize--) {
|
||||||
row=_mm_read_UBYTE(r);
|
row=_mm_read_UBYTE(r);
|
||||||
|
@ -144,18 +190,23 @@ static int AMF_UnpackTrack(MREADER* r)
|
||||||
|
|
||||||
}
|
}
|
||||||
/* invalid row (probably unexpected end of row) */
|
/* invalid row (probably unexpected end of row) */
|
||||||
if (row>=64)
|
if (row>=64) {
|
||||||
return 0;
|
_mm_fseek(modreader, tracksize * 3, SEEK_CUR);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (cmd<0x7f) {
|
if (cmd<0x7f) {
|
||||||
/* note, vol */
|
/* note, vol */
|
||||||
|
/* Note that 0xff values mean this note was not originally
|
||||||
|
accomanied by a volume event. The +1 here causes it to
|
||||||
|
overflow to 0, which will then (correctly) be ignored later. */
|
||||||
track[row].note=cmd;
|
track[row].note=cmd;
|
||||||
track[row].volume=(UBYTE)arg+1;
|
track[row].volume=(UBYTE)arg+1;
|
||||||
} else
|
} else
|
||||||
if (cmd==0x7f) {
|
if (cmd==0x7f) {
|
||||||
/* duplicate row */
|
/* AMF.TXT claims this should duplicate the previous row, but
|
||||||
if ((arg<0)&&(row+arg>=0)) {
|
this is a lie. This note value is used to communicate to
|
||||||
memcpy(track+row,track+(row+arg),sizeof(AMFNOTE));
|
DSMI that the current playing note should be updated when
|
||||||
}
|
an instrument is used with no note. This can be ignored. */
|
||||||
} else
|
} else
|
||||||
if (cmd==0x80) {
|
if (cmd==0x80) {
|
||||||
/* instr */
|
/* instr */
|
||||||
|
@ -173,8 +224,11 @@ static int AMF_UnpackTrack(MREADER* r)
|
||||||
} else
|
} else
|
||||||
if(track[row].fxcnt<3) {
|
if(track[row].fxcnt<3) {
|
||||||
/* effect, param */
|
/* effect, param */
|
||||||
if(cmd>0x97)
|
if(cmd>0x97) {
|
||||||
return 0;
|
/* Instead of failing, we just ignore unknown effects.
|
||||||
|
This will load the "escape from dulce base" module */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
track[row].effect[track[row].fxcnt]=cmd&0x7f;
|
track[row].effect[track[row].fxcnt]=cmd&0x7f;
|
||||||
track[row].parameter[track[row].fxcnt]=arg;
|
track[row].parameter[track[row].fxcnt]=arg;
|
||||||
track[row].fxcnt++;
|
track[row].fxcnt++;
|
||||||
|
@ -185,7 +239,7 @@ static int AMF_UnpackTrack(MREADER* r)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UBYTE* AMF_ConvertTrack(void)
|
static UBYTE *AMF_ConvertTrack(void)
|
||||||
{
|
{
|
||||||
int row,fx4memory=0;
|
int row,fx4memory=0;
|
||||||
|
|
||||||
|
@ -315,6 +369,7 @@ static UBYTE* AMF_ConvertTrack(void)
|
||||||
UniEffect(fx4memory,0);
|
UniEffect(fx4memory,0);
|
||||||
break;
|
break;
|
||||||
case 0x17: /* Panning */
|
case 0x17: /* Panning */
|
||||||
|
/* S3M pan, except offset by -64. */
|
||||||
if (inf>64)
|
if (inf>64)
|
||||||
UniEffect(UNI_ITEFFECTS0,0x91); /* surround */
|
UniEffect(UNI_ITEFFECTS0,0x91); /* surround */
|
||||||
else
|
else
|
||||||
|
@ -338,17 +393,29 @@ static int AMF_Load(int curious)
|
||||||
SAMPLE *q;
|
SAMPLE *q;
|
||||||
UWORD *track_remap;
|
UWORD *track_remap;
|
||||||
ULONG samplepos, fileend;
|
ULONG samplepos, fileend;
|
||||||
int channel_remap[16];
|
UBYTE channel_remap[16];
|
||||||
|
int no_loopend;
|
||||||
(void)curious;
|
(void)curious;
|
||||||
|
|
||||||
/* try to read module header */
|
/* try to read module header */
|
||||||
_mm_read_UBYTES(mh->id,3,modreader);
|
_mm_read_UBYTES(mh->id,3,modreader);
|
||||||
mh->version =_mm_read_UBYTE(modreader);
|
mh->version =_mm_read_UBYTE(modreader);
|
||||||
|
|
||||||
|
/* For version 8, the song name is only 20 characters long and then come
|
||||||
|
// some data, which I do not know what is. The original code by Otto Chrons
|
||||||
|
// load the song name as 20 characters long and then it is overwritten again
|
||||||
|
// it another function, where it loads 32 characters, no matter which version
|
||||||
|
// it is. So we do the same here */
|
||||||
_mm_read_string(mh->songname,32,modreader);
|
_mm_read_string(mh->songname,32,modreader);
|
||||||
|
|
||||||
mh->numsamples =_mm_read_UBYTE(modreader);
|
mh->numsamples =_mm_read_UBYTE(modreader);
|
||||||
mh->numorders =_mm_read_UBYTE(modreader);
|
mh->numorders =_mm_read_UBYTE(modreader);
|
||||||
mh->numtracks =_mm_read_I_UWORD(modreader);
|
mh->numtracks =_mm_read_I_UWORD(modreader);
|
||||||
mh->numchannels =_mm_read_UBYTE(modreader);
|
|
||||||
|
if(mh->version>=9)
|
||||||
|
mh->numchannels=_mm_read_UBYTE(modreader);
|
||||||
|
else
|
||||||
|
mh->numchannels=4;
|
||||||
|
|
||||||
if((!mh->numchannels)||(mh->numchannels>(mh->version>=12?32:16))) {
|
if((!mh->numchannels)||(mh->numchannels>(mh->version>=12?32:16))) {
|
||||||
_mm_errno=MMERR_NOT_A_MODULE;
|
_mm_errno=MMERR_NOT_A_MODULE;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -357,7 +424,7 @@ static int AMF_Load(int curious)
|
||||||
if(mh->version>=11) {
|
if(mh->version>=11) {
|
||||||
memset(mh->panpos,0,32);
|
memset(mh->panpos,0,32);
|
||||||
_mm_read_SBYTES(mh->panpos,(mh->version>=13)?32:16,modreader);
|
_mm_read_SBYTES(mh->panpos,(mh->version>=13)?32:16,modreader);
|
||||||
} else
|
} else if(mh->version>=9)
|
||||||
_mm_read_UBYTES(channel_remap,16,modreader);
|
_mm_read_UBYTES(channel_remap,16,modreader);
|
||||||
|
|
||||||
if (mh->version>=13) {
|
if (mh->version>=13) {
|
||||||
|
@ -408,16 +475,22 @@ static int AMF_Load(int curious)
|
||||||
* UF_PANNING, to use our preferred panning table for this case.
|
* UF_PANNING, to use our preferred panning table for this case.
|
||||||
*/
|
*/
|
||||||
defaultpanning = 1;
|
defaultpanning = 1;
|
||||||
for (t = 0; t < 32; t++) {
|
|
||||||
if (mh->panpos[t] > 64) {
|
if(mh->version>=11) {
|
||||||
of.panning[t] = PAN_SURROUND;
|
for (t = 0; t < 32; t++) {
|
||||||
defaultpanning = 0;
|
if (mh->panpos[t] > 64) {
|
||||||
} else
|
of.panning[t] = PAN_SURROUND;
|
||||||
if (mh->panpos[t] == 64)
|
defaultpanning = 0;
|
||||||
of.panning[t] = PAN_RIGHT;
|
} else
|
||||||
else
|
if (mh->panpos[t] == 64)
|
||||||
of.panning[t] = (mh->panpos[t] + 64) << 1;
|
of.panning[t] = PAN_RIGHT;
|
||||||
|
else
|
||||||
|
of.panning[t] = (mh->panpos[t] + 64) << 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
defaultpanning = 0;
|
||||||
|
|
||||||
if (defaultpanning) {
|
if (defaultpanning) {
|
||||||
for (t = 0; t < of.numchn; t++)
|
for (t = 0; t < of.numchn; t++)
|
||||||
if (of.panning[t] == (((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT)) {
|
if (of.panning[t] == (((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT)) {
|
||||||
|
@ -442,11 +515,13 @@ static int AMF_Load(int curious)
|
||||||
if (mh->version>=14)
|
if (mh->version>=14)
|
||||||
/* track size */
|
/* track size */
|
||||||
of.pattrows[t]=_mm_read_I_UWORD(modreader);
|
of.pattrows[t]=_mm_read_I_UWORD(modreader);
|
||||||
if (mh->version>=10)
|
if ((mh->version==9) || (mh->version==10)) {
|
||||||
_mm_read_I_UWORDS(of.patterns+(t*of.numchn),of.numchn,modreader);
|
/* Only version 9 and 10 uses channel remap */
|
||||||
|
for (u = 0; u < of.numchn; u++)
|
||||||
|
of.patterns[t * of.numchn + channel_remap[u]] = _mm_read_I_UWORD(modreader);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
for(u=0;u<of.numchn;u++)
|
_mm_read_I_UWORDS(of.patterns + (t * of.numchn), of.numchn, modreader);
|
||||||
of.patterns[t*of.numchn+channel_remap[u]]=_mm_read_I_UWORD(modreader);
|
|
||||||
}
|
}
|
||||||
if(_mm_eof(modreader)) {
|
if(_mm_eof(modreader)) {
|
||||||
_mm_errno = MMERR_LOADING_HEADER;
|
_mm_errno = MMERR_LOADING_HEADER;
|
||||||
|
@ -455,6 +530,12 @@ static int AMF_Load(int curious)
|
||||||
|
|
||||||
/* read sample information */
|
/* read sample information */
|
||||||
if(!AllocSamples()) return 0;
|
if(!AllocSamples()) return 0;
|
||||||
|
|
||||||
|
no_loopend = 0;
|
||||||
|
if(mh->version == 10) {
|
||||||
|
no_loopend = AMF_ScanV10Instruments(modreader, of.numins);
|
||||||
|
}
|
||||||
|
|
||||||
q=of.samples;
|
q=of.samples;
|
||||||
for(t=0;t<of.numins;t++) {
|
for(t=0;t<of.numins;t++) {
|
||||||
/* try to read sample info */
|
/* try to read sample info */
|
||||||
|
@ -462,19 +543,38 @@ static int AMF_Load(int curious)
|
||||||
_mm_read_string(s.samplename,32,modreader);
|
_mm_read_string(s.samplename,32,modreader);
|
||||||
_mm_read_string(s.filename,13,modreader);
|
_mm_read_string(s.filename,13,modreader);
|
||||||
s.offset =_mm_read_I_ULONG(modreader);
|
s.offset =_mm_read_I_ULONG(modreader);
|
||||||
s.length =_mm_read_I_ULONG(modreader);
|
|
||||||
|
if(mh->version>=10)
|
||||||
|
s.length =_mm_read_I_ULONG(modreader);
|
||||||
|
else
|
||||||
|
s.length = _mm_read_I_UWORD(modreader);
|
||||||
|
|
||||||
s.c2spd =_mm_read_I_UWORD(modreader);
|
s.c2spd =_mm_read_I_UWORD(modreader);
|
||||||
if(s.c2spd==8368) s.c2spd=8363;
|
if(s.c2spd==8368) s.c2spd=8363;
|
||||||
s.volume =_mm_read_UBYTE(modreader);
|
s.volume =_mm_read_UBYTE(modreader);
|
||||||
/* "the tribal zone.amf" and "the way its gonna b.amf" by Maelcum
|
/* "the tribal zone.amf" and "the way its gonna b.amf" by Maelcum
|
||||||
* are the only version 10 files I can find, and they have 32 bit
|
* are the only version 10 files I can find, and they have 32 bit
|
||||||
* reppos and repend, not 16. */
|
* reppos and repend, not 16. */
|
||||||
if(mh->version>=10) {/* was 11 */
|
if(mh->version>=10 && no_loopend==0) {/* was 11 */
|
||||||
s.reppos =_mm_read_I_ULONG(modreader);
|
s.reppos =_mm_read_I_ULONG(modreader);
|
||||||
s.repend =_mm_read_I_ULONG(modreader);
|
s.repend =_mm_read_I_ULONG(modreader);
|
||||||
} else {
|
} else if(mh->version==10) {
|
||||||
|
/* Early AMF 1.0 modules have the upper two bytes of
|
||||||
|
* the loop start and the entire loop end truncated.
|
||||||
|
* libxmp cites "sweetdrm.amf" and "facing_n.amf", but
|
||||||
|
* these are currently missing. M2AMF 1.3 (from DMP 2.32)
|
||||||
|
* has been confirmed to output these, however. */
|
||||||
s.reppos =_mm_read_I_UWORD(modreader);
|
s.reppos =_mm_read_I_UWORD(modreader);
|
||||||
s.repend =s.length;
|
s.repend =s.length;
|
||||||
|
/* There's not really a correct way to handle the loop
|
||||||
|
* end, but this makes unlooped samples work at least. */
|
||||||
|
if(s.reppos==0)
|
||||||
|
s.repend=0;
|
||||||
|
} else {
|
||||||
|
s.reppos =_mm_read_I_UWORD(modreader);
|
||||||
|
s.repend =_mm_read_I_UWORD(modreader);
|
||||||
|
if (s.repend==0xffff)
|
||||||
|
s.repend=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_mm_eof(modreader)) {
|
if(_mm_eof(modreader)) {
|
||||||
|
|
|
@ -58,8 +58,12 @@ typedef struct MSAMPINFO {
|
||||||
|
|
||||||
typedef struct MODULEHEADER {
|
typedef struct MODULEHEADER {
|
||||||
CHAR songname[21];
|
CHAR songname[21];
|
||||||
|
UBYTE initspeed;
|
||||||
|
UBYTE inittempo;
|
||||||
|
UBYTE num_samples;
|
||||||
UBYTE num_patterns; /* number of patterns used */
|
UBYTE num_patterns; /* number of patterns used */
|
||||||
UBYTE num_orders;
|
UBYTE num_orders;
|
||||||
|
UBYTE reppos;
|
||||||
UBYTE positions[256]; /* which pattern to play at pos */
|
UBYTE positions[256]; /* which pattern to play at pos */
|
||||||
MSAMPINFO samples[64]; /* all sampleinfo */
|
MSAMPINFO samples[64]; /* all sampleinfo */
|
||||||
} MODULEHEADER;
|
} MODULEHEADER;
|
||||||
|
@ -177,7 +181,7 @@ static int ConvertNote(MODNOTE *n)
|
||||||
|
|
||||||
if (instrument) {
|
if (instrument) {
|
||||||
/* if instrument does not exist, note cut */
|
/* if instrument does not exist, note cut */
|
||||||
if ((instrument > 31) || (!mh->samples[instrument - 1].length)) {
|
if ((instrument > mh->num_samples) || (!mh->samples[instrument - 1].length)) {
|
||||||
UniPTEffect(0xc, 0);
|
UniPTEffect(0xc, 0);
|
||||||
if (effect == 0xc)
|
if (effect == 0xc)
|
||||||
effect = effdat = 0;
|
effect = effdat = 0;
|
||||||
|
@ -194,7 +198,6 @@ static int ConvertNote(MODNOTE *n)
|
||||||
* played */
|
* played */
|
||||||
if (effect || effdat) {
|
if (effect || effdat) {
|
||||||
UniInstrument(instrument - 1);
|
UniInstrument(instrument - 1);
|
||||||
note = lastnote;
|
|
||||||
} else
|
} else
|
||||||
UniPTEffect(0xc,
|
UniPTEffect(0xc,
|
||||||
mh->samples[instrument -
|
mh->samples[instrument -
|
||||||
|
@ -294,22 +297,33 @@ static int ASY_Load(int curious)
|
||||||
/* no title in asylum amf files :( */
|
/* no title in asylum amf files :( */
|
||||||
mh->songname[0] = '\0';
|
mh->songname[0] = '\0';
|
||||||
|
|
||||||
_mm_fseek(modreader, 0x23, SEEK_SET);
|
_mm_fseek(modreader, 0x20, SEEK_SET);
|
||||||
|
mh->initspeed = _mm_read_UBYTE(modreader);
|
||||||
|
mh->inittempo = _mm_read_UBYTE(modreader);
|
||||||
|
mh->num_samples = _mm_read_UBYTE(modreader);
|
||||||
mh->num_patterns = _mm_read_UBYTE(modreader);
|
mh->num_patterns = _mm_read_UBYTE(modreader);
|
||||||
mh->num_orders = _mm_read_UBYTE(modreader);
|
mh->num_orders = _mm_read_UBYTE(modreader);
|
||||||
|
mh->reppos = _mm_read_UBYTE(modreader);
|
||||||
|
|
||||||
/* skip unknown byte */
|
|
||||||
_mm_skip_BYTE(modreader);
|
|
||||||
_mm_read_UBYTES(mh->positions, 256, modreader);
|
_mm_read_UBYTES(mh->positions, 256, modreader);
|
||||||
|
|
||||||
|
#ifdef MIKMOD_DEBUG
|
||||||
|
fprintf(stderr, "ASY: bpm=%d, spd=%d, numins=%d, numpat=%d\n",
|
||||||
|
mh->inittempo, mh->initspeed, mh->num_samples, mh->num_patterns);
|
||||||
|
#endif
|
||||||
|
if (!mh->initspeed || !mh->inittempo || mh->num_samples > 64) {
|
||||||
|
_mm_errno = MMERR_NOT_A_MODULE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* read samples headers*/
|
/* read samples headers*/
|
||||||
for (t = 0; t < 64; t++) {
|
for (t = 0; t < mh->num_samples; t++) {
|
||||||
s = &mh->samples[t];
|
s = &mh->samples[t];
|
||||||
|
|
||||||
_mm_fseek(modreader, 0x126 + (t*37), SEEK_SET);
|
_mm_fseek(modreader, 0x126 + (t*37), SEEK_SET);
|
||||||
|
|
||||||
_mm_read_string(s->samplename, 22, modreader);
|
_mm_read_string(s->samplename, 22, modreader);
|
||||||
s->samplename[21] = 0; /* just in case */
|
s->samplename[22] = 0;
|
||||||
|
|
||||||
s->finetune = _mm_read_UBYTE(modreader);
|
s->finetune = _mm_read_UBYTE(modreader);
|
||||||
s->volume = _mm_read_UBYTE(modreader);
|
s->volume = _mm_read_UBYTE(modreader);
|
||||||
|
@ -324,14 +338,16 @@ static int ASY_Load(int curious)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_mm_fseek(modreader, 37*(64-mh->num_samples), SEEK_CUR);
|
||||||
|
|
||||||
/* set module variables */
|
/* set module variables */
|
||||||
of.initspeed = 6;
|
of.initspeed = mh->initspeed;
|
||||||
of.inittempo = 125;
|
of.inittempo = mh->inittempo;
|
||||||
of.numchn = 8;
|
of.numchn = 8;
|
||||||
modtype = 0;
|
modtype = 0;
|
||||||
of.songname = DupStr(mh->songname, 21, 1);
|
of.songname = MikMod_strdup("");
|
||||||
of.numpos = mh->num_orders;
|
of.numpos = mh->num_orders;
|
||||||
of.reppos = 0;
|
of.reppos = mh->reppos;
|
||||||
of.numpat = mh->num_patterns;
|
of.numpat = mh->num_patterns;
|
||||||
of.numtrk = of.numpat * of.numchn;
|
of.numtrk = of.numpat * of.numchn;
|
||||||
|
|
||||||
|
@ -348,8 +364,8 @@ static int ASY_Load(int curious)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finally, init the sampleinfo structures */
|
/* Finally, init the sampleinfo structures */
|
||||||
of.numins = 31;
|
of.numins = mh->num_samples;
|
||||||
of.numsmp = 31;
|
of.numsmp = mh->num_samples;
|
||||||
if (!AllocSamples())
|
if (!AllocSamples())
|
||||||
return 0;
|
return 0;
|
||||||
s = mh->samples;
|
s = mh->samples;
|
||||||
|
|
|
@ -93,6 +93,7 @@ static FARHEADER2 *mh2 = NULL;
|
||||||
static FARNOTE *pat = NULL;
|
static FARNOTE *pat = NULL;
|
||||||
|
|
||||||
static const unsigned char FARSIG[4+3]={'F','A','R',0xfe,13,10,26};
|
static const unsigned char FARSIG[4+3]={'F','A','R',0xfe,13,10,26};
|
||||||
|
static const UWORD FAR_MAXPATSIZE=(256*16*4)+2;
|
||||||
|
|
||||||
/*========== Loader code */
|
/*========== Loader code */
|
||||||
|
|
||||||
|
@ -134,20 +135,36 @@ static UBYTE *FAR_ConvertTrack(FARNOTE* n,int rows)
|
||||||
UniInstrument(n->ins);
|
UniInstrument(n->ins);
|
||||||
UniNote(n->note+3*OCTAVE-1);
|
UniNote(n->note+3*OCTAVE-1);
|
||||||
}
|
}
|
||||||
if (n->vol&0xf) UniPTEffect(0xc,(n->vol&0xf)<<2);
|
if (n->vol>=0x01 && n->vol<=0x10) UniPTEffect(0xc,(n->vol - 1)<<2);
|
||||||
if (n->eff)
|
if (n->eff)
|
||||||
switch(n->eff>>4) {
|
switch(n->eff>>4) {
|
||||||
|
case 0x0: /* global effects */
|
||||||
|
switch(n->eff & 0xf) {
|
||||||
|
case 0x3: /* fulfill loop */
|
||||||
|
UniEffect(UNI_KEYFADE, 0);
|
||||||
|
break;
|
||||||
|
case 0x4: /* old tempo mode */
|
||||||
|
case 0x5: /* new tempo mode */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x1: /* pitch adjust up */
|
||||||
|
UniEffect(UNI_FAREFFECT1, n->eff & 0xf);
|
||||||
|
break;
|
||||||
|
case 0x2: /* pitch adjust down */
|
||||||
|
UniEffect(UNI_FAREFFECT2, n->eff & 0xf);
|
||||||
|
break;
|
||||||
case 0x3: /* porta to note */
|
case 0x3: /* porta to note */
|
||||||
UniPTEffect(0x3,(n->eff&0xf)<<4);
|
UniEffect(UNI_FAREFFECT3, n->eff & 0xf);
|
||||||
break;
|
break;
|
||||||
case 0x4: /* retrigger */
|
case 0x4: /* retrigger */
|
||||||
UniPTEffect(0x0e, 0x90 | (n->eff & 0x0f));
|
UniEffect(UNI_FAREFFECT4, n->eff & 0xf);
|
||||||
break;
|
break;
|
||||||
case 0x5: /* set vibrato depth */
|
case 0x5: /* set vibrato depth */
|
||||||
vibdepth=n->eff&0xf;
|
vibdepth=n->eff&0xf;
|
||||||
break;
|
break;
|
||||||
case 0x6: /* vibrato */
|
case 0x6: /* vibrato */
|
||||||
UniPTEffect(0x4,((n->eff&0xf)<<4)|vibdepth);
|
UniEffect(UNI_FAREFFECT6,((n->eff&0xf)<<4)|vibdepth);
|
||||||
break;
|
break;
|
||||||
case 0x7: /* volume slide up */
|
case 0x7: /* volume slide up */
|
||||||
UniPTEffect(0xa,(n->eff&0xf)<<4);
|
UniPTEffect(0xa,(n->eff&0xf)<<4);
|
||||||
|
@ -155,11 +172,21 @@ static UBYTE *FAR_ConvertTrack(FARNOTE* n,int rows)
|
||||||
case 0x8: /* volume slide down */
|
case 0x8: /* volume slide down */
|
||||||
UniPTEffect(0xa,n->eff&0xf);
|
UniPTEffect(0xa,n->eff&0xf);
|
||||||
break;
|
break;
|
||||||
|
case 0x9: /* sustained vibrato */
|
||||||
|
break;
|
||||||
case 0xb: /* panning */
|
case 0xb: /* panning */
|
||||||
UniPTEffect(0xe,0x80|(n->eff&0xf));
|
UniPTEffect(0xe,0x80|(n->eff&0xf));
|
||||||
break;
|
break;
|
||||||
|
case 0xc: /* note offset */
|
||||||
|
break;
|
||||||
|
case 0xd: /* fine tempo down */
|
||||||
|
UniEffect(UNI_FAREFFECTD, n->eff & 0xf);
|
||||||
|
break;
|
||||||
|
case 0xe: /* fine tempo up */
|
||||||
|
UniEffect(UNI_FAREFFECTE, n->eff & 0xf);
|
||||||
|
break;
|
||||||
case 0xf: /* set speed */
|
case 0xf: /* set speed */
|
||||||
UniPTEffect(0xf,n->eff&0xf);
|
UniEffect(UNI_FAREFFECTF,n->eff&0xf);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* others not yet implemented */
|
/* others not yet implemented */
|
||||||
|
@ -178,11 +205,12 @@ static UBYTE *FAR_ConvertTrack(FARNOTE* n,int rows)
|
||||||
|
|
||||||
static int FAR_Load(int curious)
|
static int FAR_Load(int curious)
|
||||||
{
|
{
|
||||||
int t,u,tracks=0;
|
int r,t,u,tracks=0;
|
||||||
SAMPLE *q;
|
SAMPLE *q;
|
||||||
FARSAMPLE s;
|
FARSAMPLE s;
|
||||||
FARNOTE *crow;
|
FARNOTE *crow;
|
||||||
UBYTE smap[8];
|
UBYTE smap[8];
|
||||||
|
UBYTE addextrapattern;
|
||||||
(void)curious;
|
(void)curious;
|
||||||
|
|
||||||
/* try to read module header (first part) */
|
/* try to read module header (first part) */
|
||||||
|
@ -202,10 +230,9 @@ static int FAR_Load(int curious)
|
||||||
of.modtype = MikMod_strdup(FAR_Version);
|
of.modtype = MikMod_strdup(FAR_Version);
|
||||||
of.songname = DupStr(mh1->songname,40,1);
|
of.songname = DupStr(mh1->songname,40,1);
|
||||||
of.numchn = 16;
|
of.numchn = 16;
|
||||||
of.initspeed = mh1->speed;
|
of.initspeed = mh1->speed != 0 ? mh1->speed : 4;
|
||||||
of.inittempo = 80;
|
of.bpmlimit = 5;
|
||||||
of.reppos = 0;
|
of.flags |= UF_PANNING | UF_FARTEMPO | UF_HIGHBPM;
|
||||||
of.flags |= UF_PANNING;
|
|
||||||
for(t=0;t<16;t++) of.panning[t]=mh1->panning[t]<<4;
|
for(t=0;t<16;t++) of.panning[t]=mh1->panning[t]<<4;
|
||||||
|
|
||||||
/* read songtext into comment field */
|
/* read songtext into comment field */
|
||||||
|
@ -225,17 +252,29 @@ static int FAR_Load(int curious)
|
||||||
_mm_read_I_UWORDS(mh2->patsiz,256,modreader);
|
_mm_read_I_UWORDS(mh2->patsiz,256,modreader);
|
||||||
|
|
||||||
of.numpos = mh2->snglen;
|
of.numpos = mh2->snglen;
|
||||||
|
of.reppos = mh2->loopto;
|
||||||
|
|
||||||
if(!AllocPositions(of.numpos)) return 0;
|
if(!AllocPositions(of.numpos)) return 0;
|
||||||
for(t=0;t<of.numpos;t++) {
|
|
||||||
if(mh2->orders[t]==0xff) break;
|
|
||||||
of.positions[t] = mh2->orders[t];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* count number of patterns stored in file */
|
/* count number of patterns stored in file */
|
||||||
of.numpat = 0;
|
of.numpat = 0;
|
||||||
for(t=0;t<256;t++)
|
for(t=0;t<256;t++)
|
||||||
if(mh2->patsiz[t])
|
if(mh2->patsiz[t])
|
||||||
if((t+1)>of.numpat) of.numpat=t+1;
|
if((t+1)>of.numpat) of.numpat=t+1;
|
||||||
|
|
||||||
|
addextrapattern = 0;
|
||||||
|
for (t = 0; t < of.numpos; t++) {
|
||||||
|
if (mh2->orders[t] == 0xff) break;
|
||||||
|
of.positions[t] = mh2->orders[t];
|
||||||
|
if (of.positions[t] >= of.numpat) {
|
||||||
|
of.positions[t] = of.numpat;
|
||||||
|
addextrapattern = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addextrapattern)
|
||||||
|
of.numpat++;
|
||||||
|
|
||||||
of.numtrk = of.numpat*of.numchn;
|
of.numtrk = of.numpat*of.numchn;
|
||||||
|
|
||||||
/* seek across eventual new data */
|
/* seek across eventual new data */
|
||||||
|
@ -246,18 +285,17 @@ static int FAR_Load(int curious)
|
||||||
if(!AllocPatterns()) return 0;
|
if(!AllocPatterns()) return 0;
|
||||||
|
|
||||||
for(t=0;t<of.numpat;t++) {
|
for(t=0;t<of.numpat;t++) {
|
||||||
UBYTE rows=0;
|
|
||||||
UBYTE tempo;
|
|
||||||
|
|
||||||
memset(pat,0,256*16*4*sizeof(FARNOTE));
|
memset(pat,0,256*16*4*sizeof(FARNOTE));
|
||||||
if(mh2->patsiz[t]) {
|
if(mh2->patsiz[t]) {
|
||||||
rows = _mm_read_UBYTE(modreader);
|
/* Break position byte is always 1 less than the final row index,
|
||||||
tempo = _mm_read_UBYTE(modreader);
|
i.e. it is 2 less than the total row count. */
|
||||||
(void)tempo; /* unused */
|
UWORD rows = _mm_read_UBYTE(modreader) + 2;
|
||||||
|
_mm_skip_BYTE(modreader); /* tempo */
|
||||||
|
|
||||||
crow = pat;
|
crow = pat;
|
||||||
/* file often allocates 64 rows even if there are less in pattern */
|
/* file often allocates 64 rows even if there are less in pattern */
|
||||||
if (mh2->patsiz[t]<2+(rows*16*4)) {
|
/* Also, don't allow more than 256 rows. */
|
||||||
|
if (mh2->patsiz[t]<2+(rows*16*4) || rows>256 || mh2->patsiz[t]>FAR_MAXPATSIZE) {
|
||||||
_mm_errno = MMERR_LOADING_PATTERN;
|
_mm_errno = MMERR_LOADING_PATTERN;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -280,8 +318,17 @@ static int FAR_Load(int curious)
|
||||||
_mm_errno=MMERR_LOADING_PATTERN;
|
_mm_errno=MMERR_LOADING_PATTERN;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
tracks+=16;
|
// Farandole Composer normally use a 64 rows blank track for patterns with 0 rows
|
||||||
|
for (u = 0; u < 16; u++) {
|
||||||
|
UniReset();
|
||||||
|
for (r = 0; r < 64; r++) {
|
||||||
|
UniNewline();
|
||||||
|
}
|
||||||
|
of.tracks[tracks++] = UniDup();
|
||||||
|
}
|
||||||
|
of.pattrows[t] = 64;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read sample map */
|
/* read sample map */
|
||||||
|
@ -319,11 +366,17 @@ static int FAR_Load(int curious)
|
||||||
q->loopend = s.repend;
|
q->loopend = s.repend;
|
||||||
q->volume = s.volume<<2;
|
q->volume = s.volume<<2;
|
||||||
|
|
||||||
if(s.type&1) q->flags|=SF_16BITS;
|
if(s.type&1) {
|
||||||
|
q->flags|=SF_16BITS;
|
||||||
|
q->length >>= 1;
|
||||||
|
q->loopstart >>= 1;
|
||||||
|
q->loopend >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
if(s.loop&8) q->flags|=SF_LOOP;
|
if(s.loop&8) q->flags|=SF_LOOP;
|
||||||
|
|
||||||
q->seekpos = _mm_ftell(modreader);
|
q->seekpos = _mm_ftell(modreader);
|
||||||
_mm_fseek(modreader,q->length,SEEK_CUR);
|
_mm_fseek(modreader,s.length,SEEK_CUR);
|
||||||
} else
|
} else
|
||||||
q->samplename = MikMod_strdup("");
|
q->samplename = MikMod_strdup("");
|
||||||
q++;
|
q++;
|
||||||
|
|
|
@ -221,7 +221,7 @@ static UBYTE *GDM_ConvertTrack(GDMNOTE*tr)
|
||||||
|
|
||||||
if ((ins)&&(ins!=255))
|
if ((ins)&&(ins!=255))
|
||||||
UniInstrument(ins-1);
|
UniInstrument(ins-1);
|
||||||
if (note!=255) {
|
if (note && note!=255) {
|
||||||
UniNote(((note>>4)*OCTAVE)+(note&0xf)-1);
|
UniNote(((note>>4)*OCTAVE)+(note&0xf)-1);
|
||||||
}
|
}
|
||||||
for (i=0;i<4;i++) {
|
for (i=0;i<4;i++) {
|
||||||
|
@ -237,18 +237,18 @@ static UBYTE *GDM_ConvertTrack(GDMNOTE*tr)
|
||||||
UniEffect(UNI_ITEFFECTG,inf);
|
UniEffect(UNI_ITEFFECTG,inf);
|
||||||
break;
|
break;
|
||||||
case 4: /* vibrato */
|
case 4: /* vibrato */
|
||||||
UniEffect(UNI_ITEFFECTH,inf);
|
UniEffect(UNI_GDMEFFECT4,inf);
|
||||||
break;
|
break;
|
||||||
case 5: /* portamento+volslide */
|
case 5: /* portamento+volslide */
|
||||||
UniEffect(UNI_ITEFFECTG,0);
|
UniEffect(UNI_ITEFFECTG,0);
|
||||||
UniEffect(UNI_S3MEFFECTD,inf);
|
UniEffect(UNI_S3MEFFECTD,inf);
|
||||||
break;
|
break;
|
||||||
case 6: /* vibrato+volslide */
|
case 6: /* vibrato+volslide */
|
||||||
UniEffect(UNI_ITEFFECTH,0);
|
UniEffect(UNI_GDMEFFECT4,0);
|
||||||
UniEffect(UNI_S3MEFFECTD,inf);
|
UniEffect(UNI_S3MEFFECTD,inf);
|
||||||
break;
|
break;
|
||||||
case 7: /* tremolo */
|
case 7: /* tremolo */
|
||||||
UniEffect(UNI_S3MEFFECTR,inf);
|
UniEffect(UNI_GDMEFFECT7,inf);
|
||||||
break;
|
break;
|
||||||
case 8: /* tremor */
|
case 8: /* tremor */
|
||||||
UniEffect(UNI_S3MEFFECTI,inf);
|
UniEffect(UNI_S3MEFFECTI,inf);
|
||||||
|
@ -271,37 +271,29 @@ static UBYTE *GDM_ConvertTrack(GDMNOTE*tr)
|
||||||
case 0x0e: /* extended */
|
case 0x0e: /* extended */
|
||||||
switch (inf&0xf0) {
|
switch (inf&0xf0) {
|
||||||
case 0x10: /* fine portamento up */
|
case 0x10: /* fine portamento up */
|
||||||
UniEffect(UNI_S3MEFFECTF, 0x0f|((inf<<4)&0x0f));
|
UniEffect(UNI_S3MEFFECTF, 0xf0|(inf&0x0f));
|
||||||
break;
|
break;
|
||||||
case 0x20: /* fine portamento down */
|
case 0x20: /* fine portamento down */
|
||||||
UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f));
|
UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f));
|
||||||
break;
|
break;
|
||||||
case 0x30: /* glissando control */
|
case 0x30: /* glissando control */
|
||||||
UniEffect(SS_GLISSANDO, inf&0x0f);
|
|
||||||
break;
|
|
||||||
case 0x40: /* vibrato waveform */
|
case 0x40: /* vibrato waveform */
|
||||||
UniEffect(SS_VIBWAVE, inf&0x0f);
|
|
||||||
break;
|
|
||||||
case 0x50: /* set c4spd */
|
case 0x50: /* set c4spd */
|
||||||
UniEffect(SS_FINETUNE, inf&0x0f);
|
|
||||||
break;
|
|
||||||
case 0x60: /* loop fun */
|
case 0x60: /* loop fun */
|
||||||
UniEffect(UNI_ITEFFECTS0, (inf&0x0f)|0xb0);
|
|
||||||
break;
|
|
||||||
case 0x70: /* tremolo waveform */
|
case 0x70: /* tremolo waveform */
|
||||||
UniEffect(SS_TREMWAVE, inf&0x0f);
|
UniPTEffect(0xe, inf);
|
||||||
break;
|
break;
|
||||||
case 0x80: /* extra fine porta up */
|
case 0x80: /* extra fine porta up */
|
||||||
UniEffect(UNI_S3MEFFECTF, 0x0e|((inf<<4)&0x0f));
|
UniEffect(UNI_S3MEFFECTF, 0xe0|(inf&0x0f));
|
||||||
break;
|
break;
|
||||||
case 0x90: /* extra fine porta down */
|
case 0x90: /* extra fine porta down */
|
||||||
UniEffect(UNI_S3MEFFECTE, 0xe0|(inf&0x0f));
|
UniEffect(UNI_S3MEFFECTE, 0xe0|(inf&0x0f));
|
||||||
break;
|
break;
|
||||||
case 0xa0: /* fine volslide up */
|
case 0xa0: /* fine volslide up */
|
||||||
UniEffect(UNI_S3MEFFECTD, 0x0f|((inf<<4)&0x0f));
|
UniEffect(UNI_S3MEFFECTD, 0x0f|((inf&0x0f)<<4));
|
||||||
break;
|
break;
|
||||||
case 0xb0: /* fine volslide down */
|
case 0xb0: /* fine volslide down */
|
||||||
UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f));
|
UniEffect(UNI_S3MEFFECTD, 0xf0|(inf&0x0f));
|
||||||
break;
|
break;
|
||||||
case 0xc0: /* note cut */
|
case 0xc0: /* note cut */
|
||||||
case 0xd0: /* note delay */
|
case 0xd0: /* note delay */
|
||||||
|
@ -320,18 +312,15 @@ static UBYTE *GDM_ConvertTrack(GDMNOTE*tr)
|
||||||
UniEffect(UNI_S3MEFFECTQ,inf);
|
UniEffect(UNI_S3MEFFECTQ,inf);
|
||||||
break;
|
break;
|
||||||
case 0x13: /* set global volume */
|
case 0x13: /* set global volume */
|
||||||
UniEffect(UNI_XMEFFECTG,inf<<1);
|
UniEffect(UNI_XMEFFECTG,inf);
|
||||||
break;
|
break;
|
||||||
case 0x14: /* fine vibrato */
|
case 0x14: /* fine vibrato */
|
||||||
UniEffect(UNI_ITEFFECTU,inf);
|
UniEffect(UNI_GDMEFFECT14,inf);
|
||||||
break;
|
break;
|
||||||
case 0x1e: /* special */
|
case 0x1e: /* special */
|
||||||
switch (inf&0xf0) {
|
switch (inf&0xf0) {
|
||||||
case 8: /* set pan position */
|
case 0x80: /* set pan position */
|
||||||
if (inf >=128)
|
UniPTEffect(0xe,inf);
|
||||||
UniPTEffect(0x08,255);
|
|
||||||
else
|
|
||||||
UniPTEffect(0x08,inf<<1);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -473,16 +462,21 @@ static int GDM_Load(int curious)
|
||||||
q->length=s.length;
|
q->length=s.length;
|
||||||
q->loopstart=s.loopbeg;
|
q->loopstart=s.loopbeg;
|
||||||
q->loopend=s.loopend;
|
q->loopend=s.loopend;
|
||||||
q->volume=s.vol;
|
q->volume=64;
|
||||||
q->panning=s.pan;
|
|
||||||
q->seekpos=position;
|
q->seekpos=position;
|
||||||
|
|
||||||
position +=s.length;
|
position +=s.length;
|
||||||
|
|
||||||
|
/* Only use the sample volume byte if bit 2 is set. When bit 3 is set,
|
||||||
|
the sample panning is supposed to be used, but 2GDM isn't capable
|
||||||
|
of making a GDM using this feature; the panning byte is always 0xFF
|
||||||
|
or junk. Likewise, bit 5 is unused (supposed to be LZW compression). */
|
||||||
if (s.flags&1)
|
if (s.flags&1)
|
||||||
q->flags |=SF_LOOP;
|
q->flags |=SF_LOOP;
|
||||||
if (s.flags&2)
|
if (s.flags&2)
|
||||||
q->flags |=SF_16BITS;
|
q->flags |=SF_16BITS;
|
||||||
|
if ((s.flags&4) && s.vol<=64)
|
||||||
|
q->volume=s.vol;
|
||||||
if (s.flags&16)
|
if (s.flags&16)
|
||||||
q->flags |=SF_STEREO;
|
q->flags |=SF_STEREO;
|
||||||
q++;
|
q++;
|
||||||
|
|
|
@ -76,6 +76,7 @@ typedef struct ITHEADER {
|
||||||
|
|
||||||
/* sample information */
|
/* sample information */
|
||||||
typedef struct ITSAMPLE {
|
typedef struct ITSAMPLE {
|
||||||
|
UBYTE id[4]; /* 'IMPS' */
|
||||||
CHAR filename[12];
|
CHAR filename[12];
|
||||||
UBYTE zerobyte;
|
UBYTE zerobyte;
|
||||||
UBYTE globvol;
|
UBYTE globvol;
|
||||||
|
@ -102,6 +103,7 @@ typedef struct ITSAMPLE {
|
||||||
#define ITENVCNT 25
|
#define ITENVCNT 25
|
||||||
#define ITNOTECNT 120
|
#define ITNOTECNT 120
|
||||||
typedef struct ITINSTHEADER {
|
typedef struct ITINSTHEADER {
|
||||||
|
UBYTE id[4]; /* 'IMPI' */
|
||||||
ULONG size; /* (dword) Instrument size */
|
ULONG size; /* (dword) Instrument size */
|
||||||
CHAR filename[12]; /* (char) Instrument filename */
|
CHAR filename[12]; /* (char) Instrument filename */
|
||||||
UBYTE zerobyte; /* (byte) Instrument type (always 0) */
|
UBYTE zerobyte; /* (byte) Instrument type (always 0) */
|
||||||
|
@ -194,8 +196,8 @@ static int IT_Init(void)
|
||||||
if(!(mh=(ITHEADER*)MikMod_malloc(sizeof(ITHEADER)))) return 0;
|
if(!(mh=(ITHEADER*)MikMod_malloc(sizeof(ITHEADER)))) return 0;
|
||||||
if(!(poslookup=(UBYTE*)MikMod_malloc(256*sizeof(UBYTE)))) return 0;
|
if(!(poslookup=(UBYTE*)MikMod_malloc(256*sizeof(UBYTE)))) return 0;
|
||||||
if(!(itpat=(ITNOTE*)MikMod_malloc(200*64*sizeof(ITNOTE)))) return 0;
|
if(!(itpat=(ITNOTE*)MikMod_malloc(200*64*sizeof(ITNOTE)))) return 0;
|
||||||
if(!(mask=(UBYTE*)MikMod_malloc(64*sizeof(UBYTE)))) return 0;
|
if(!(mask=(UBYTE*)MikMod_calloc(64,sizeof(UBYTE)))) return 0;
|
||||||
if(!(last=(ITNOTE*)MikMod_malloc(64*sizeof(ITNOTE)))) return 0;
|
if(!(last=(ITNOTE*)MikMod_calloc(64,sizeof(ITNOTE)))) return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -277,7 +279,10 @@ static UBYTE* IT_ConvertTrack(ITNOTE* tr,UWORD numrows)
|
||||||
UniNote(note);
|
UniNote(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((ins)&&(ins<100))
|
/* Impulse Tracker only allows up to 99 instruments and crashes when it
|
||||||
|
encounters instruments >=100. But the file format supports them just
|
||||||
|
fine and there are many MPT-created ITs with that many instruments. */
|
||||||
|
if((ins)&&(ins<253))
|
||||||
UniInstrument(ins-1);
|
UniInstrument(ins-1);
|
||||||
else if(ins==253)
|
else if(ins==253)
|
||||||
UniWriteByte(UNI_KEYOFF);
|
UniWriteByte(UNI_KEYOFF);
|
||||||
|
@ -632,7 +637,16 @@ static int IT_Load(int curious)
|
||||||
ITSAMPLE s;
|
ITSAMPLE s;
|
||||||
|
|
||||||
/* seek to sample position */
|
/* seek to sample position */
|
||||||
_mm_fseek(modreader,(long)(paraptr[mh->insnum+t]+4),SEEK_SET);
|
_mm_fseek(modreader,(long)(paraptr[mh->insnum+t]),SEEK_SET);
|
||||||
|
if(!_mm_read_UBYTES(s.id,4,modreader)||
|
||||||
|
memcmp(s.id,"IMPS",4) != 0) {
|
||||||
|
/* no error so that use-brdg.it and use-funk.it
|
||||||
|
* to load correctly (both IT 2.04) (from libxmp) */
|
||||||
|
#ifdef MIKMOD_DEBUG
|
||||||
|
fprintf(stderr,"Bad magic in sample %d\n",t);
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* load sample info */
|
/* load sample info */
|
||||||
_mm_read_string(s.filename,12,modreader);
|
_mm_read_string(s.filename,12,modreader);
|
||||||
|
@ -702,7 +716,8 @@ static int IT_Load(int curious)
|
||||||
if(s.flag&16) q->flags|=SF_LOOP;
|
if(s.flag&16) q->flags|=SF_LOOP;
|
||||||
if(s.flag&64) q->flags|=SF_BIDI;
|
if(s.flag&64) q->flags|=SF_BIDI;
|
||||||
|
|
||||||
if(mh->cwt>=0x200) {
|
if(s.convert==0xff) q->flags|=SF_ADPCM4|SF_SIGNED; /* MODPlugin ADPCM */
|
||||||
|
else if(mh->cwt>=0x200) {
|
||||||
if(s.convert&1) q->flags|=SF_SIGNED;
|
if(s.convert&1) q->flags|=SF_SIGNED;
|
||||||
if(s.convert&4) q->flags|=SF_DELTA;
|
if(s.convert&4) q->flags|=SF_DELTA;
|
||||||
}
|
}
|
||||||
|
@ -719,7 +734,12 @@ static int IT_Load(int curious)
|
||||||
ITINSTHEADER ih;
|
ITINSTHEADER ih;
|
||||||
|
|
||||||
/* seek to instrument position */
|
/* seek to instrument position */
|
||||||
_mm_fseek(modreader,paraptr[t]+4,SEEK_SET);
|
_mm_fseek(modreader,paraptr[t],SEEK_SET);
|
||||||
|
if(!_mm_read_UBYTES(ih.id,4,modreader)||
|
||||||
|
memcmp(ih.id,"IMPI",4) != 0) {
|
||||||
|
_mm_errno = MMERR_LOADING_SAMPLEINFO;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* load instrument info */
|
/* load instrument info */
|
||||||
_mm_read_string(ih.filename,12,modreader);
|
_mm_read_string(ih.filename,12,modreader);
|
||||||
|
@ -988,8 +1008,6 @@ static int IT_Load(int curious)
|
||||||
if(!AllocTracks()) return 0;
|
if(!AllocTracks()) return 0;
|
||||||
|
|
||||||
for(t=0;t<of.numpat;t++) {
|
for(t=0;t<of.numpat;t++) {
|
||||||
UWORD packlen;
|
|
||||||
|
|
||||||
/* seek to pattern position */
|
/* seek to pattern position */
|
||||||
if(!paraptr[mh->insnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */
|
if(!paraptr[mh->insnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */
|
||||||
of.pattrows[t]=64;
|
of.pattrows[t]=64;
|
||||||
|
@ -1002,8 +1020,7 @@ static int IT_Load(int curious)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET);
|
_mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET);
|
||||||
packlen=_mm_read_I_UWORD(modreader);
|
(void) _mm_read_I_UWORD(modreader); /* packlen */
|
||||||
(void)packlen; /* unused */
|
|
||||||
of.pattrows[t]=_mm_read_I_UWORD(modreader);
|
of.pattrows[t]=_mm_read_I_UWORD(modreader);
|
||||||
_mm_read_I_ULONG(modreader);
|
_mm_read_I_ULONG(modreader);
|
||||||
if(!IT_ReadPattern(of.pattrows[t])) return 0;
|
if(!IT_ReadPattern(of.pattrows[t])) return 0;
|
||||||
|
|
|
@ -20,8 +20,6 @@
|
||||||
|
|
||||||
/*==============================================================================
|
/*==============================================================================
|
||||||
|
|
||||||
$Id$
|
|
||||||
|
|
||||||
Amiga MED module loader
|
Amiga MED module loader
|
||||||
|
|
||||||
==============================================================================*/
|
==============================================================================*/
|
||||||
|
@ -48,6 +46,8 @@ extern int fprintf(FILE *, const char *, ...);
|
||||||
|
|
||||||
/*========== Module information */
|
/*========== Module information */
|
||||||
|
|
||||||
|
#define MEDNOTECNT 120
|
||||||
|
|
||||||
typedef struct MEDHEADER {
|
typedef struct MEDHEADER {
|
||||||
ULONG id;
|
ULONG id;
|
||||||
ULONG modlen;
|
ULONG modlen;
|
||||||
|
@ -137,6 +137,19 @@ typedef struct MEDINSTINFO {
|
||||||
UBYTE name[40];
|
UBYTE name[40];
|
||||||
} MEDINSTINFO;
|
} MEDINSTINFO;
|
||||||
|
|
||||||
|
enum MEDINSTTYPE {
|
||||||
|
INST_HYBRID = -2,
|
||||||
|
INST_SYNTH = -1,
|
||||||
|
INST_SAMPLE = 0,
|
||||||
|
INST_IFFOCT_5 = 1,
|
||||||
|
INST_IFFOCT_3 = 2,
|
||||||
|
INST_IFFOCT_2 = 3,
|
||||||
|
INST_IFFOCT_4 = 4,
|
||||||
|
INST_IFFOCT_6 = 5,
|
||||||
|
INST_IFFOCT_7 = 6,
|
||||||
|
INST_EXTSAMPLE = 7
|
||||||
|
};
|
||||||
|
|
||||||
/*========== Loader variables */
|
/*========== Loader variables */
|
||||||
|
|
||||||
#define MMD0_string 0x4D4D4430
|
#define MMD0_string 0x4D4D4430
|
||||||
|
@ -149,8 +162,11 @@ static ULONG *ba = NULL;
|
||||||
static MMD0NOTE *mmd0pat = NULL;
|
static MMD0NOTE *mmd0pat = NULL;
|
||||||
static MMD1NOTE *mmd1pat = NULL;
|
static MMD1NOTE *mmd1pat = NULL;
|
||||||
|
|
||||||
|
static UBYTE medversion;
|
||||||
static int decimalvolumes;
|
static int decimalvolumes;
|
||||||
static int bpmtempos;
|
static int bpmtempos;
|
||||||
|
static int is8channel;
|
||||||
|
static UWORD rowsperbeat;
|
||||||
|
|
||||||
#define d0note(row,col) mmd0pat[((row)*(UWORD)of.numchn)+(col)]
|
#define d0note(row,col) mmd0pat[((row)*(UWORD)of.numchn)+(col)]
|
||||||
#define d1note(row,col) mmd1pat[((row)*(UWORD)of.numchn)+(col)]
|
#define d1note(row,col) mmd1pat[((row)*(UWORD)of.numchn)+(col)]
|
||||||
|
@ -197,52 +213,118 @@ static void MED_Cleanup(void)
|
||||||
mmd1pat = NULL;
|
mmd1pat = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EffectCvt(UBYTE eff, UBYTE dat)
|
static UWORD MED_ConvertTempo(UWORD tempo)
|
||||||
|
{
|
||||||
|
/* MED tempos 1-10 are compatibility tempos that are converted to different values.
|
||||||
|
These were determined by testing with OctaMED 2.00 and roughly correspond to the
|
||||||
|
formula: (195 + speed/2) / speed. Despite being "tracker compatible" these really
|
||||||
|
are supposed to change the tempo and NOT the speed. These are tempo-mode only. */
|
||||||
|
static const UBYTE tempocompat[11] =
|
||||||
|
{
|
||||||
|
0, 195, 97, 65, 49, 39, 32, 28, 24, 22, 20
|
||||||
|
};
|
||||||
|
|
||||||
|
/* MEDs with 8 channels do something completely different with their tempos.
|
||||||
|
This behavior completely overrides normal timing when it is enabled.
|
||||||
|
NOTE: the tempos used for this are directly from OctaMED Soundstudio 2, but
|
||||||
|
in older versions the playback speeds differed slightly between NTSC and PAL.
|
||||||
|
This table seems to have been intended to be a compromise between the two.*/
|
||||||
|
static const UBYTE tempo8channel[11] =
|
||||||
|
{
|
||||||
|
0, 179, 164, 152, 141, 131, 123, 116, 110, 104, 99
|
||||||
|
};
|
||||||
|
|
||||||
|
ULONG result;
|
||||||
|
|
||||||
|
if (is8channel) {
|
||||||
|
tempo = tempo < 10 ? tempo : 10;
|
||||||
|
return tempo8channel[tempo];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bpmtempos) {
|
||||||
|
/* Convert MED BPM into ProTracker-compatible BPM. All that really needs to be done
|
||||||
|
here is the BPM needs to be multiplied by (rows per beat)/(PT rows per beat = 4).
|
||||||
|
BPM mode doesn't have compatibility tempos like tempo mode but OctaMED does
|
||||||
|
something unusual with BPM<=2 that was found in electrosound 64.med. */
|
||||||
|
result = (tempo > 2) ? ((ULONG)tempo * rowsperbeat + 2) / 4 : 125;
|
||||||
|
} else {
|
||||||
|
if (tempo >= 1 && tempo <= 10)
|
||||||
|
tempo = tempocompat[tempo];
|
||||||
|
|
||||||
|
/* Convert MED tempo into ProTracker-compatble BPM. */
|
||||||
|
result = ((ULONG)tempo * 125) / 33;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result < 65535 ? result : 65535;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void EffectCvt(UBYTE note, UBYTE eff, UBYTE dat)
|
||||||
{
|
{
|
||||||
switch (eff) {
|
switch (eff) {
|
||||||
/* 0x0 0x1 0x2 0x3 0x4 PT effects */
|
/* 0x0: arpeggio */
|
||||||
case 0x5: /* PT vibrato with speed/depth nibbles swapped */
|
case 0x1: /* portamento up (PT compatible, ignore 0) */
|
||||||
UniPTEffect(0x4, (dat >> 4) | ((dat & 0xf) << 4));
|
if (dat)
|
||||||
|
UniPTEffect(0x1, dat);
|
||||||
break;
|
break;
|
||||||
/* 0x6 0x7 not used */
|
case 0x2: /* portamento down (PT compatible, ignore 0) */
|
||||||
case 0x6:
|
if (dat)
|
||||||
case 0x7:
|
UniPTEffect(0x2, dat);
|
||||||
break;
|
break;
|
||||||
case 0x8: /* midi hold/decay */
|
/* 0x3: tone portamento */
|
||||||
|
case 0x4: /* vibrato (~2x the speed/depth of PT vibrato) */
|
||||||
|
UniWriteByte(UNI_MEDEFFECT_VIB);
|
||||||
|
UniWriteByte((dat & 0xf0) >> 3);
|
||||||
|
UniWriteByte((dat & 0x0f) << 1);
|
||||||
break;
|
break;
|
||||||
case 0x9:
|
case 0x5: /* tone portamento + volslide (MMD0: old vibrato) */
|
||||||
if (bpmtempos) {
|
if (medversion == 0) {
|
||||||
if (!dat)
|
/* Approximate conversion, probably wrong.
|
||||||
dat = of.initspeed;
|
The entire param is depth and the rate is fixed. */
|
||||||
|
UniWriteByte(UNI_MEDEFFECT_VIB);
|
||||||
|
UniWriteByte(0x16);
|
||||||
|
UniWriteByte((dat + 3) >> 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
UniPTEffect(eff, dat);
|
||||||
|
break;
|
||||||
|
/* 0x6: vibrato + volslide */
|
||||||
|
/* 0x7: tremolo */
|
||||||
|
case 0x8: /* set hold/decay (FIXME- hold/decay not implemented) */
|
||||||
|
break;
|
||||||
|
case 0x9: /* set speed */
|
||||||
|
/* TODO: Rarely MED modules request values of 0x00 or >0x20. In most Amiga versions
|
||||||
|
these behave as speed=(param & 0x1F) ? (param & 0x1F) : 32. From Soundstudio 2
|
||||||
|
up, these have different behavior. Since the docs/UI insist you shouldn't use
|
||||||
|
these values and not many modules use these, just ignore them for now. */
|
||||||
|
if (dat >= 0x01 && dat <= 0x20) {
|
||||||
UniEffect(UNI_S3MEFFECTA, dat);
|
UniEffect(UNI_S3MEFFECTA, dat);
|
||||||
} else {
|
|
||||||
if (dat <= 0x20) {
|
|
||||||
if (!dat)
|
|
||||||
dat = of.initspeed;
|
|
||||||
else
|
|
||||||
dat /= 4;
|
|
||||||
UniPTEffect(0xf, dat);
|
|
||||||
} else
|
|
||||||
UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / (33 * 4));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
/* 0xa 0xb PT effects */
|
/* 0xa: volslide */
|
||||||
|
/* 0xb: position jump */
|
||||||
case 0xc:
|
case 0xc:
|
||||||
if (decimalvolumes)
|
if (decimalvolumes)
|
||||||
dat = (dat >> 4) * 10 + (dat & 0xf);
|
dat = (dat >> 4) * 10 + (dat & 0xf);
|
||||||
UniPTEffect(0xc, dat);
|
UniPTEffect(0xc, dat);
|
||||||
break;
|
break;
|
||||||
|
case 0xa:
|
||||||
case 0xd: /* same as PT volslide */
|
case 0xd: /* same as PT volslide */
|
||||||
|
/* if both nibbles are set, a slide up is performed. */
|
||||||
|
if ((dat & 0xf) && (dat & 0xf0))
|
||||||
|
dat &= 0xf0;
|
||||||
UniPTEffect(0xa, dat);
|
UniPTEffect(0xa, dat);
|
||||||
break;
|
break;
|
||||||
case 0xe: /* synth jmp - midi */
|
case 0xe: /* synth jump (FIXME- synth instruments not implemented) */
|
||||||
break;
|
break;
|
||||||
case 0xf:
|
case 0xf:
|
||||||
switch (dat) {
|
switch (dat) {
|
||||||
case 0: /* patternbreak */
|
case 0: /* patternbreak */
|
||||||
UniPTEffect(0xd, 0);
|
UniPTEffect(0xd, 0);
|
||||||
break;
|
break;
|
||||||
case 0xf1: /* play note twice */
|
case 0xf1: /* play note twice */
|
||||||
|
/* Note: OctaMED 6.00d and up will not play FF1/FF3 effects when
|
||||||
|
they are used on a line without a note. Since MMD2/MMD3 support is
|
||||||
|
theoretical at this point, allow these unconditionally for now. */
|
||||||
UniWriteByte(UNI_MEDEFFECTF1);
|
UniWriteByte(UNI_MEDEFFECTF1);
|
||||||
break;
|
break;
|
||||||
case 0xf2: /* delay note */
|
case 0xf2: /* delay note */
|
||||||
|
@ -251,6 +333,15 @@ static void EffectCvt(UBYTE eff, UBYTE dat)
|
||||||
case 0xf3: /* play note three times */
|
case 0xf3: /* play note three times */
|
||||||
UniWriteByte(UNI_MEDEFFECTF3);
|
UniWriteByte(UNI_MEDEFFECTF3);
|
||||||
break;
|
break;
|
||||||
|
case 0xf8: /* hardware filter off */
|
||||||
|
UniPTEffect(0xe, 0x01);
|
||||||
|
break;
|
||||||
|
case 0xf9: /* hardware filter on */
|
||||||
|
UniPTEffect(0xe, 0x00);
|
||||||
|
break;
|
||||||
|
case 0xfd: /* set pitch */
|
||||||
|
UniWriteByte(UNI_MEDEFFECT_FD);
|
||||||
|
break;
|
||||||
case 0xfe: /* stop playing */
|
case 0xfe: /* stop playing */
|
||||||
UniPTEffect(0xb, of.numpat);
|
UniPTEffect(0xb, of.numpat);
|
||||||
break;
|
break;
|
||||||
|
@ -258,18 +349,65 @@ static void EffectCvt(UBYTE eff, UBYTE dat)
|
||||||
UniPTEffect(0xc, 0);
|
UniPTEffect(0xc, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (dat <= 10)
|
if (dat <= 240)
|
||||||
UniPTEffect(0xf, dat);
|
UniEffect(UNI_MEDSPEED, MED_ConvertTempo(dat));
|
||||||
else if (dat <= 240) {
|
|
||||||
if (bpmtempos)
|
|
||||||
UniPTEffect(0xf, (dat < 32) ? 32 : dat);
|
|
||||||
else
|
|
||||||
UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / 33);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: /* all normal PT effects are handled here */
|
case 0x11: /* fine portamento up */
|
||||||
UniPTEffect(eff, dat);
|
/* fine portamento of 0 does nothing. */
|
||||||
|
if (dat)
|
||||||
|
UniEffect(UNI_XMEFFECTE1, dat);
|
||||||
|
break;
|
||||||
|
case 0x12: /* fine portamento down */
|
||||||
|
if (dat)
|
||||||
|
UniEffect(UNI_XMEFFECTE2, dat);
|
||||||
|
break;
|
||||||
|
case 0x14: /* vibrato (PT compatible depth, ~2x speed) */
|
||||||
|
UniWriteByte(UNI_MEDEFFECT_VIB);
|
||||||
|
UniWriteByte((dat & 0xf0) >> 3);
|
||||||
|
UniWriteByte((dat & 0x0f));
|
||||||
|
break;
|
||||||
|
case 0x15: /* set finetune */
|
||||||
|
/* Valid values are 0x0 to 0x7 and 0xF8 to 0xFF. */
|
||||||
|
if (dat <= 0x7 || dat >= 0xF8)
|
||||||
|
UniPTEffect(0xe, 0x50 | (dat & 0xF));
|
||||||
|
break;
|
||||||
|
case 0x16: /* loop */
|
||||||
|
UniEffect(UNI_MEDEFFECT_16, dat);
|
||||||
|
break;
|
||||||
|
case 0x18: /* cut note */
|
||||||
|
UniEffect(UNI_MEDEFFECT_18, dat);
|
||||||
|
break;
|
||||||
|
case 0x19: /* sample offset */
|
||||||
|
UniPTEffect(0x9, dat);
|
||||||
|
break;
|
||||||
|
case 0x1a: /* fine volslide up */
|
||||||
|
/* volslide of 0 does nothing. */
|
||||||
|
if (dat)
|
||||||
|
UniEffect(UNI_XMEFFECTEA, dat);
|
||||||
|
break;
|
||||||
|
case 0x1b: /* fine volslide down */
|
||||||
|
if (dat)
|
||||||
|
UniEffect(UNI_XMEFFECTEB, dat);
|
||||||
|
break;
|
||||||
|
case 0x1d: /* pattern break */
|
||||||
|
UniPTEffect(0xd, dat);
|
||||||
|
break;
|
||||||
|
case 0x1e: /* pattern delay */
|
||||||
|
UniEffect(UNI_MEDEFFECT_1E, dat);
|
||||||
|
break;
|
||||||
|
case 0x1f: /* combined delay-retrigger */
|
||||||
|
/* This effect does nothing on lines without a note. */
|
||||||
|
if (note)
|
||||||
|
UniEffect(UNI_MEDEFFECT_1F, dat);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (eff < 0x10)
|
||||||
|
UniPTEffect(eff, dat);
|
||||||
|
#ifdef MIKMOD_DEBUG
|
||||||
|
else
|
||||||
|
fprintf(stderr, "unsupported OctaMED command %u\n", eff);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,14 +424,14 @@ static UBYTE *MED_Convert1(int count, int col)
|
||||||
|
|
||||||
note = n->a & 0x7f;
|
note = n->a & 0x7f;
|
||||||
inst = n->b & 0x3f;
|
inst = n->b & 0x3f;
|
||||||
eff = n->c & 0xf;
|
eff = n->c;
|
||||||
dat = n->d;
|
dat = n->d;
|
||||||
|
|
||||||
if (inst)
|
if (inst)
|
||||||
UniInstrument(inst - 1);
|
UniInstrument(inst - 1);
|
||||||
if (note)
|
if (note)
|
||||||
UniNote(note + 3 * OCTAVE - 1);
|
UniNote(note - 1);
|
||||||
EffectCvt(eff, dat);
|
EffectCvt(note, eff, dat);
|
||||||
UniNewline();
|
UniNewline();
|
||||||
}
|
}
|
||||||
return UniDup();
|
return UniDup();
|
||||||
|
@ -321,8 +459,8 @@ static UBYTE *MED_Convert0(int count, int col)
|
||||||
if (inst)
|
if (inst)
|
||||||
UniInstrument(inst - 1);
|
UniInstrument(inst - 1);
|
||||||
if (note)
|
if (note)
|
||||||
UniNote(note + 3 * OCTAVE - 1);
|
UniNote(note - 1);
|
||||||
EffectCvt(eff, dat);
|
EffectCvt(note, eff, dat);
|
||||||
UniNewline();
|
UniNewline();
|
||||||
}
|
}
|
||||||
return UniDup();
|
return UniDup();
|
||||||
|
@ -349,7 +487,7 @@ static int LoadMEDPatterns(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* sanity check */
|
/* sanity check */
|
||||||
if (! of.numchn) /* docs say 4, 8, 12 or 16 */
|
if (! of.numchn || of.numchn > 16) /* docs say 4, 8, 12 or 16 */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
of.numtrk = of.numpat * of.numchn;
|
of.numtrk = of.numpat * of.numchn;
|
||||||
|
@ -375,6 +513,8 @@ static int LoadMEDPatterns(void)
|
||||||
mmdp->b = _mm_read_UBYTE(modreader);
|
mmdp->b = _mm_read_UBYTE(modreader);
|
||||||
mmdp->c = _mm_read_UBYTE(modreader);
|
mmdp->c = _mm_read_UBYTE(modreader);
|
||||||
}
|
}
|
||||||
|
/* Skip tracks this block doesn't use. */
|
||||||
|
for (col = numtracks; col < of.numchn; col++, mmdp++) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (col = 0; col < of.numchn; col++)
|
for (col = 0; col < of.numchn; col++)
|
||||||
|
@ -405,7 +545,7 @@ static int LoadMMD1Patterns(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* sanity check */
|
/* sanity check */
|
||||||
if (! of.numchn) /* docs say 4, 8, 12 or 16 */
|
if (! of.numchn || of.numchn > 16) /* docs say 4, 8, 12 or 16 */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
of.numtrk = of.numpat * of.numchn;
|
of.numtrk = of.numpat * of.numchn;
|
||||||
|
@ -434,6 +574,8 @@ static int LoadMMD1Patterns(void)
|
||||||
mmdp->c = _mm_read_UBYTE(modreader);
|
mmdp->c = _mm_read_UBYTE(modreader);
|
||||||
mmdp->d = _mm_read_UBYTE(modreader);
|
mmdp->d = _mm_read_UBYTE(modreader);
|
||||||
}
|
}
|
||||||
|
/* Skip tracks this block doesn't use. */
|
||||||
|
for (col = numtracks; col < of.numchn; col++, mmdp++) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (col = 0; col < of.numchn; col++)
|
for (col = 0; col < of.numchn; col++)
|
||||||
|
@ -444,9 +586,10 @@ static int LoadMMD1Patterns(void)
|
||||||
|
|
||||||
static int MED_Load(int curious)
|
static int MED_Load(int curious)
|
||||||
{
|
{
|
||||||
int t;
|
int t, i;
|
||||||
ULONG sa[64];
|
ULONG sa[64];
|
||||||
MEDINSTHEADER s;
|
MEDINSTHEADER s;
|
||||||
|
INSTRUMENT *d;
|
||||||
SAMPLE *q;
|
SAMPLE *q;
|
||||||
MEDSAMPLE *mss;
|
MEDSAMPLE *mss;
|
||||||
|
|
||||||
|
@ -536,7 +679,7 @@ static int MED_Load(int curious)
|
||||||
_mm_errno = MMERR_NOT_A_MODULE;
|
_mm_errno = MMERR_NOT_A_MODULE;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* truncate insane songnamelen (fail instead??) */
|
/* truncate insane songnamelen (fail instead?) */
|
||||||
if (me->songnamelen > 256)
|
if (me->songnamelen > 256)
|
||||||
me->songnamelen = 256;
|
me->songnamelen = 256;
|
||||||
}
|
}
|
||||||
|
@ -570,46 +713,18 @@ static int MED_Load(int curious)
|
||||||
}
|
}
|
||||||
|
|
||||||
decimalvolumes = (ms->flags & 0x10) ? 0 : 1;
|
decimalvolumes = (ms->flags & 0x10) ? 0 : 1;
|
||||||
|
is8channel = (ms->flags & 0x40) ? 1 : 0;
|
||||||
bpmtempos = (ms->flags2 & 0x20) ? 1 : 0;
|
bpmtempos = (ms->flags2 & 0x20) ? 1 : 0;
|
||||||
|
|
||||||
if (bpmtempos) {
|
if (bpmtempos) {
|
||||||
int bpmlen = (ms->flags2 & 0x1f) + 1;
|
rowsperbeat = (ms->flags2 & 0x1f) + 1;
|
||||||
of.initspeed = ms->tempo2;
|
of.initspeed = ms->tempo2;
|
||||||
of.inittempo = ms->deftempo * bpmlen / 4;
|
of.inittempo = MED_ConvertTempo(ms->deftempo);
|
||||||
|
|
||||||
if (bpmlen != 4) {
|
|
||||||
/* Let's do some math : compute GCD of BPM beat length and speed */
|
|
||||||
int a, b;
|
|
||||||
|
|
||||||
a = bpmlen;
|
|
||||||
b = ms->tempo2;
|
|
||||||
|
|
||||||
if (a > b) {
|
|
||||||
t = b;
|
|
||||||
b = a;
|
|
||||||
a = t;
|
|
||||||
}
|
|
||||||
while ((a != b) && (a)) {
|
|
||||||
t = a;
|
|
||||||
a = b - a;
|
|
||||||
b = t;
|
|
||||||
if (a > b) {
|
|
||||||
t = b;
|
|
||||||
b = a;
|
|
||||||
a = t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
of.initspeed /= b;
|
|
||||||
of.inittempo = ms->deftempo * bpmlen / (4 * b);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
of.initspeed = ms->tempo2;
|
of.initspeed = ms->tempo2;
|
||||||
of.inittempo = ms->deftempo ? ((UWORD)ms->deftempo * 125) / 33 : 128;
|
of.inittempo = ms->deftempo ? MED_ConvertTempo(ms->deftempo) : 128;
|
||||||
if ((ms->deftempo <= 10) && (ms->deftempo))
|
|
||||||
of.inittempo = (of.inittempo * 33) / 6;
|
|
||||||
of.flags |= UF_HIGHBPM;
|
|
||||||
}
|
}
|
||||||
|
of.flags |= UF_HIGHBPM;
|
||||||
MED_Version[12] = mh->id;
|
MED_Version[12] = mh->id;
|
||||||
of.modtype = MikMod_strdup(MED_Version);
|
of.modtype = MikMod_strdup(MED_Version);
|
||||||
of.numchn = 0; /* will be counted later */
|
of.numchn = 0; /* will be counted later */
|
||||||
|
@ -633,18 +748,29 @@ static int MED_Load(int curious)
|
||||||
ReadComment(me->annolen);
|
ReadComment(me->annolen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!AllocSamples())
|
/* TODO: should do an initial scan for IFFOCT instruments to determine the
|
||||||
|
actual number of samples (instead of assuming 1-to-1). */
|
||||||
|
if (!AllocSamples() || !AllocInstruments())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
of.flags |= UF_INST;
|
||||||
q = of.samples;
|
q = of.samples;
|
||||||
|
d = of.instruments;
|
||||||
for (t = 0; t < of.numins; t++) {
|
for (t = 0; t < of.numins; t++) {
|
||||||
q->flags = SF_SIGNED;
|
q->flags = SF_SIGNED;
|
||||||
q->volume = 64;
|
q->volume = 64;
|
||||||
|
s.type = INST_SAMPLE;
|
||||||
if (sa[t]) {
|
if (sa[t]) {
|
||||||
_mm_fseek(modreader, sa[t], SEEK_SET);
|
_mm_fseek(modreader, sa[t], SEEK_SET);
|
||||||
s.length = _mm_read_M_ULONG(modreader);
|
s.length = _mm_read_M_ULONG(modreader);
|
||||||
s.type = _mm_read_M_SWORD(modreader);
|
s.type = _mm_read_M_SWORD(modreader);
|
||||||
|
|
||||||
if (s.type) {
|
switch (s.type) {
|
||||||
|
case INST_SAMPLE:
|
||||||
|
case INST_EXTSAMPLE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
#ifdef MIKMOD_DEBUG
|
#ifdef MIKMOD_DEBUG
|
||||||
fprintf(stderr, "\rNon-sample instruments not supported in MED loader yet\n");
|
fprintf(stderr, "\rNon-sample instruments not supported in MED loader yet\n");
|
||||||
#endif
|
#endif
|
||||||
|
@ -668,6 +794,9 @@ static int MED_Load(int curious)
|
||||||
if (ms->sample[t].replen > 1)
|
if (ms->sample[t].replen > 1)
|
||||||
q->flags |= SF_LOOP;
|
q->flags |= SF_LOOP;
|
||||||
|
|
||||||
|
if(ms->sample[t].svol <= 64)
|
||||||
|
q->volume = ms->sample[t].svol;
|
||||||
|
|
||||||
/* don't load sample if length>='MMD0'...
|
/* don't load sample if length>='MMD0'...
|
||||||
such kluges make libmikmod's code unique !!! */
|
such kluges make libmikmod's code unique !!! */
|
||||||
if (q->length >= MMD0_string)
|
if (q->length >= MMD0_string)
|
||||||
|
@ -697,18 +826,53 @@ static int MED_Load(int curious)
|
||||||
_mm_fseek(modreader, me->iinfo + t * me->i_ext_entrsz, SEEK_SET);
|
_mm_fseek(modreader, me->iinfo + t * me->i_ext_entrsz, SEEK_SET);
|
||||||
_mm_read_UBYTES(ii.name, 40, modreader);
|
_mm_read_UBYTES(ii.name, 40, modreader);
|
||||||
q->samplename = DupStr((char*)ii.name, 40, 1);
|
q->samplename = DupStr((char*)ii.name, 40, 1);
|
||||||
} else
|
d->insname = DupStr((char*)ii.name, 40, 1);
|
||||||
|
} else {
|
||||||
q->samplename = NULL;
|
q->samplename = NULL;
|
||||||
|
d->insname = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Instrument transpose tables. */
|
||||||
|
for (i = 0; i < MEDNOTECNT; i++) {
|
||||||
|
int note = i + 3 * OCTAVE + ms->sample[t].strans + ms->playtransp;
|
||||||
|
|
||||||
|
/* TODO: IFFOCT instruments... */
|
||||||
|
switch (s.type) {
|
||||||
|
case INST_EXTSAMPLE:
|
||||||
|
/* TODO: not clear if this has the same wrapping behavior as regular samples.
|
||||||
|
This is a MMD2/MMD3 extension so it has not been tested. */
|
||||||
|
note -= 2 * OCTAVE;
|
||||||
|
/* fall-through */
|
||||||
|
|
||||||
|
case INST_SAMPLE:
|
||||||
|
/* TODO: in MMD2/MMD3 mixing mode, these wrapping transforms don't apply. */
|
||||||
|
if (note >= 10 * OCTAVE) {
|
||||||
|
/* Buggy octaves 8 through A wrap to 2 octaves below octave 1.
|
||||||
|
Technically they're also a finetune step higher but that's safe
|
||||||
|
to ignore. */
|
||||||
|
note -= 9 * OCTAVE;
|
||||||
|
} else if (note >= 6 * OCTAVE) {
|
||||||
|
/* Octaves 4 through 7 repeat octave 3. */
|
||||||
|
note = (note % 12) + 5 * OCTAVE;
|
||||||
|
}
|
||||||
|
d->samplenumber[i] = t;
|
||||||
|
d->samplenote[i] = note<0 ? 0 : note>255 ? 255 : note;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
q++;
|
q++;
|
||||||
|
d++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mh->id == MMD0_string) {
|
if (mh->id == MMD0_string) {
|
||||||
|
medversion = 0;
|
||||||
if (!LoadMEDPatterns()) {
|
if (!LoadMEDPatterns()) {
|
||||||
_mm_errno = MMERR_LOADING_PATTERN;
|
_mm_errno = MMERR_LOADING_PATTERN;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (mh->id == MMD1_string) {
|
} else if (mh->id == MMD1_string) {
|
||||||
|
medversion = 1;
|
||||||
if (!LoadMMD1Patterns()) {
|
if (!LoadMMD1Patterns()) {
|
||||||
_mm_errno = MMERR_LOADING_PATTERN;
|
_mm_errno = MMERR_LOADING_PATTERN;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -84,10 +84,13 @@ typedef struct MODNOTE {
|
||||||
static CHAR protracker[] = "Protracker";
|
static CHAR protracker[] = "Protracker";
|
||||||
static CHAR startrekker[] = "Startrekker";
|
static CHAR startrekker[] = "Startrekker";
|
||||||
static CHAR fasttracker[] = "Fasttracker";
|
static CHAR fasttracker[] = "Fasttracker";
|
||||||
static CHAR oktalyser[] = "Oktalyser";
|
static CHAR octalyser[] = "Octalyser";
|
||||||
static CHAR oktalyzer[] = "Oktalyzer";
|
static CHAR oktalyzer[] = "Oktalyzer";
|
||||||
static CHAR taketracker[] = "TakeTracker";
|
static CHAR taketracker[] = "TakeTracker";
|
||||||
|
static CHAR digitaltracker[] = "Digital Tracker MOD";
|
||||||
static CHAR orpheus[] = "Imago Orpheus (MOD format)";
|
static CHAR orpheus[] = "Imago Orpheus (MOD format)";
|
||||||
|
static CHAR modsgrave[] = "Mod's Grave";
|
||||||
|
static CHAR unknown[] = "Unknown tracker MOD";
|
||||||
|
|
||||||
static MODULEHEADER *mh = NULL;
|
static MODULEHEADER *mh = NULL;
|
||||||
static MODNOTE *patbuf = NULL;
|
static MODNOTE *patbuf = NULL;
|
||||||
|
@ -102,7 +105,7 @@ static int MOD_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)
|
||||||
modtype = trekker = 0;
|
modtype = trekker = 0;
|
||||||
|
|
||||||
/* Protracker and variants */
|
/* Protracker and variants */
|
||||||
if ((!memcmp(id, "M.K.", 4)) || (!memcmp(id, "M!K!", 4))) {
|
if ((!memcmp(id, "M.K.", 4)) || (!memcmp(id, "M!K!", 4)) || (!memcmp(id, "M&K!", 4))) {
|
||||||
*descr = protracker;
|
*descr = protracker;
|
||||||
modtype = 0;
|
modtype = 0;
|
||||||
*numchn = 4;
|
*numchn = 4;
|
||||||
|
@ -132,11 +135,11 @@ static int MOD_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Oktalyser (Atari) */
|
/* Octalyser (Atari) */
|
||||||
if (!memcmp(id, "CD81", 4)) {
|
if (!memcmp(id, "CD81", 4) || !memcmp(id, "CD61", 4)) {
|
||||||
*descr = oktalyser;
|
*descr = octalyser;
|
||||||
modtype = 1;
|
modtype = 1;
|
||||||
*numchn = 8;
|
*numchn = id[2] - '0';
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +163,27 @@ static int MOD_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)
|
||||||
*numchn = (id[0] - '0') * 10 + (id[1] - '0');
|
*numchn = (id[0] - '0') * 10 + (id[1] - '0');
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
/* Taketracker */
|
||||||
|
if (!memcmp(id, "TDZ", 3) && (id[3] >= '1' && id[3] <= '3')) {
|
||||||
|
*descr = taketracker;
|
||||||
|
*numchn = (id[3] - '0');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Digital Tracker */
|
||||||
|
if (!memcmp(id, "FA0", 3) && (id[3] == '4' || id[3] == '6' || id[3] == '8')) {
|
||||||
|
*descr = digitaltracker;
|
||||||
|
*numchn = (id[3] - '0');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Standard 4-channel MODs with unusual IDs. */
|
||||||
|
if (!memcmp(id, "LARD", 4) /* judgement_day_gvine.mod */
|
||||||
|
|| !memcmp(id, "NSMS", 4)) { /* kingdomofpleasure.mod */
|
||||||
|
*descr = unknown;
|
||||||
|
*numchn = 4;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -368,6 +392,16 @@ static int MOD_Load(int curious)
|
||||||
SAMPLE *q;
|
SAMPLE *q;
|
||||||
MSAMPINFO *s;
|
MSAMPINFO *s;
|
||||||
CHAR *descr;
|
CHAR *descr;
|
||||||
|
int maybewow = 1;
|
||||||
|
ULONG samplelength = 0;
|
||||||
|
ULONG filelength;
|
||||||
|
ULONG pos;
|
||||||
|
char adpcm[5];
|
||||||
|
|
||||||
|
pos = _mm_ftell(modreader);
|
||||||
|
_mm_fseek(modreader, 0, SEEK_END);
|
||||||
|
filelength = _mm_ftell(modreader);
|
||||||
|
_mm_fseek(modreader, pos, SEEK_SET);
|
||||||
|
|
||||||
/* try to read module header */
|
/* try to read module header */
|
||||||
_mm_read_string((CHAR *)mh->songname, 20, modreader);
|
_mm_read_string((CHAR *)mh->songname, 20, modreader);
|
||||||
|
@ -382,6 +416,11 @@ static int MOD_Load(int curious)
|
||||||
s->volume = _mm_read_UBYTE(modreader);
|
s->volume = _mm_read_UBYTE(modreader);
|
||||||
s->reppos = _mm_read_M_UWORD(modreader);
|
s->reppos = _mm_read_M_UWORD(modreader);
|
||||||
s->replen = _mm_read_M_UWORD(modreader);
|
s->replen = _mm_read_M_UWORD(modreader);
|
||||||
|
/* Mod's Grave .WOW files are converted from .669 and thus
|
||||||
|
do not have sample finetune or volume. */
|
||||||
|
samplelength += (ULONG)s->length << 1;
|
||||||
|
if (s->length && (s->finetune != 0x00 || s->volume != 0x40))
|
||||||
|
maybewow = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mh->songlength = _mm_read_UBYTE(modreader);
|
mh->songlength = _mm_read_UBYTE(modreader);
|
||||||
|
@ -394,6 +433,10 @@ static int MOD_Load(int curious)
|
||||||
_mm_read_UBYTES(mh->positions, 128, modreader);
|
_mm_read_UBYTES(mh->positions, 128, modreader);
|
||||||
_mm_read_UBYTES(mh->magic2, 4, modreader);
|
_mm_read_UBYTES(mh->magic2, 4, modreader);
|
||||||
|
|
||||||
|
/* Mod's Grave .WOW files always use 0x00 for the "restart" byte. */
|
||||||
|
if (mh->magic1 != 0x00)
|
||||||
|
maybewow = 0;
|
||||||
|
|
||||||
if (_mm_eof(modreader)) {
|
if (_mm_eof(modreader)) {
|
||||||
_mm_errno = MMERR_LOADING_HEADER;
|
_mm_errno = MMERR_LOADING_HEADER;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -406,6 +449,12 @@ static int MOD_Load(int curious)
|
||||||
_mm_errno = MMERR_NOT_A_MODULE;
|
_mm_errno = MMERR_NOT_A_MODULE;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (descr == digitaltracker) {
|
||||||
|
/* Digital Tracker FA0x modules add four extra bytes after the
|
||||||
|
* magic. These don't seem to have ever been used for their
|
||||||
|
* intended purpose (rows per pattern and sample bits/rate). */
|
||||||
|
_mm_read_M_ULONG(modreader);
|
||||||
|
}
|
||||||
if (trekker && of.numchn == 8)
|
if (trekker && of.numchn == 8)
|
||||||
for (t = 0; t < 128; t++)
|
for (t = 0; t < 128; t++)
|
||||||
/* if module pretends to be FLT8, yet the order table
|
/* if module pretends to be FLT8, yet the order table
|
||||||
|
@ -443,6 +492,24 @@ static int MOD_Load(int curious)
|
||||||
of.numpos = t + 1;
|
of.numpos = t + 1;
|
||||||
}
|
}
|
||||||
of.numpat++;
|
of.numpat++;
|
||||||
|
|
||||||
|
/* Mod's Grave .WOW files have an M.K. signature but they're actually 8 channel.
|
||||||
|
The only way to distinguish them from a 4-channel M.K. file is to check the
|
||||||
|
length of the .MOD against the expected length of a .WOW file with the same
|
||||||
|
number of patterns as this file. To make things harder, Mod's Grave occasionally
|
||||||
|
adds an extra byte to .WOW files and sometimes .MOD authors pad their files.
|
||||||
|
Prior checks for WOW behavior should help eliminate false positives here.
|
||||||
|
|
||||||
|
Also note the length check relies on counting samples with a length word=1 to work. */
|
||||||
|
if (modtype == 0 && maybewow == 1) {
|
||||||
|
ULONG wowlength = MODULEHEADERSIZE + 4 + samplelength + of.numpat * (64 * 4 * 8);
|
||||||
|
if ((filelength & ~1) == wowlength) {
|
||||||
|
modtype = 1;
|
||||||
|
descr = modsgrave;
|
||||||
|
of.numchn = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
of.numtrk = of.numpat * of.numchn;
|
of.numtrk = of.numpat * of.numchn;
|
||||||
|
|
||||||
if (!AllocPositions(of.numpos))
|
if (!AllocPositions(of.numpos))
|
||||||
|
@ -450,12 +517,16 @@ static int MOD_Load(int curious)
|
||||||
for (t = 0; t < of.numpos; t++)
|
for (t = 0; t < of.numpos; t++)
|
||||||
of.positions[t] = mh->positions[t];
|
of.positions[t] = mh->positions[t];
|
||||||
|
|
||||||
|
if (!ML_LoadPatterns())
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Finally, init the sampleinfo structures */
|
/* Finally, init the sampleinfo structures */
|
||||||
of.numins = of.numsmp = 31;
|
of.numins = of.numsmp = 31;
|
||||||
if (!AllocSamples())
|
if (!AllocSamples())
|
||||||
return 0;
|
return 0;
|
||||||
s = mh->samples;
|
s = mh->samples;
|
||||||
q = of.samples;
|
q = of.samples;
|
||||||
|
pos = _mm_ftell(modreader);
|
||||||
for (t = 0; t < of.numins; t++) {
|
for (t = 0; t < of.numins; t++) {
|
||||||
/* convert the samplename */
|
/* convert the samplename */
|
||||||
q->samplename = DupStr(s->samplename, 23, 1);
|
q->samplename = DupStr(s->samplename, 23, 1);
|
||||||
|
@ -474,15 +545,28 @@ static int MOD_Load(int curious)
|
||||||
if (s->replen > 2)
|
if (s->replen > 2)
|
||||||
q->flags |= SF_LOOP;
|
q->flags |= SF_LOOP;
|
||||||
|
|
||||||
|
q->seekpos = pos;
|
||||||
|
/* Test for MODPlugin ADPCM. These are indicated by "ADPCM"
|
||||||
|
* embedded at the start of each sample's data. :( */
|
||||||
|
memset(adpcm, 0, sizeof(adpcm));
|
||||||
|
_mm_read_UBYTES(adpcm, 5, modreader);
|
||||||
|
if (!memcmp(adpcm, "ADPCM", 5)) {
|
||||||
|
q->flags |= SF_ADPCM4;
|
||||||
|
q->seekpos += 5;
|
||||||
|
/* Stored half-length, plus a 16 byte table. */
|
||||||
|
pos += s->length + 16 + 5;
|
||||||
|
_mm_fseek(modreader, s->length + 16, SEEK_CUR);
|
||||||
|
} else {
|
||||||
|
pos += q->length;
|
||||||
|
_mm_fseek(modreader, q->length - 5, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
s++;
|
s++;
|
||||||
q++;
|
q++;
|
||||||
}
|
}
|
||||||
|
|
||||||
of.modtype = MikMod_strdup(descr);
|
of.modtype = MikMod_strdup(descr);
|
||||||
|
|
||||||
if (!ML_LoadPatterns())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -403,6 +403,7 @@ static int S3M_Load(int curious)
|
||||||
if(s.flags&1) q->flags |= SF_LOOP;
|
if(s.flags&1) q->flags |= SF_LOOP;
|
||||||
if(s.flags&4) q->flags |= SF_16BITS;
|
if(s.flags&4) q->flags |= SF_16BITS;
|
||||||
if(mh->fileformat==1) q->flags |= SF_SIGNED;
|
if(mh->fileformat==1) q->flags |= SF_SIGNED;
|
||||||
|
if(s.pack==4) q->flags |= SF_ADPCM4 | SF_SIGNED; /* MODPlugin ADPCM4. */
|
||||||
|
|
||||||
/* don't load sample if it doesn't have the SCRS tag */
|
/* don't load sample if it doesn't have the SCRS tag */
|
||||||
if(memcmp(s.scrs,"SCRS",4)) q->length = 0;
|
if(memcmp(s.scrs,"SCRS",4)) q->length = 0;
|
||||||
|
|
|
@ -225,7 +225,7 @@ static UBYTE *STM_ConvertTrack(STMNOTE *n)
|
||||||
return UniDup();
|
return UniDup();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int STM_LoadPatterns(void)
|
static int STM_LoadPatterns(unsigned int pattoload)
|
||||||
{
|
{
|
||||||
unsigned int t,s,tracks=0;
|
unsigned int t,s,tracks=0;
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ static int STM_LoadPatterns(void)
|
||||||
if(!AllocTracks()) return 0;
|
if(!AllocTracks()) return 0;
|
||||||
|
|
||||||
/* Allocate temporary buffer for loading and converting the patterns */
|
/* Allocate temporary buffer for loading and converting the patterns */
|
||||||
for(t=0;t<of.numpat;t++) {
|
for(t=0;t<pattoload;t++) {
|
||||||
for(s=0;s<(64U*of.numchn);s++) {
|
for(s=0;s<(64U*of.numchn);s++) {
|
||||||
stmbuf[s].note = _mm_read_UBYTE(modreader);
|
stmbuf[s].note = _mm_read_UBYTE(modreader);
|
||||||
stmbuf[s].insvol = _mm_read_UBYTE(modreader);
|
stmbuf[s].insvol = _mm_read_UBYTE(modreader);
|
||||||
|
@ -254,11 +254,13 @@ static int STM_LoadPatterns(void)
|
||||||
|
|
||||||
static int STM_Load(int curious)
|
static int STM_Load(int curious)
|
||||||
{
|
{
|
||||||
|
int blankpattern=0;
|
||||||
|
int pattoload;
|
||||||
int t;
|
int t;
|
||||||
ULONG MikMod_ISA; /* We must generate our own ISA, it's not stored in stm */
|
ULONG samplestart;
|
||||||
|
ULONG sampleend;
|
||||||
SAMPLE *q;
|
SAMPLE *q;
|
||||||
(void)curious;
|
(void)curious;
|
||||||
|
|
||||||
/* try to read stm header */
|
/* try to read stm header */
|
||||||
_mm_read_string(mh->songname,20,modreader);
|
_mm_read_string(mh->songname,20,modreader);
|
||||||
_mm_read_string(mh->trackername,8,modreader);
|
_mm_read_string(mh->trackername,8,modreader);
|
||||||
|
@ -318,22 +320,38 @@ static int STM_Load(int curious)
|
||||||
t=0;
|
t=0;
|
||||||
if(!AllocPositions(0x80)) return 0;
|
if(!AllocPositions(0x80)) return 0;
|
||||||
/* 99 terminates the patorder list */
|
/* 99 terminates the patorder list */
|
||||||
while((mh->patorder[t]<=99)&&(mh->patorder[t]<mh->numpat)) {
|
while(mh->patorder[t]<99) {
|
||||||
of.positions[t]=mh->patorder[t];
|
of.positions[t]=mh->patorder[t];
|
||||||
|
|
||||||
|
/* Screamtracker 2 treaks patterns >= numpat as blank patterns.
|
||||||
|
* Example modules: jimmy.stm, Rauno/dogs.stm, Skaven/hevijanis istu maas.stm.
|
||||||
|
*
|
||||||
|
* Patterns>=64 have unpredictable behavior in Screamtracker 2,
|
||||||
|
* but nothing seems to rely on them, so they're OK to blank too.
|
||||||
|
*/
|
||||||
|
if(of.positions[t]>=mh->numpat) {
|
||||||
|
of.positions[t]=mh->numpat;
|
||||||
|
blankpattern=1;
|
||||||
|
}
|
||||||
|
|
||||||
if(++t == 0x80) {
|
if(++t == 0x80) {
|
||||||
_mm_errno = MMERR_NOT_A_MODULE;
|
_mm_errno = MMERR_NOT_A_MODULE;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(mh->patorder[t]<=99) t++;
|
/* Allocate an extra blank pattern if the module references one. */
|
||||||
|
pattoload=of.numpat;
|
||||||
|
if(blankpattern) of.numpat++;
|
||||||
of.numpos=t;
|
of.numpos=t;
|
||||||
of.numtrk=of.numpat*of.numchn;
|
of.numtrk=of.numpat*of.numchn;
|
||||||
of.numins=of.numsmp=31;
|
of.numins=of.numsmp=31;
|
||||||
|
|
||||||
if(!AllocSamples()) return 0;
|
if(!AllocSamples()) return 0;
|
||||||
if(!STM_LoadPatterns()) return 0;
|
if(!STM_LoadPatterns(pattoload)) return 0;
|
||||||
MikMod_ISA=_mm_ftell(modreader);
|
|
||||||
MikMod_ISA=(MikMod_ISA+15)&0xfffffff0; /* normalize */
|
samplestart=_mm_ftell(modreader);
|
||||||
|
_mm_fseek(modreader,0,SEEK_END);
|
||||||
|
sampleend=_mm_ftell(modreader);
|
||||||
|
|
||||||
for(q=of.samples,t=0;t<of.numsmp;t++,q++) {
|
for(q=of.samples,t=0;t<of.numsmp;t++,q++) {
|
||||||
/* load sample info */
|
/* load sample info */
|
||||||
|
@ -341,19 +359,46 @@ static int STM_Load(int curious)
|
||||||
q->speed = (mh->sample[t].c2spd * 8363) / 8448;
|
q->speed = (mh->sample[t].c2spd * 8363) / 8448;
|
||||||
q->volume = mh->sample[t].volume;
|
q->volume = mh->sample[t].volume;
|
||||||
q->length = mh->sample[t].length;
|
q->length = mh->sample[t].length;
|
||||||
if (/*!mh->sample[t].volume || */q->length==1) q->length=0;
|
if (!mh->sample[t].volume || q->length==1) q->length=0;
|
||||||
q->loopstart = mh->sample[t].loopbeg;
|
q->loopstart = mh->sample[t].loopbeg;
|
||||||
q->loopend = mh->sample[t].loopend;
|
q->loopend = mh->sample[t].loopend;
|
||||||
q->seekpos = MikMod_ISA;
|
q->seekpos = mh->sample[t].reserved << 4;
|
||||||
|
|
||||||
MikMod_ISA+=q->length;
|
/* Sanity checks to make sure samples are bounded within the file. */
|
||||||
MikMod_ISA=(MikMod_ISA+15)&0xfffffff0; /* normalize */
|
if(q->length) {
|
||||||
|
if(q->seekpos<samplestart) {
|
||||||
|
#ifdef MIKMOD_DEBUG
|
||||||
|
fprintf(stderr,"rejected sample # %d (seekpos=%u < samplestart=%u)\n",t,q->seekpos,samplestart);
|
||||||
|
#endif
|
||||||
|
_mm_errno = MMERR_LOADING_SAMPLEINFO;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Some .STMs seem to rely on allowing truncated samples... */
|
||||||
|
if(q->seekpos>=sampleend) {
|
||||||
|
#ifdef MIKMOD_DEBUG
|
||||||
|
fprintf(stderr,"truncating sample # %d from length %u to 0\n",t,q->length);
|
||||||
|
#endif
|
||||||
|
q->seekpos = q->length = 0;
|
||||||
|
} else if(q->seekpos+q->length>sampleend) {
|
||||||
|
#ifdef MIKMOD_DEBUG
|
||||||
|
fprintf(stderr,"truncating sample # %d from length %u to %u\n",t,q->length,sampleend - q->seekpos);
|
||||||
|
#endif
|
||||||
|
q->length = sampleend - q->seekpos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
q->seekpos = 0;
|
||||||
|
|
||||||
/* contrary to the STM specs, sample data is signed */
|
/* contrary to the STM specs, sample data is signed */
|
||||||
q->flags = SF_SIGNED;
|
q->flags = SF_SIGNED;
|
||||||
|
|
||||||
if(q->loopend && q->loopend != 0xffff)
|
if(q->loopend && q->loopend != 0xffff && q->loopstart < q->length) {
|
||||||
q->flags|=SF_LOOP;
|
q->flags|=SF_LOOP;
|
||||||
|
if (q->loopend > q->length)
|
||||||
|
q->loopend = q->length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
q->loopstart = q->loopend = 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,6 @@
|
||||||
|
|
||||||
/*==============================================================================
|
/*==============================================================================
|
||||||
|
|
||||||
$Id$
|
|
||||||
|
|
||||||
Ultratracker (ULT) module loader
|
Ultratracker (ULT) module loader
|
||||||
|
|
||||||
==============================================================================*/
|
==============================================================================*/
|
||||||
|
@ -183,17 +181,19 @@ static int ULT_Load(int curious)
|
||||||
}
|
}
|
||||||
|
|
||||||
q->samplename=DupStr(s.samplename,32,1);
|
q->samplename=DupStr(s.samplename,32,1);
|
||||||
/* The correct formula for the coefficient would be
|
/* The correct formula would be
|
||||||
pow(2,(double)s.finetume/OCTAVE/32768), but to avoid floating point
|
s.speed * pow(2, (double)s.finetune / (OCTAVE * 32768))
|
||||||
here, we'll use a first order approximation here.
|
but to avoid libm, we'll use a first order approximation.
|
||||||
1/567290 == Ln(2)/OCTAVE/32768 */
|
1/567290 == Ln(2)/OCTAVE/32768 */
|
||||||
q->speed=s.speed+s.speed*(((SLONG)s.speed*(SLONG)s.finetune)/567290);
|
if(!s.finetune) q->speed = s.speed;
|
||||||
|
else q->speed= s.speed*((double)s.finetune/567290.0 + 1.0);
|
||||||
q->length = s.sizeend-s.sizestart;
|
q->length = s.sizeend-s.sizestart;
|
||||||
q->volume = s.volume>>2;
|
q->volume = s.volume>>2;
|
||||||
q->loopstart = s.loopstart;
|
q->loopstart = s.loopstart;
|
||||||
q->loopend = s.loopend;
|
q->loopend = s.loopend;
|
||||||
q->flags = SF_SIGNED;
|
q->flags = SF_SIGNED;
|
||||||
if(s.flags&ULTS_LOOP) q->flags|=SF_LOOP;
|
if(s.flags&ULTS_LOOP) q->flags|=SF_LOOP;
|
||||||
|
else q->loopstart = q->loopend = 0;
|
||||||
if(s.flags&ULTS_16BITS) {
|
if(s.flags&ULTS_16BITS) {
|
||||||
s.sizeend+=(s.sizeend-s.sizestart);
|
s.sizeend+=(s.sizeend-s.sizestart);
|
||||||
s.sizestart<<=1;
|
s.sizestart<<=1;
|
||||||
|
@ -246,6 +246,11 @@ static int ULT_Load(int curious)
|
||||||
|
|
||||||
for(t=0;t<of.numtrk;t++) {
|
for(t=0;t<of.numtrk;t++) {
|
||||||
int rep,row=0;
|
int rep,row=0;
|
||||||
|
/* FIXME: unrolling continuous portamento is a HACK and needs to
|
||||||
|
* be replaced with a real continuous effect. This implementation
|
||||||
|
* breaks when tone portamento continues between patterns. See
|
||||||
|
* discussion in https://github.com/sezero/mikmod/pull/40 . */
|
||||||
|
int continuePortaToNote = 0;
|
||||||
|
|
||||||
UniReset();
|
UniReset();
|
||||||
while(row<64) {
|
while(row<64) {
|
||||||
|
@ -261,14 +266,22 @@ static int ULT_Load(int curious)
|
||||||
int offset;
|
int offset;
|
||||||
|
|
||||||
if(ev.sample) UniInstrument(ev.sample-1);
|
if(ev.sample) UniInstrument(ev.sample-1);
|
||||||
if(ev.note) UniNote(ev.note+2*OCTAVE-1);
|
if(ev.note) {
|
||||||
|
UniNote(ev.note+2*OCTAVE-1);
|
||||||
|
continuePortaToNote = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* first effect - various fixes by Alexander Kerkhove and
|
/* first effect - various fixes by Alexander Kerkhove and
|
||||||
Thomas Neumann */
|
Thomas Neumann */
|
||||||
eff = ev.eff>>4;
|
eff = ev.eff>>4;
|
||||||
|
|
||||||
|
if (continuePortaToNote && (eff != 0x3) && ((ev.eff & 0xf) != 0x3))
|
||||||
|
UniEffect(UNI_ITEFFECTG, 0);
|
||||||
|
|
||||||
switch(eff) {
|
switch(eff) {
|
||||||
case 0x3: /* tone portamento */
|
case 0x3: /* tone portamento */
|
||||||
UniEffect(UNI_ITEFFECTG,ev.dat2);
|
UniEffect(UNI_ITEFFECTG,ev.dat2);
|
||||||
|
continuePortaToNote = 1;
|
||||||
break;
|
break;
|
||||||
case 0x5:
|
case 0x5:
|
||||||
break;
|
break;
|
||||||
|
@ -293,6 +306,7 @@ static int ULT_Load(int curious)
|
||||||
switch(eff) {
|
switch(eff) {
|
||||||
case 0x3: /* tone portamento */
|
case 0x3: /* tone portamento */
|
||||||
UniEffect(UNI_ITEFFECTG,ev.dat1);
|
UniEffect(UNI_ITEFFECTG,ev.dat1);
|
||||||
|
continuePortaToNote = 1;
|
||||||
break;
|
break;
|
||||||
case 0x5:
|
case 0x5:
|
||||||
break;
|
break;
|
||||||
|
@ -344,5 +358,4 @@ MIKMODAPI MLOADER load_ult={
|
||||||
ULT_LoadTitle
|
ULT_LoadTitle
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* ex:set ts=4: */
|
/* ex:set ts=4: */
|
||||||
|
|
|
@ -29,12 +29,7 @@
|
||||||
*
|
*
|
||||||
* UPKG parsing partially based on Unreal Media Ripper (UMR) v0.3
|
* UPKG parsing partially based on Unreal Media Ripper (UMR) v0.3
|
||||||
* by Andy Ward <wardwh@swbell.net>, with additional updates
|
* by Andy Ward <wardwh@swbell.net>, with additional updates
|
||||||
* by O. Sezer - see git repo at https://github.com/sezero/umr/
|
* by O. Sezer - see git repo at https://github.com/sezero/umr.git
|
||||||
*
|
|
||||||
* The cheaper way, i.e. linear search of music object like libxmp
|
|
||||||
* and libmodplug does, is possible. With this however we're using
|
|
||||||
* the embedded offset, size and object type directly from the umx
|
|
||||||
* file, and I feel safer with it.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
|
@ -79,11 +74,10 @@ struct upkg_hdr {
|
||||||
ULONG guid[4];
|
ULONG guid[4];
|
||||||
SLONG generation_count;
|
SLONG generation_count;
|
||||||
#define UPKG_HDR_SIZE 64 /* 64 bytes up until here */
|
#define UPKG_HDR_SIZE 64 /* 64 bytes up until here */
|
||||||
/*struct _genhist *gen;*/
|
struct _genhist *gen;
|
||||||
};
|
};
|
||||||
/* compile time assert for upkg_hdr size */
|
/* compile time assert for upkg_hdr size */
|
||||||
/*typedef int _check_hdrsize[2 * (offsetof(struct upkg_hdr, gen) == UPKG_HDR_SIZE) - 1];*/
|
typedef int _check_hdrsize[2 * (offsetof(struct upkg_hdr, gen) == UPKG_HDR_SIZE) - 1];
|
||||||
typedef int _check_hdrsize[2 * (sizeof(struct upkg_hdr) == UPKG_HDR_SIZE) - 1];
|
|
||||||
|
|
||||||
/*========== Supported content types */
|
/*========== Supported content types */
|
||||||
|
|
||||||
|
@ -145,6 +139,7 @@ static int get_objtype (SLONG ofs, int type)
|
||||||
{
|
{
|
||||||
char sig[16];
|
char sig[16];
|
||||||
_retry:
|
_retry:
|
||||||
|
memset(sig, 0, sizeof(sig));
|
||||||
_mm_fseek(modreader, ofs, SEEK_SET);
|
_mm_fseek(modreader, ofs, SEEK_SET);
|
||||||
_mm_read_UBYTES(sig, 16, modreader);
|
_mm_read_UBYTES(sig, 16, modreader);
|
||||||
if (type == UMUSIC_IT) {
|
if (type == UMUSIC_IT) {
|
||||||
|
@ -207,20 +202,21 @@ static int read_export (const struct upkg_hdr *hdr,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_typname(const struct upkg_hdr *hdr,
|
static int read_typname(const struct upkg_hdr *hdr,
|
||||||
int idx, char *out)
|
int idx, char *out, long end)
|
||||||
{
|
{
|
||||||
int i, s;
|
int i, s;
|
||||||
long l;
|
long l;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
|
||||||
if (idx >= hdr->name_count) return -1;
|
if (idx >= hdr->name_count) return -1;
|
||||||
buf[63] = '\0';
|
memset(buf, 0, 64);
|
||||||
for (i = 0, l = 0; i <= idx; i++) {
|
for (i = 0, l = 0; i <= idx; i++) {
|
||||||
|
if (hdr->name_offset + l >= end) return -1;
|
||||||
_mm_fseek(modreader, hdr->name_offset + l, SEEK_SET);
|
_mm_fseek(modreader, hdr->name_offset + l, SEEK_SET);
|
||||||
_mm_read_UBYTES(buf, 63, modreader);
|
_mm_read_UBYTES(buf, 63, modreader);
|
||||||
if (hdr->file_version >= 64) {
|
if (hdr->file_version >= 64) {
|
||||||
s = *(signed char *)buf; /* numchars *including* terminator */
|
s = *(signed char *)buf; /* numchars *including* terminator */
|
||||||
if (s <= 0 || s > 64) return -1;
|
if (s <= 0) return -1;
|
||||||
l += s + 5; /* 1 for buf[0], 4 for int32_t name_flags */
|
l += s + 5; /* 1 for buf[0], 4 for int32_t name_flags */
|
||||||
} else {
|
} else {
|
||||||
l += (long)strlen(buf);
|
l += (long)strlen(buf);
|
||||||
|
@ -244,6 +240,12 @@ static int probe_umx (const struct upkg_hdr *hdr,
|
||||||
_mm_fseek(modreader, 0, SEEK_END);
|
_mm_fseek(modreader, 0, SEEK_END);
|
||||||
fsiz = _mm_ftell(modreader);
|
fsiz = _mm_ftell(modreader);
|
||||||
|
|
||||||
|
if (hdr->name_offset >= fsiz ||
|
||||||
|
hdr->export_offset >= fsiz ||
|
||||||
|
hdr->import_offset >= fsiz) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Find the offset and size of the first IT, S3M or XM
|
/* Find the offset and size of the first IT, S3M or XM
|
||||||
* by parsing the exports table. The umx files should
|
* by parsing the exports table. The umx files should
|
||||||
* have only one export. Kran32.umx from Unreal has two,
|
* have only one export. Kran32.umx from Unreal has two,
|
||||||
|
@ -267,7 +269,7 @@ static int probe_umx (const struct upkg_hdr *hdr,
|
||||||
if ((t = read_export(hdr, &pos, &s)) < 0) return -1;
|
if ((t = read_export(hdr, &pos, &s)) < 0) return -1;
|
||||||
if (s <= 0 || s > fsiz - pos) return -1;
|
if (s <= 0 || s > fsiz - pos) return -1;
|
||||||
|
|
||||||
if (read_typname(hdr, t, buf) < 0) return -1;
|
if (read_typname(hdr, t, buf, fsiz) < 0) return -1;
|
||||||
for (i = 0; mustype[i] != NULL; i++) {
|
for (i = 0; mustype[i] != NULL; i++) {
|
||||||
if (!strcasecmp(buf, mustype[i])) {
|
if (!strcasecmp(buf, mustype[i])) {
|
||||||
t = i;
|
t = i;
|
||||||
|
@ -282,33 +284,34 @@ static int probe_umx (const struct upkg_hdr *hdr,
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SLONG probe_header (void *header)
|
static SLONG probe_header (struct upkg_hdr *hdr)
|
||||||
{
|
{
|
||||||
struct upkg_hdr *hdr;
|
hdr->tag = _mm_read_I_ULONG(modreader);
|
||||||
unsigned char *p;
|
hdr->file_version = _mm_read_I_SLONG(modreader);
|
||||||
ULONG *swp;
|
hdr->pkg_flags = _mm_read_I_ULONG(modreader);
|
||||||
int i;
|
hdr->name_count = _mm_read_I_SLONG(modreader);
|
||||||
|
hdr->name_offset = _mm_read_I_SLONG(modreader);
|
||||||
|
hdr->export_count = _mm_read_I_SLONG(modreader);
|
||||||
|
hdr->export_offset = _mm_read_I_SLONG(modreader);
|
||||||
|
hdr->import_count = _mm_read_I_SLONG(modreader);
|
||||||
|
hdr->import_offset = _mm_read_I_SLONG(modreader);
|
||||||
|
|
||||||
/* byte swap the header - all members are 32 bit LE values */
|
if (_mm_eof(modreader)) return -1;
|
||||||
p = (unsigned char *) header;
|
|
||||||
swp = (ULONG *) header;
|
|
||||||
for (i = 0; i < UPKG_HDR_SIZE/4; i++, p += 4) {
|
|
||||||
swp[i] = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
hdr = (struct upkg_hdr *) header;
|
|
||||||
if (hdr->tag != UPKG_HDR_TAG) {
|
if (hdr->tag != UPKG_HDR_TAG) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (hdr->name_count < 0 ||
|
if (hdr->name_count < 0 ||
|
||||||
hdr->name_offset < 0 ||
|
|
||||||
hdr->export_count < 0 ||
|
hdr->export_count < 0 ||
|
||||||
hdr->export_offset < 0 ||
|
|
||||||
hdr->import_count < 0 ||
|
hdr->import_count < 0 ||
|
||||||
hdr->import_offset < 0 ) {
|
hdr->name_offset < 36 ||
|
||||||
|
hdr->export_offset < 36 ||
|
||||||
|
hdr->import_offset < 36 ) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 1 /* no need being overzealous */
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
switch (hdr->file_version) {
|
switch (hdr->file_version) {
|
||||||
case 35: case 37: /* Unreal beta - */
|
case 35: case 37: /* Unreal beta - */
|
||||||
case 40: case 41: /* 1998 */
|
case 40: case 41: /* 1998 */
|
||||||
|
@ -324,30 +327,20 @@ static SLONG probe_header (void *header)
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
#endif /* #if 0 */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_upkg (SLONG *ofs, SLONG *objsize)
|
static int process_upkg (SLONG *ofs, SLONG *objsize)
|
||||||
{
|
{
|
||||||
char header[UPKG_HDR_SIZE];
|
struct upkg_hdr header;
|
||||||
|
|
||||||
if (!_mm_read_UBYTES(header, UPKG_HDR_SIZE, modreader))
|
memset(&header, 0, sizeof(header));
|
||||||
return -1;
|
if (probe_header(&header) < 0)
|
||||||
if (probe_header(header) < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return probe_umx((struct upkg_hdr *)header, ofs, objsize);
|
return probe_umx(&header, ofs, objsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*========== Loader vars */
|
|
||||||
|
|
||||||
typedef struct _umx_info {
|
|
||||||
int type;
|
|
||||||
SLONG ofs, size;
|
|
||||||
MLOADER* loader;
|
|
||||||
} umx_info;
|
|
||||||
|
|
||||||
static umx_info *umx_data = NULL;
|
|
||||||
|
|
||||||
/*========== Loader code */
|
/*========== Loader code */
|
||||||
|
|
||||||
/* Without Test() being called first, Load[Title] is never called.
|
/* Without Test() being called first, Load[Title] is never called.
|
||||||
|
@ -359,15 +352,23 @@ static umx_info *umx_data = NULL;
|
||||||
* and always clear it when returning from LoadTitle() or Cleanup().
|
* and always clear it when returning from LoadTitle() or Cleanup().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
typedef struct _umx_info {
|
||||||
|
int type;
|
||||||
|
SLONG ofs, size;
|
||||||
|
MLOADER* loader;
|
||||||
|
} umx_info;
|
||||||
|
|
||||||
|
static umx_info *umx_data = NULL;
|
||||||
|
|
||||||
static int UMX_Test(void)
|
static int UMX_Test(void)
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
SLONG ofs = 0, size = 0;
|
SLONG ofs = 0, size = 0;
|
||||||
|
|
||||||
if (umx_data) {
|
if (umx_data) {
|
||||||
#ifdef MIKMOD_DEBUG
|
#ifdef MIKMOD_DEBUG
|
||||||
fprintf(stderr, "UMX_Test called while a previous instance is active\n");
|
fprintf(stderr, "UMX_Test called while a previous instance is active\n");
|
||||||
#endif
|
#endif
|
||||||
MikMod_free(umx_data);
|
MikMod_free(umx_data);
|
||||||
umx_data = NULL;
|
umx_data = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,7 +201,7 @@ static UBYTE* readtrack(void)
|
||||||
opcode++;
|
opcode++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((!opcode)||(opcode>=UNI_LAST)) {
|
if((!opcode)||(opcode>=UNI_FORMAT_LAST)) {
|
||||||
MikMod_free(t);
|
MikMod_free(t);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -477,14 +477,23 @@ static int loadsmp5(void)
|
||||||
|
|
||||||
/* convert flags */
|
/* convert flags */
|
||||||
q->flags=0;
|
q->flags=0;
|
||||||
if(s->flags&128) q->flags|=SF_REVERSE;
|
if (universion < 5) {
|
||||||
if(s->flags& 64) q->flags|=SF_SUSTAIN;
|
/* UN04 flags, as suggested by Thomas Neumann */
|
||||||
if(s->flags& 32) q->flags|=SF_BIDI;
|
if(s->flags& 64) q->flags|=SF_OWNPAN;
|
||||||
if(s->flags& 16) q->flags|=SF_LOOP;
|
if(s->flags& 32) q->flags|=SF_SIGNED;
|
||||||
if(s->flags& 8) q->flags|=SF_BIG_ENDIAN;
|
if(s->flags& 16) q->flags|=SF_BIDI;
|
||||||
if(s->flags& 4) q->flags|=SF_DELTA;
|
if(s->flags& 8) q->flags|=SF_LOOP;
|
||||||
if(s->flags& 2) q->flags|=SF_SIGNED;
|
if(s->flags& 4) q->flags|=SF_DELTA;
|
||||||
if(s->flags& 1) q->flags|=SF_16BITS;
|
} else {
|
||||||
|
if(s->flags&128) q->flags|=SF_REVERSE;
|
||||||
|
if(s->flags& 64) q->flags|=SF_OWNPAN;
|
||||||
|
if(s->flags& 32) q->flags|=SF_BIDI;
|
||||||
|
if(s->flags& 16) q->flags|=SF_LOOP;
|
||||||
|
if(s->flags& 8) q->flags|=SF_BIG_ENDIAN;
|
||||||
|
if(s->flags& 4) q->flags|=SF_DELTA;
|
||||||
|
if(s->flags& 2) q->flags|=SF_SIGNED;
|
||||||
|
if(s->flags& 1) q->flags|=SF_16BITS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d=of.instruments;s=wh;
|
d=of.instruments;s=wh;
|
||||||
|
@ -574,6 +583,8 @@ static int UNI_Load(int curious)
|
||||||
of.bpmlimit=32;
|
of.bpmlimit=32;
|
||||||
|
|
||||||
of.songname=readstring();
|
of.songname=readstring();
|
||||||
|
if(!of.songname)
|
||||||
|
of.songname=MikMod_strdup("");
|
||||||
if(universion<0x102)
|
if(universion<0x102)
|
||||||
oldtype=readstring();
|
oldtype=readstring();
|
||||||
if(oldtype) {
|
if(oldtype) {
|
||||||
|
@ -698,13 +709,16 @@ static CHAR *UNI_LoadTitle(void)
|
||||||
{
|
{
|
||||||
UBYTE ver;
|
UBYTE ver;
|
||||||
int posit[3]={304,306,26};
|
int posit[3]={304,306,26};
|
||||||
|
CHAR *title;
|
||||||
|
|
||||||
_mm_fseek(modreader,3,SEEK_SET);
|
_mm_fseek(modreader,3,SEEK_SET);
|
||||||
ver=_mm_read_UBYTE(modreader);
|
ver=_mm_read_UBYTE(modreader);
|
||||||
if(ver=='N') ver='6';
|
if(ver=='N') ver='6';
|
||||||
|
|
||||||
_mm_fseek(modreader,posit[ver-'4'],SEEK_SET);
|
_mm_fseek(modreader,posit[ver-'4'],SEEK_SET);
|
||||||
return readstring();
|
title=readstring();
|
||||||
|
if(!title) title=MikMod_strdup("");
|
||||||
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*========== Loader information */
|
/*========== Loader information */
|
||||||
|
|
|
@ -73,7 +73,8 @@ typedef struct XMINSTHEADER {
|
||||||
ULONG ssize;
|
ULONG ssize;
|
||||||
} XMINSTHEADER;
|
} XMINSTHEADER;
|
||||||
|
|
||||||
#define XMENVCNT (12*2)
|
#define XMENVPTS (12)
|
||||||
|
#define XMENVCNT (XMENVPTS*2)
|
||||||
#define XMNOTECNT (8*OCTAVE)
|
#define XMNOTECNT (8*OCTAVE)
|
||||||
typedef struct XMPATCHHEADER {
|
typedef struct XMPATCHHEADER {
|
||||||
UBYTE what[XMNOTECNT]; /* Sample number for all notes */
|
UBYTE what[XMNOTECNT]; /* Sample number for all notes */
|
||||||
|
@ -442,6 +443,12 @@ static void FixEnvelope(ENVPT *cur, int pts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for MOD plugin packed samples */
|
||||||
|
static int IsSamplePacked(void)
|
||||||
|
{
|
||||||
|
return (s->reserved == 0xad) && !(s->type & 0x30);
|
||||||
|
}
|
||||||
|
|
||||||
static int LoadInstruments(void)
|
static int LoadInstruments(void)
|
||||||
{
|
{
|
||||||
long filend,ck;
|
long filend,ck;
|
||||||
|
@ -513,10 +520,10 @@ static int LoadInstruments(void)
|
||||||
/* we can't trust the envelope point count here, as some
|
/* we can't trust the envelope point count here, as some
|
||||||
modules have incorrect values (K_OSPACE.XM reports 32 volume
|
modules have incorrect values (K_OSPACE.XM reports 32 volume
|
||||||
points, for example). */
|
points, for example). */
|
||||||
if(pth.volpts>XMENVCNT/2) pth.volpts=XMENVCNT/2;
|
if(pth.volpts>XMENVPTS) pth.volpts=XMENVPTS;
|
||||||
if(pth.panpts>XMENVCNT/2) pth.panpts=XMENVCNT/2;
|
if(pth.panpts>XMENVPTS) pth.panpts=XMENVPTS;
|
||||||
|
|
||||||
if((_mm_eof(modreader))||(pth.volpts>XMENVCNT/2)||(pth.panpts>XMENVCNT/2)) {
|
if(_mm_eof(modreader)) {
|
||||||
MikMod_free(nextwav);nextwav=NULL;
|
MikMod_free(nextwav);nextwav=NULL;
|
||||||
MikMod_free(wh);wh=NULL;
|
MikMod_free(wh);wh=NULL;
|
||||||
_mm_errno = MMERR_LOADING_SAMPLEINFO;
|
_mm_errno = MMERR_LOADING_SAMPLEINFO;
|
||||||
|
@ -529,7 +536,7 @@ static int LoadInstruments(void)
|
||||||
|
|
||||||
#if defined __STDC__ || defined _MSC_VER || defined __WATCOMC__ || defined MPW_C
|
#if defined __STDC__ || defined _MSC_VER || defined __WATCOMC__ || defined MPW_C
|
||||||
#define XM_ProcessEnvelope(name) \
|
#define XM_ProcessEnvelope(name) \
|
||||||
for (u = 0; u < (XMENVCNT >> 1); u++) { \
|
for (u = 0; u < XMENVPTS; u++) { \
|
||||||
d-> name##env[u].pos = pth. name##env[u << 1]; \
|
d-> name##env[u].pos = pth. name##env[u << 1]; \
|
||||||
d-> name##env[u].val = pth. name##env[(u << 1)+ 1]; \
|
d-> name##env[u].val = pth. name##env[(u << 1)+ 1]; \
|
||||||
} \
|
} \
|
||||||
|
@ -542,14 +549,14 @@ static int LoadInstruments(void)
|
||||||
d-> name##pts=pth. name##pts; \
|
d-> name##pts=pth. name##pts; \
|
||||||
\
|
\
|
||||||
/* scale envelope */ \
|
/* scale envelope */ \
|
||||||
for (p=0;p<XMENVCNT/2;p++) \
|
for (p = 0; p < XMENVPTS; p++) \
|
||||||
d-> name##env[p].val<<=2; \
|
d-> name##env[p].val<<=2; \
|
||||||
\
|
\
|
||||||
if ((d-> name##flg&EF_ON)&&(d-> name##pts<2)) \
|
if ((d-> name##flg&EF_ON)&&(d-> name##pts<2)) \
|
||||||
d-> name##flg&=~EF_ON
|
d-> name##flg&=~EF_ON
|
||||||
#else
|
#else
|
||||||
#define XM_ProcessEnvelope(name) \
|
#define XM_ProcessEnvelope(name) \
|
||||||
for (u = 0; u < (XMENVCNT >> 1); u++) { \
|
for (u = 0; u < XMENVPTS; u++) { \
|
||||||
d-> name/**/env[u].pos = pth. name/**/env[u << 1]; \
|
d-> name/**/env[u].pos = pth. name/**/env[u << 1]; \
|
||||||
d-> name/**/env[u].val = pth. name/**/env[(u << 1)+ 1]; \
|
d-> name/**/env[u].val = pth. name/**/env[(u << 1)+ 1]; \
|
||||||
} \
|
} \
|
||||||
|
@ -563,7 +570,7 @@ static int LoadInstruments(void)
|
||||||
d-> name/**/pts=pth. name/**/pts; \
|
d-> name/**/pts=pth. name/**/pts; \
|
||||||
\
|
\
|
||||||
/* scale envelope */ \
|
/* scale envelope */ \
|
||||||
for (p=0;p<XMENVCNT/2;p++) \
|
for (p = 0; p < XMENVPTS; p++) \
|
||||||
d-> name/**/env[p].val<<=2; \
|
d-> name/**/env[p].val<<=2; \
|
||||||
\
|
\
|
||||||
if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \
|
if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \
|
||||||
|
@ -625,7 +632,11 @@ static int LoadInstruments(void)
|
||||||
_mm_read_string(s->samplename, 22, modreader);
|
_mm_read_string(s->samplename, 22, modreader);
|
||||||
|
|
||||||
nextwav[of.numsmp+u]=next;
|
nextwav[of.numsmp+u]=next;
|
||||||
next+=s->length;
|
|
||||||
|
if(IsSamplePacked())
|
||||||
|
next+=((s->length + 1) >> 1) + 16;
|
||||||
|
else
|
||||||
|
next+=s->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mh->version>0x0103) {
|
if(mh->version>0x0103) {
|
||||||
|
@ -793,6 +804,11 @@ static int XM_Load(int curious)
|
||||||
if(s->type&0x3) q->flags|=SF_LOOP;
|
if(s->type&0x3) q->flags|=SF_LOOP;
|
||||||
if(s->type&0x2) q->flags|=SF_BIDI;
|
if(s->type&0x2) q->flags|=SF_BIDI;
|
||||||
if(s->type&0x10) q->flags|=SF_16BITS;
|
if(s->type&0x10) q->flags|=SF_16BITS;
|
||||||
|
|
||||||
|
if(IsSamplePacked()) {
|
||||||
|
q->flags &= ~SF_DELTA;
|
||||||
|
q->flags |= SF_ADPCM4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d=of.instruments;
|
d=of.instruments;
|
||||||
|
|
|
@ -187,7 +187,7 @@ MIKMODAPI CHAR* MikMod_InfoDriver(void)
|
||||||
MUTEX_LOCK(lists);
|
MUTEX_LOCK(lists);
|
||||||
/* compute size of buffer */
|
/* compute size of buffer */
|
||||||
for(l = firstdriver; l; l = l->next)
|
for(l = firstdriver; l; l = l->next)
|
||||||
len += 4 + (l->next ? 1 : 0) + strlen(l->Version);
|
len += 4 + 1 + strlen(l->Version);
|
||||||
|
|
||||||
if(len)
|
if(len)
|
||||||
if((list=(CHAR*)MikMod_malloc(len*sizeof(CHAR))) != NULL) {
|
if((list=(CHAR*)MikMod_malloc(len*sizeof(CHAR))) != NULL) {
|
||||||
|
@ -195,7 +195,8 @@ MIKMODAPI CHAR* MikMod_InfoDriver(void)
|
||||||
list[0] = 0;
|
list[0] = 0;
|
||||||
/* list all registered device drivers : */
|
/* list all registered device drivers : */
|
||||||
for(t = 1, l = firstdriver; l; l = l->next, t++) {
|
for(t = 1, l = firstdriver; l; l = l->next, t++) {
|
||||||
list_end += sprintf(list_end, "%2d %s%s", t, l->Version, (l->next)? "\n" : "");
|
list_end += sprintf(list_end, "%2d %s\n", t, l->Version);
|
||||||
|
if (!l->next) list_end[-1] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MUTEX_UNLOCK(lists);
|
MUTEX_UNLOCK(lists);
|
||||||
|
|
|
@ -45,6 +45,7 @@ static int curfile = 0, direction = DIR_NEXT, entries = 0;
|
||||||
/* list of the mod files */
|
/* list of the mod files */
|
||||||
static char **file_pt;
|
static char **file_pt;
|
||||||
|
|
||||||
|
static int inited = 0;
|
||||||
|
|
||||||
/* The MP3 audio buffer which we will use as heap memory */
|
/* The MP3 audio buffer which we will use as heap memory */
|
||||||
static unsigned char* audio_buffer;
|
static unsigned char* audio_buffer;
|
||||||
|
@ -532,7 +533,7 @@ static void applysettings(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (md_mixfreq != rb->hw_freq_sampr[settings.sample_rate]) {
|
if (inited && (md_mixfreq != rb->hw_freq_sampr[settings.sample_rate])) {
|
||||||
md_mixfreq = rb->hw_freq_sampr[settings.sample_rate];
|
md_mixfreq = rb->hw_freq_sampr[settings.sample_rate];
|
||||||
// MikMod_Reset(""); BROKEN!
|
// MikMod_Reset(""); BROKEN!
|
||||||
rb->pcm_play_stop();
|
rb->pcm_play_stop();
|
||||||
|
@ -993,6 +994,8 @@ enum plugin_status plugin_start(const void* parameter)
|
||||||
return PLUGIN_ERROR;
|
return PLUGIN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inited = 1;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
retval = playfile(np_file);
|
retval = playfile(np_file);
|
||||||
|
|
|
@ -41,7 +41,7 @@ extern "C" {
|
||||||
*
|
*
|
||||||
* ========== NOTE TO WINDOWS DEVELOPERS:
|
* ========== NOTE TO WINDOWS DEVELOPERS:
|
||||||
* If you are compiling for Windows and will link to the static library
|
* If you are compiling for Windows and will link to the static library
|
||||||
* (libmikmod.a with MinGW, or mikmod_static.lib with MSVC or LCC, etc),
|
* (libmikmod.a with MinGW, or mikmod_static.lib with MSVC, Watcom, ..),
|
||||||
* you must define MIKMOD_STATIC in your project. Otherwise, dllimport
|
* you must define MIKMOD_STATIC in your project. Otherwise, dllimport
|
||||||
* will be assumed.
|
* will be assumed.
|
||||||
*/
|
*/
|
||||||
|
@ -76,7 +76,7 @@ extern "C" {
|
||||||
|
|
||||||
#define LIBMIKMOD_VERSION_MAJOR 3L
|
#define LIBMIKMOD_VERSION_MAJOR 3L
|
||||||
#define LIBMIKMOD_VERSION_MINOR 3L
|
#define LIBMIKMOD_VERSION_MINOR 3L
|
||||||
#define LIBMIKMOD_REVISION 11L
|
#define LIBMIKMOD_REVISION 12L
|
||||||
|
|
||||||
#define LIBMIKMOD_VERSION \
|
#define LIBMIKMOD_VERSION \
|
||||||
((LIBMIKMOD_VERSION_MAJOR<<16)| \
|
((LIBMIKMOD_VERSION_MAJOR<<16)| \
|
||||||
|
@ -89,7 +89,7 @@ MIKMODAPI extern long MikMod_GetVersion(void);
|
||||||
* ========== Dependency platform headers
|
* ========== Dependency platform headers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32)||defined(__CYGWIN__)
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#endif
|
#endif
|
||||||
|
@ -136,10 +136,8 @@ typedef unsigned char UBYTE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* 2 bytes, signed and unsigned: */
|
/* 2 bytes, signed and unsigned: */
|
||||||
#if !(defined __LCC__ && defined _WIN32)
|
|
||||||
typedef signed short int SWORD;
|
typedef signed short int SWORD;
|
||||||
#endif
|
#if !defined(_MIKMOD_AMIGA)
|
||||||
#if !((defined __LCC__ && defined _WIN32) || defined(_MIKMOD_AMIGA))
|
|
||||||
typedef unsigned short int UWORD;
|
typedef unsigned short int UWORD;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -147,13 +145,13 @@ typedef unsigned short int UWORD;
|
||||||
#if defined(_LP64) || defined(__LP64__) || defined(__arch64__) || defined(__alpha) || defined(__x86_64) || defined(__powerpc64__)
|
#if defined(_LP64) || defined(__LP64__) || defined(__arch64__) || defined(__alpha) || defined(__x86_64) || defined(__powerpc64__)
|
||||||
/* 64 bit architectures: */
|
/* 64 bit architectures: */
|
||||||
typedef signed int SLONG;
|
typedef signed int SLONG;
|
||||||
#if !(defined(_WIN32) || defined(_MIKMOD_AMIGA))
|
#if !defined(_MIKMOD_AMIGA)
|
||||||
typedef unsigned int ULONG;
|
typedef unsigned int ULONG;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else /* 32 bit architectures: */
|
#else /* 32 bit architectures: */
|
||||||
typedef signed long int SLONG;
|
typedef signed long int SLONG;
|
||||||
#if !(defined(_MIKMOD_OS2) || defined(_MIKMOD_WIN32) || defined(_MIKMOD_AMIGA))
|
#if !(defined(_MIKMOD_OS2) || defined(_MIKMOD_AMIGA))
|
||||||
typedef unsigned long int ULONG;
|
typedef unsigned long int ULONG;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -254,14 +252,14 @@ enum {
|
||||||
MMERR_MAC_SPEED,
|
MMERR_MAC_SPEED,
|
||||||
MMERR_MAC_START,
|
MMERR_MAC_START,
|
||||||
|
|
||||||
MMERR_OSX_UNKNOWN_DEVICE,
|
MMERR_OSX_UNKNOWN_DEVICE, /* obsolete */
|
||||||
MMERR_OSX_BAD_PROPERTY,
|
MMERR_OSX_BAD_PROPERTY, /* obsolete */
|
||||||
MMERR_OSX_UNSUPPORTED_FORMAT,
|
MMERR_OSX_UNSUPPORTED_FORMAT,
|
||||||
MMERR_OSX_SET_STEREO,
|
MMERR_OSX_SET_STEREO, /* obsolete */
|
||||||
MMERR_OSX_BUFFER_ALLOC,
|
MMERR_OSX_BUFFER_ALLOC, /* obsolete */
|
||||||
MMERR_OSX_ADD_IO_PROC,
|
MMERR_OSX_ADD_IO_PROC, /* obsolete */
|
||||||
MMERR_OSX_DEVICE_START,
|
MMERR_OSX_DEVICE_START,
|
||||||
MMERR_OSX_PTHREAD,
|
MMERR_OSX_PTHREAD, /* obsolete */
|
||||||
|
|
||||||
MMERR_DOSWSS_STARTDMA,
|
MMERR_DOSWSS_STARTDMA,
|
||||||
MMERR_DOSSB_STARTDMA,
|
MMERR_DOSSB_STARTDMA,
|
||||||
|
@ -376,8 +374,9 @@ typedef struct MWRITER {
|
||||||
#define SF_BIG_ENDIAN 0x0008
|
#define SF_BIG_ENDIAN 0x0008
|
||||||
#define SF_DELTA 0x0010
|
#define SF_DELTA 0x0010
|
||||||
#define SF_ITPACKED 0x0020
|
#define SF_ITPACKED 0x0020
|
||||||
|
#define SF_ADPCM4 0x0040
|
||||||
|
|
||||||
#define SF_FORMATMASK 0x003F
|
#define SF_FORMATMASK 0x007F
|
||||||
|
|
||||||
/* General Playback flags */
|
/* General Playback flags */
|
||||||
|
|
||||||
|
@ -551,6 +550,7 @@ struct MP_VOICE;
|
||||||
#define UF_FT2QUIRKS 0x0200 /* emulate some FT2 replay quirks */
|
#define UF_FT2QUIRKS 0x0200 /* emulate some FT2 replay quirks */
|
||||||
#define UF_PANNING 0x0400 /* module uses panning effects or have
|
#define UF_PANNING 0x0400 /* module uses panning effects or have
|
||||||
non-tracker default initial panning */
|
non-tracker default initial panning */
|
||||||
|
#define UF_FARTEMPO 0x0800 /* Module uses Farandole tempo calculations */
|
||||||
|
|
||||||
typedef struct MODULE {
|
typedef struct MODULE {
|
||||||
/* general module information */
|
/* general module information */
|
||||||
|
|
|
@ -70,14 +70,11 @@ typedef long long SLONGLONG;
|
||||||
#endif
|
#endif
|
||||||
typedef int __s64_typetest [(sizeof(SLONGLONG)==8) * 2 - 1];
|
typedef int __s64_typetest [(sizeof(SLONGLONG)==8) * 2 - 1];
|
||||||
|
|
||||||
/* pointer-sized signed int (ssize_t/intptr_t) : */
|
/* signed size type (ssize_t) */
|
||||||
#if defined(_WIN64) /* win64 is LLP64, not LP64 */
|
#if !defined(_WIN32) /* Win32 SDK has SSIZE_T */
|
||||||
typedef long long SINTPTR_T;
|
typedef long SSIZE_T;
|
||||||
#else
|
|
||||||
/* long should be pointer-sized for all others : */
|
|
||||||
typedef long SINTPTR_T;
|
|
||||||
#endif
|
#endif
|
||||||
typedef int __iptr_typetest [(sizeof(SINTPTR_T)==sizeof(void*)) * 2 - 1];
|
typedef int __ssize_typetest [(sizeof(SSIZE_T)==sizeof(size_t)) * 2 - 1];
|
||||||
|
|
||||||
/*========== Error handling */
|
/*========== Error handling */
|
||||||
|
|
||||||
|
@ -106,7 +103,7 @@ extern MikMod_handler_t _mm_errorhandler;
|
||||||
if(_mm_mutex_##name)\
|
if(_mm_mutex_##name)\
|
||||||
DosReleaseMutexSem(_mm_mutex_##name)
|
DosReleaseMutexSem(_mm_mutex_##name)
|
||||||
|
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)||defined(__CYGWIN__)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#define DECLARE_MUTEX(name) \
|
#define DECLARE_MUTEX(name) \
|
||||||
extern HANDLE _mm_mutex_##name
|
extern HANDLE _mm_mutex_##name
|
||||||
|
@ -338,6 +335,35 @@ enum {
|
||||||
/* Oktalyzer effects */
|
/* Oktalyzer effects */
|
||||||
UNI_OKTARP, /* arpeggio */
|
UNI_OKTARP, /* arpeggio */
|
||||||
|
|
||||||
|
/* Last effect supported by old modules in the UNI format. */
|
||||||
|
UNI_FORMAT_LAST,
|
||||||
|
|
||||||
|
/* Scream Tracker effects */
|
||||||
|
UNI_S3MEFFECTH, /* vibrato */
|
||||||
|
/* Impulse Tracker effects */
|
||||||
|
UNI_ITEFFECTH_OLD, /* vibrato (old) */
|
||||||
|
UNI_ITEFFECTU_OLD, /* fine vibrato (old) */
|
||||||
|
/* GDM effects. */
|
||||||
|
UNI_GDMEFFECT4, /* vibrato */
|
||||||
|
UNI_GDMEFFECT7, /* tremolo */
|
||||||
|
UNI_GDMEFFECT14, /* fine vibrato */
|
||||||
|
/* OctaMED effects. */
|
||||||
|
UNI_MEDEFFECT_VIB, /* MED vibrato */
|
||||||
|
UNI_MEDEFFECT_FD, /* set pitch */
|
||||||
|
UNI_MEDEFFECT_16, /* loop */
|
||||||
|
UNI_MEDEFFECT_18, /* stop note */
|
||||||
|
UNI_MEDEFFECT_1E, /* pattern delay */
|
||||||
|
UNI_MEDEFFECT_1F, /* note delay and retrigger */
|
||||||
|
/* Farandole effects. */
|
||||||
|
UNI_FAREFFECT1, /* Porta up */
|
||||||
|
UNI_FAREFFECT2, /* Porta down */
|
||||||
|
UNI_FAREFFECT3, /* Porta to note */
|
||||||
|
UNI_FAREFFECT4, /* Retrigger */
|
||||||
|
UNI_FAREFFECT6, /* Vibrato */
|
||||||
|
UNI_FAREFFECTD, /* Fine tempo down */
|
||||||
|
UNI_FAREFFECTE, /* Fine tempo up */
|
||||||
|
UNI_FAREFFECTF, /* Set tempo */
|
||||||
|
|
||||||
UNI_LAST
|
UNI_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -503,6 +529,16 @@ typedef struct MP_CONTROL {
|
||||||
UBYTE s3mrtgspeed;/* last used retrig speed */
|
UBYTE s3mrtgspeed;/* last used retrig speed */
|
||||||
UBYTE s3mrtgslide;/* last used retrig slide */
|
UBYTE s3mrtgslide;/* last used retrig slide */
|
||||||
|
|
||||||
|
UBYTE fartoneportarunning; /* FAR tone porta (effect 3) is a little bit different than other effects. It should keep running when the effect has first started, even if it is not given on subsequently rows */
|
||||||
|
SLONG fartoneportaspeed; /* FAR tone porta increment value */
|
||||||
|
SLONG farcurrentvalue; /* Because we're using fixing points as speed and the current period is an integer, we need to store the current value here for next round */
|
||||||
|
UBYTE farretrigcount; /* Number of retrigs to do */
|
||||||
|
|
||||||
|
/* These variables are only stored on the first control instance and therefore used globally.
|
||||||
|
The reason they are stored here is to minimize the number of global variables. */
|
||||||
|
UBYTE farcurtempo; /* Farandole current speed */
|
||||||
|
SWORD fartempobend; /* Used by the Farandole fine tempo effects and store the current bend value */
|
||||||
|
|
||||||
UBYTE glissando; /* glissando (0 means off) */
|
UBYTE glissando; /* glissando (0 means off) */
|
||||||
UBYTE wavecontrol;
|
UBYTE wavecontrol;
|
||||||
|
|
||||||
|
@ -533,7 +569,8 @@ typedef struct MP_CONTROL {
|
||||||
SBYTE panbspd; /* "" speed */
|
SBYTE panbspd; /* "" speed */
|
||||||
UBYTE panbdepth; /* "" depth */
|
UBYTE panbdepth; /* "" depth */
|
||||||
|
|
||||||
UWORD newsamp; /* set to 1 upon a sample / inst change */
|
UBYTE newnote; /* set to 1 if the current row contains a note */
|
||||||
|
UBYTE newsamp; /* set to 1 upon a sample / inst change */
|
||||||
UBYTE voleffect; /* Volume Column Effect Memory as used by IT */
|
UBYTE voleffect; /* Volume Column Effect Memory as used by IT */
|
||||||
UBYTE voldata; /* Volume Column Data Memory */
|
UBYTE voldata; /* Volume Column Data Memory */
|
||||||
|
|
||||||
|
@ -748,7 +785,7 @@ extern MikMod_callback_t vc_callback;
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
# if defined(_MSC_VER)
|
# if defined(_MSC_VER)
|
||||||
# define IS_ALIGNED_16(ptr) (!((__int64)(ptr) & 15i64))
|
# define IS_ALIGNED_16(ptr) (!((__int64)(ptr) & 15i64))
|
||||||
# else /* GCC, LCC, .. */
|
# else /* GCC, etc. */
|
||||||
# define IS_ALIGNED_16(ptr) (!((long long)(ptr) & 15LL))
|
# define IS_ALIGNED_16(ptr) (!((long long)(ptr) & 15LL))
|
||||||
# endif
|
# endif
|
||||||
#else /* long cast should be OK for all else */
|
#else /* long cast should be OK for all else */
|
||||||
|
@ -860,7 +897,7 @@ void MikMod_afree(void *); /* frees if ptr != NULL */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else /* NO SIMD */
|
#else /* NO SIMD */
|
||||||
#define MikMod_amalloc MikMod_malloc
|
#define MikMod_amalloc(s) MikMod_calloc(1,(s))
|
||||||
#define MikMod_afree MikMod_free
|
#define MikMod_afree MikMod_free
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -115,18 +115,20 @@ MIKMODAPI void MikMod_RegisterLoader(struct MLOADER* ldr)
|
||||||
int ReadComment(UWORD len)
|
int ReadComment(UWORD len)
|
||||||
{
|
{
|
||||||
if(len) {
|
if(len) {
|
||||||
int i;
|
CHAR *ptr;
|
||||||
|
|
||||||
if(!(of.comment=(CHAR*)MikMod_malloc(len+1))) return 0;
|
of.comment=(CHAR*)MikMod_calloc(1,len+1);
|
||||||
|
if(!of.comment) return 0;
|
||||||
_mm_read_UBYTES(of.comment,len,modreader);
|
_mm_read_UBYTES(of.comment,len,modreader);
|
||||||
|
|
||||||
/* translate IT linefeeds */
|
/* translate IT linefeeds */
|
||||||
for(i=0;i<len;i++)
|
ptr=of.comment;
|
||||||
if(of.comment[i]=='\r') of.comment[i]='\n';
|
while(*ptr) {
|
||||||
|
if(*ptr=='\r') *ptr='\n';
|
||||||
of.comment[len]=0; /* just in case */
|
++ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(!of.comment[0]) {
|
if(of.comment && !of.comment[0]) {
|
||||||
MikMod_free(of.comment);
|
MikMod_free(of.comment);
|
||||||
of.comment=NULL;
|
of.comment=NULL;
|
||||||
}
|
}
|
||||||
|
@ -142,16 +144,17 @@ int ReadLinedComment(UWORD len,UWORD linelen)
|
||||||
if (!linelen) return 0;
|
if (!linelen) return 0;
|
||||||
if (!len) return 1;
|
if (!len) return 1;
|
||||||
|
|
||||||
if (!(buf = (CHAR *) MikMod_malloc(len))) return 0;
|
|
||||||
numlines = (len + linelen - 1) / linelen;
|
numlines = (len + linelen - 1) / linelen;
|
||||||
cnt = (linelen + 1) * numlines;
|
cnt = (linelen + 1) * numlines;
|
||||||
if (!(storage = (CHAR *) MikMod_malloc(cnt + 1))) {
|
buf = (CHAR *) MikMod_calloc(1, len);
|
||||||
|
if (!buf) return 0;
|
||||||
|
storage = (CHAR *) MikMod_calloc(1, cnt + 1);
|
||||||
|
if (!storage) {
|
||||||
MikMod_free(buf);
|
MikMod_free(buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_mm_read_UBYTES(buf,len,modreader);
|
_mm_read_UBYTES(buf,len,modreader);
|
||||||
storage[cnt] = 0;
|
|
||||||
for (line = 0, fpos = 0, cpos = 0; line < numlines; line++, fpos += linelen, cpos += (linelen + 1))
|
for (line = 0, fpos = 0, cpos = 0; line < numlines; line++, fpos += linelen, cpos += (linelen + 1))
|
||||||
{
|
{
|
||||||
cnt = len - fpos;
|
cnt = len - fpos;
|
||||||
|
|
|
@ -182,9 +182,12 @@ void S3MIT_ProcessCmd(UBYTE cmd, UBYTE inf, unsigned int flags)
|
||||||
UniEffect(UNI_ITEFFECTG,inf);
|
UniEffect(UNI_ITEFFECTG,inf);
|
||||||
break;
|
break;
|
||||||
case 8: /* Hxy vibrato */
|
case 8: /* Hxy vibrato */
|
||||||
if (flags & S3MIT_OLDSTYLE)
|
if (flags & S3MIT_OLDSTYLE) {
|
||||||
UniPTEffect(0x4,inf);
|
if (flags & S3MIT_IT)
|
||||||
else
|
UniEffect(UNI_ITEFFECTH_OLD,inf);
|
||||||
|
else
|
||||||
|
UniEffect(UNI_S3MEFFECTH,inf);
|
||||||
|
} else
|
||||||
UniEffect(UNI_ITEFFECTH,inf);
|
UniEffect(UNI_ITEFFECTH,inf);
|
||||||
break;
|
break;
|
||||||
case 9: /* Ixy tremor, ontime x, offtime y */
|
case 9: /* Ixy tremor, ontime x, offtime y */
|
||||||
|
@ -197,9 +200,12 @@ void S3MIT_ProcessCmd(UBYTE cmd, UBYTE inf, unsigned int flags)
|
||||||
UniPTEffect(0x0,inf);
|
UniPTEffect(0x0,inf);
|
||||||
break;
|
break;
|
||||||
case 0xb: /* Kxy Dual command H00 & Dxy */
|
case 0xb: /* Kxy Dual command H00 & Dxy */
|
||||||
if (flags & S3MIT_OLDSTYLE)
|
if (flags & S3MIT_OLDSTYLE) {
|
||||||
UniPTEffect(0x4,0);
|
if (flags & S3MIT_IT)
|
||||||
else
|
UniEffect(UNI_ITEFFECTH_OLD,0);
|
||||||
|
else
|
||||||
|
UniEffect(UNI_S3MEFFECTH,0);
|
||||||
|
} else
|
||||||
UniEffect(UNI_ITEFFECTH,0);
|
UniEffect(UNI_ITEFFECTH,0);
|
||||||
UniEffect(UNI_S3MEFFECTD,inf);
|
UniEffect(UNI_S3MEFFECTD,inf);
|
||||||
break;
|
break;
|
||||||
|
@ -211,7 +217,9 @@ void S3MIT_ProcessCmd(UBYTE cmd, UBYTE inf, unsigned int flags)
|
||||||
UniEffect(UNI_S3MEFFECTD,inf);
|
UniEffect(UNI_S3MEFFECTD,inf);
|
||||||
break;
|
break;
|
||||||
case 0xd: /* Mxx Set Channel Volume */
|
case 0xd: /* Mxx Set Channel Volume */
|
||||||
UniEffect(UNI_ITEFFECTM,inf);
|
/* Ignore invalid values > 64. */
|
||||||
|
if (inf <= 0x40)
|
||||||
|
UniEffect(UNI_ITEFFECTM,inf);
|
||||||
break;
|
break;
|
||||||
case 0xe: /* Nxy Slide Channel Volume */
|
case 0xe: /* Nxy Slide Channel Volume */
|
||||||
UniEffect(UNI_ITEFFECTN,inf);
|
UniEffect(UNI_ITEFFECTN,inf);
|
||||||
|
@ -259,9 +267,12 @@ void S3MIT_ProcessCmd(UBYTE cmd, UBYTE inf, unsigned int flags)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x15: /* Uxy Fine Vibrato speed x, depth y */
|
case 0x15: /* Uxy Fine Vibrato speed x, depth y */
|
||||||
if(flags & S3MIT_OLDSTYLE)
|
if(flags & S3MIT_OLDSTYLE) {
|
||||||
UniEffect(UNI_S3MEFFECTU,inf);
|
if (flags & S3MIT_IT)
|
||||||
else
|
UniEffect(UNI_ITEFFECTU_OLD,inf);
|
||||||
|
else
|
||||||
|
UniEffect(UNI_S3MEFFECTU,inf);
|
||||||
|
} else
|
||||||
UniEffect(UNI_ITEFFECTU,inf);
|
UniEffect(UNI_ITEFFECTU,inf);
|
||||||
break;
|
break;
|
||||||
case 0x16: /* Vxx Set Global Volume */
|
case 0x16: /* Vxx Set Global Volume */
|
||||||
|
|
|
@ -20,8 +20,6 @@
|
||||||
|
|
||||||
/*==============================================================================
|
/*==============================================================================
|
||||||
|
|
||||||
$Id$
|
|
||||||
|
|
||||||
Dynamic memory routines
|
Dynamic memory routines
|
||||||
|
|
||||||
==============================================================================*/
|
==============================================================================*/
|
||||||
|
@ -106,7 +104,12 @@ void* MikMod_realloc(void *data, size_t size)
|
||||||
/* Same as malloc, but sets error variable _mm_error when fails */
|
/* Same as malloc, but sets error variable _mm_error when fails */
|
||||||
void* MikMod_malloc(size_t size)
|
void* MikMod_malloc(size_t size)
|
||||||
{
|
{
|
||||||
return MikMod_calloc(1, size);
|
void *d = malloc(size);
|
||||||
|
if (d) return d;
|
||||||
|
|
||||||
|
_mm_errno = MMERR_OUT_OF_MEMORY;
|
||||||
|
if(_mm_errorhandler) _mm_errorhandler();
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Same as calloc, but sets error variable _mm_error when fails */
|
/* Same as calloc, but sets error variable _mm_error when fails */
|
||||||
|
@ -134,8 +137,8 @@ CHAR *MikMod_strdup(const CHAR *s)
|
||||||
if (!s) return NULL;
|
if (!s) return NULL;
|
||||||
|
|
||||||
l = strlen(s) + 1;
|
l = strlen(s) + 1;
|
||||||
d = (CHAR *) MikMod_calloc(1, l * sizeof(CHAR));
|
d = (CHAR *) MikMod_malloc(l);
|
||||||
if (d) strcpy(d, s);
|
if (d) memcpy(d, s, l);
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -202,14 +202,14 @@ static const char *_mm_errmsg[MMERR_MAX+1] =
|
||||||
|
|
||||||
/* MacOS X/Darwin driver errors */
|
/* MacOS X/Darwin driver errors */
|
||||||
#ifdef DRV_OSX
|
#ifdef DRV_OSX
|
||||||
"Unknown device",
|
_mmerr_invalid,
|
||||||
"Bad property",
|
_mmerr_invalid,
|
||||||
"Could not set playback format",
|
"Could not set playback format",
|
||||||
"Could not set mono/stereo setting",
|
_mmerr_invalid,
|
||||||
"Could not create playback buffers",
|
_mmerr_invalid,
|
||||||
"Could not create playback thread",
|
_mmerr_invalid,
|
||||||
"Could not start audio device",
|
"Could not start audio device",
|
||||||
"Could not create buffer thread",
|
_mmerr_invalid,
|
||||||
#else
|
#else
|
||||||
_mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
|
_mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
|
||||||
_mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
|
_mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -100,6 +100,27 @@ const UWORD unioperands[UNI_LAST] = {
|
||||||
0, /* UNI_MEDEFFECTF2 */
|
0, /* UNI_MEDEFFECTF2 */
|
||||||
0, /* UNI_MEDEFFECTF3 */
|
0, /* UNI_MEDEFFECTF3 */
|
||||||
2, /* UNI_OKTARP */
|
2, /* UNI_OKTARP */
|
||||||
|
0, /* not used */
|
||||||
|
1, /* UNI_S3MEFFECTH */
|
||||||
|
1, /* UNI_ITEFFECTH_OLD */
|
||||||
|
1, /* UNI_ITEFFECTU_OLD */
|
||||||
|
1, /* UNI_GDMEFFECT4 */
|
||||||
|
1, /* UNI_GDMEFFECT7 */
|
||||||
|
1, /* UNI_GDMEFFECT14 */
|
||||||
|
2, /* UNI_MEDEFFECT_VIB */
|
||||||
|
0, /* UNI_MEDEFFECT_FD */
|
||||||
|
1, /* UNI_MEDEFFECT_16 */
|
||||||
|
1, /* UNI_MEDEFFECT_18 */
|
||||||
|
1, /* UNI_MEDEFFECT_1E */
|
||||||
|
1, /* UNI_MEDEFFECT_1F */
|
||||||
|
1, /* UNI_FAREFFECT1 */
|
||||||
|
1, /* UNI_FAREFFECT2 */
|
||||||
|
1, /* UNI_FAREFFECT3 */
|
||||||
|
1, /* UNI_FAREFFECT4 */
|
||||||
|
1, /* UNI_FAREFFECT6 */
|
||||||
|
1, /* UNI_FAREFFECTD */
|
||||||
|
1, /* UNI_FAREFFECTE */
|
||||||
|
1, /* UNI_FAREFFECTF */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Sparse description of the internal module format
|
/* Sparse description of the internal module format
|
||||||
|
@ -262,7 +283,7 @@ void UniNewline(void)
|
||||||
unibuf[lastp]+=0x20;
|
unibuf[lastp]+=0x20;
|
||||||
unipc = unitt+1;
|
unipc = unitt+1;
|
||||||
} else {
|
} else {
|
||||||
if (UniExpand(unitt-unipc)) {
|
if (UniExpand(len)) {
|
||||||
/* current and previous row aren't equal... update the pointers */
|
/* current and previous row aren't equal... update the pointers */
|
||||||
unibuf[unitt] = len;
|
unibuf[unitt] = len;
|
||||||
lastp = unitt;
|
lastp = unitt;
|
||||||
|
|
|
@ -20,8 +20,6 @@
|
||||||
|
|
||||||
/*==============================================================================
|
/*==============================================================================
|
||||||
|
|
||||||
$Id$
|
|
||||||
|
|
||||||
Routines for loading samples. The sample loader utilizes the routines
|
Routines for loading samples. The sample loader utilizes the routines
|
||||||
provided by the "registered" sample loader.
|
provided by the "registered" sample loader.
|
||||||
|
|
||||||
|
@ -56,7 +54,7 @@ typedef struct ITPACK {
|
||||||
int SL_Init(SAMPLOAD* s)
|
int SL_Init(SAMPLOAD* s)
|
||||||
{
|
{
|
||||||
if(!sl_buffer)
|
if(!sl_buffer)
|
||||||
if(!(sl_buffer=(SWORD*)MikMod_malloc(SLBUFSIZE*sizeof(SWORD)))) return 0;
|
if(!(sl_buffer=(SWORD*)MikMod_calloc(1,SLBUFSIZE*sizeof(SWORD)))) return 0;
|
||||||
|
|
||||||
sl_rlength = s->length;
|
sl_rlength = s->length;
|
||||||
if(s->infmt & SF_16BITS) sl_rlength>>=1;
|
if(s->infmt & SF_16BITS) sl_rlength>>=1;
|
||||||
|
@ -221,7 +219,7 @@ static int read_itcompr16(ITPACK *status,MREADER *reader,SWORD *out,UWORD count,
|
||||||
return (dest-out);
|
return (dest-out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int SL_LoadInternal(void* buffer,UWORD infmt,UWORD outfmt,int scalefactor,ULONG length,MREADER* reader,int dither)
|
static int SL_LoadInternal(void *buffer,UWORD infmt,UWORD outfmt,int scalefactor,ULONG length,MREADER *reader,int dither)
|
||||||
{
|
{
|
||||||
SBYTE *bptr = (SBYTE*)buffer;
|
SBYTE *bptr = (SBYTE*)buffer;
|
||||||
SWORD *wptr = (SWORD*)buffer;
|
SWORD *wptr = (SWORD*)buffer;
|
||||||
|
@ -231,6 +229,10 @@ static int SL_LoadInternal(void* buffer,UWORD infmt,UWORD outfmt,int scalefactor
|
||||||
ITPACK status;
|
ITPACK status;
|
||||||
UWORD incnt = 0;
|
UWORD incnt = 0;
|
||||||
|
|
||||||
|
SBYTE compressionTable[16];
|
||||||
|
SWORD adpcmDelta = 0;
|
||||||
|
int hasTable = 0;
|
||||||
|
|
||||||
status.buf = 0;
|
status.buf = 0;
|
||||||
status.last = 0;
|
status.last = 0;
|
||||||
status.bufbits = 0;
|
status.bufbits = 0;
|
||||||
|
@ -260,6 +262,22 @@ static int SL_LoadInternal(void* buffer,UWORD infmt,UWORD outfmt,int scalefactor
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
c_block -= stodo;
|
c_block -= stodo;
|
||||||
|
} else if (infmt&SF_ADPCM4) {
|
||||||
|
if (!hasTable) {
|
||||||
|
/* Read compression table */
|
||||||
|
_mm_read_SBYTES(compressionTable, 16, reader);
|
||||||
|
hasTable = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4-bit ADPCM data, used by MOD plugin
|
||||||
|
for(t=0;t<stodo;t+=2) {
|
||||||
|
UBYTE b = _mm_read_UBYTE(reader);
|
||||||
|
|
||||||
|
adpcmDelta += compressionTable[b & 0x0f];
|
||||||
|
sl_buffer[t] = adpcmDelta << 8;
|
||||||
|
adpcmDelta += compressionTable[(b >> 4) & 0x0f];
|
||||||
|
sl_buffer[t+1] = adpcmDelta << 8;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if(infmt&SF_16BITS) {
|
if(infmt&SF_16BITS) {
|
||||||
if(_mm_eof(reader)) {
|
if(_mm_eof(reader)) {
|
||||||
|
@ -368,7 +386,7 @@ SAMPLOAD* SL_RegisterSample(SAMPLE* s,int type,MREADER* reader)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Allocate and add structure to the END of the list */
|
/* Allocate and add structure to the END of the list */
|
||||||
if(!(news=(SAMPLOAD*)MikMod_malloc(sizeof(SAMPLOAD)))) return NULL;
|
if(!(news=(SAMPLOAD*)MikMod_calloc(1, sizeof(SAMPLOAD)))) return NULL;
|
||||||
|
|
||||||
if(cruise) {
|
if(cruise) {
|
||||||
while(cruise->next) cruise=cruise->next;
|
while(cruise->next) cruise=cruise->next;
|
||||||
|
|
|
@ -20,19 +20,14 @@
|
||||||
|
|
||||||
/*==============================================================================
|
/*==============================================================================
|
||||||
|
|
||||||
$Id$
|
|
||||||
|
|
||||||
Sample mixing routines, using a 32 bits mixing buffer.
|
Sample mixing routines, using a 32 bits mixing buffer.
|
||||||
|
|
||||||
==============================================================================*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
Optional features include:
|
Optional features include:
|
||||||
(a) 4-step reverb (for 16 bit output only)
|
(a) 4-step reverb (for 16 bit output only)
|
||||||
(b) Interpolation of sample data during mixing
|
(b) Interpolation of sample data during mixing
|
||||||
(c) Dolby Surround Sound
|
(c) Dolby Surround Sound
|
||||||
*/
|
|
||||||
|
==============================================================================*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -129,7 +124,7 @@ static SLONG *RVbufR1=NULL,*RVbufR2=NULL,*RVbufR3=NULL,*RVbufR4=NULL,
|
||||||
#if defined HAVE_SSE2 || defined HAVE_ALTIVEC
|
#if defined HAVE_SSE2 || defined HAVE_ALTIVEC
|
||||||
|
|
||||||
# if !defined(NATIVE_64BIT_INT)
|
# if !defined(NATIVE_64BIT_INT)
|
||||||
static SINTPTR_T MixSIMDMonoNormal(const SWORD* srce,SLONG* dest,SINTPTR_T idx,SINTPTR_T increment,SINTPTR_T todo)
|
static SSIZE_T MixSIMDMonoNormal(const SWORD* srce,SLONG* dest,SSIZE_T idx,SSIZE_T increment,SSIZE_T todo)
|
||||||
{
|
{
|
||||||
/* TODO: */
|
/* TODO: */
|
||||||
SWORD sample;
|
SWORD sample;
|
||||||
|
@ -145,7 +140,7 @@ static SINTPTR_T MixSIMDMonoNormal(const SWORD* srce,SLONG* dest,SINTPTR_T idx,S
|
||||||
}
|
}
|
||||||
# endif /* !NATIVE_64BIT_INT */
|
# endif /* !NATIVE_64BIT_INT */
|
||||||
|
|
||||||
static SINTPTR_T MixSIMDStereoNormal(const SWORD* srce,SLONG* dest,SINTPTR_T idx,SINTPTR_T increment,SINTPTR_T todo)
|
static SSIZE_T MixSIMDStereoNormal(const SWORD* srce,SLONG* dest,SSIZE_T idx,SSIZE_T increment,SSIZE_T todo)
|
||||||
{
|
{
|
||||||
SWORD vol[8] = {vnf->lvolsel, vnf->rvolsel};
|
SWORD vol[8] = {vnf->lvolsel, vnf->rvolsel};
|
||||||
SWORD sample;
|
SWORD sample;
|
||||||
|
@ -289,7 +284,7 @@ static SLONG Mix32MonoNormal(const SWORD* srce,SLONG* dest,SLONG idx,SLONG incre
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: This mixer should works also on 64-bit platform */
|
/* FIXME: This mixer should works also on 64-bit platform */
|
||||||
/* Hint : changes SLONG / SLONGLONG mess with intptr */
|
/* Hint : changes SLONG / SLONGLONG mess with ssize_t */
|
||||||
static SLONG Mix32StereoNormal(const SWORD* srce,SLONG* dest,SLONG idx,SLONG increment,SLONG todo)
|
static SLONG Mix32StereoNormal(const SWORD* srce,SLONG* dest,SLONG idx,SLONG increment,SLONG todo)
|
||||||
{
|
{
|
||||||
#if defined HAVE_ALTIVEC || defined HAVE_SSE2
|
#if defined HAVE_ALTIVEC || defined HAVE_SSE2
|
||||||
|
@ -1029,9 +1024,10 @@ static void AddChannel(SLONG* ptr,NATIVE todo)
|
||||||
(vnf->flags&SF_LOOP)?idxlend:idxsize;
|
(vnf->flags&SF_LOOP)?idxlend:idxsize;
|
||||||
|
|
||||||
/* if the sample is not blocked... */
|
/* if the sample is not blocked... */
|
||||||
if((end==vnf->current)||(!vnf->increment))
|
if((vnf->increment>0 && vnf->current>=end) ||
|
||||||
|
(vnf->increment<0 && vnf->current<=end) || !vnf->increment) {
|
||||||
done=0;
|
done=0;
|
||||||
else {
|
} else {
|
||||||
done=MIN((end-vnf->current)/vnf->increment+1,todo);
|
done=MIN((end-vnf->current)/vnf->increment+1,todo);
|
||||||
if(done<0) done=0;
|
if(done<0) done=0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,20 +20,14 @@
|
||||||
|
|
||||||
/*==============================================================================
|
/*==============================================================================
|
||||||
|
|
||||||
$Id$
|
|
||||||
|
|
||||||
High-quality sample mixing routines, using a 32 bits mixing buffer,
|
High-quality sample mixing routines, using a 32 bits mixing buffer,
|
||||||
interpolation, and sample smoothing to improve sound quality and remove
|
interpolation, and sample smoothing to improve sound quality and remove
|
||||||
clicks.
|
clicks.
|
||||||
|
|
||||||
==============================================================================*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
Future Additions:
|
Future Additions:
|
||||||
Low-Pass filter to remove annoying staticy buzz.
|
- Low-Pass filter to remove annoying staticy buzz.
|
||||||
|
|
||||||
*/
|
==============================================================================*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -1074,9 +1068,10 @@ static void AddChannel(SLONG* ptr,NATIVE todo)
|
||||||
(vnf->flags&SF_LOOP)?idxlend:idxsize;
|
(vnf->flags&SF_LOOP)?idxlend:idxsize;
|
||||||
|
|
||||||
/* if the sample is not blocked... */
|
/* if the sample is not blocked... */
|
||||||
if((end==vnf->current)||(!vnf->increment))
|
if((vnf->increment>0 && vnf->current>=end) ||
|
||||||
|
(vnf->increment<0 && vnf->current<=end) || !vnf->increment) {
|
||||||
done=0;
|
done=0;
|
||||||
else {
|
} else {
|
||||||
done=MIN((end-vnf->current)/vnf->increment+1,todo);
|
done=MIN((end-vnf->current)/vnf->increment+1,todo);
|
||||||
if(done<0) done=0;
|
if(done<0) done=0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,8 @@
|
||||||
|
|
||||||
/*==============================================================================
|
/*==============================================================================
|
||||||
|
|
||||||
$Id$
|
|
||||||
|
|
||||||
Common source parts between the two software mixers.
|
Common source parts between the two software mixers.
|
||||||
This file is probably the ugliest part of libmikmod...
|
This file is probably the ugliest part of libmikmod.
|
||||||
|
|
||||||
==============================================================================*/
|
==============================================================================*/
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue