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:
Solomon Peachy 2025-01-03 08:34:47 -05:00
parent 08c32cee7c
commit af7ed73f31
29 changed files with 1860 additions and 706 deletions

View 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

View file

@ -20,8 +20,6 @@
/*==============================================================================
$Id: $
Composer 669 module loader
==============================================================================*/
@ -321,7 +319,8 @@ static int S69_Load(int curious)
sample.length=_mm_read_I_SLONG(modreader);
sample.loopbeg=_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)) {
_mm_errno = MMERR_LOADING_HEADER;
@ -330,7 +329,7 @@ static int S69_Load(int curious)
current->samplename=DupStr(sample.filename,13,1);
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->loopstart=sample.loopbeg;
current->loopend=sample.loopend;

View file

@ -94,7 +94,7 @@ static int AMF_Test(void)
if(memcmp(id,"AMF",3)) return 0;
ver=_mm_read_UBYTE(modreader);
if((ver>=10)&&(ver<=14)) return 1;
if((ver>=8)&&(ver<=14)) return 1;
return 0;
}
@ -114,7 +114,48 @@ static void AMF_Cleanup(void)
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;
UBYTE row,cmd;
@ -126,7 +167,12 @@ static int AMF_UnpackTrack(MREADER* r)
/* read packed track */
if (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)
while(tracksize--) {
row=_mm_read_UBYTE(r);
@ -144,18 +190,23 @@ static int AMF_UnpackTrack(MREADER* r)
}
/* invalid row (probably unexpected end of row) */
if (row>=64)
return 0;
if (row>=64) {
_mm_fseek(modreader, tracksize * 3, SEEK_CUR);
return 1;
}
if (cmd<0x7f) {
/* 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].volume=(UBYTE)arg+1;
} else
if (cmd==0x7f) {
/* duplicate row */
if ((arg<0)&&(row+arg>=0)) {
memcpy(track+row,track+(row+arg),sizeof(AMFNOTE));
}
/* AMF.TXT claims this should duplicate the previous row, but
this is a lie. This note value is used to communicate to
DSMI that the current playing note should be updated when
an instrument is used with no note. This can be ignored. */
} else
if (cmd==0x80) {
/* instr */
@ -173,8 +224,11 @@ static int AMF_UnpackTrack(MREADER* r)
} else
if(track[row].fxcnt<3) {
/* effect, param */
if(cmd>0x97)
return 0;
if(cmd>0x97) {
/* 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].parameter[track[row].fxcnt]=arg;
track[row].fxcnt++;
@ -185,7 +239,7 @@ static int AMF_UnpackTrack(MREADER* r)
return 1;
}
static UBYTE* AMF_ConvertTrack(void)
static UBYTE *AMF_ConvertTrack(void)
{
int row,fx4memory=0;
@ -315,6 +369,7 @@ static UBYTE* AMF_ConvertTrack(void)
UniEffect(fx4memory,0);
break;
case 0x17: /* Panning */
/* S3M pan, except offset by -64. */
if (inf>64)
UniEffect(UNI_ITEFFECTS0,0x91); /* surround */
else
@ -338,17 +393,29 @@ static int AMF_Load(int curious)
SAMPLE *q;
UWORD *track_remap;
ULONG samplepos, fileend;
int channel_remap[16];
UBYTE channel_remap[16];
int no_loopend;
(void)curious;
/* try to read module header */
_mm_read_UBYTES(mh->id,3,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);
mh->numsamples =_mm_read_UBYTE(modreader);
mh->numorders =_mm_read_UBYTE(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))) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
@ -357,7 +424,7 @@ static int AMF_Load(int curious)
if(mh->version>=11) {
memset(mh->panpos,0,32);
_mm_read_SBYTES(mh->panpos,(mh->version>=13)?32:16,modreader);
} else
} else if(mh->version>=9)
_mm_read_UBYTES(channel_remap,16,modreader);
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.
*/
defaultpanning = 1;
for (t = 0; t < 32; t++) {
if (mh->panpos[t] > 64) {
of.panning[t] = PAN_SURROUND;
defaultpanning = 0;
} else
if (mh->panpos[t] == 64)
of.panning[t] = PAN_RIGHT;
else
of.panning[t] = (mh->panpos[t] + 64) << 1;
if(mh->version>=11) {
for (t = 0; t < 32; t++) {
if (mh->panpos[t] > 64) {
of.panning[t] = PAN_SURROUND;
defaultpanning = 0;
} else
if (mh->panpos[t] == 64)
of.panning[t] = PAN_RIGHT;
else
of.panning[t] = (mh->panpos[t] + 64) << 1;
}
}
else
defaultpanning = 0;
if (defaultpanning) {
for (t = 0; t < of.numchn; t++)
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)
/* track size */
of.pattrows[t]=_mm_read_I_UWORD(modreader);
if (mh->version>=10)
_mm_read_I_UWORDS(of.patterns+(t*of.numchn),of.numchn,modreader);
if ((mh->version==9) || (mh->version==10)) {
/* 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
for(u=0;u<of.numchn;u++)
of.patterns[t*of.numchn+channel_remap[u]]=_mm_read_I_UWORD(modreader);
_mm_read_I_UWORDS(of.patterns + (t * of.numchn), of.numchn, modreader);
}
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
@ -455,6 +530,12 @@ static int AMF_Load(int curious)
/* read sample information */
if(!AllocSamples()) return 0;
no_loopend = 0;
if(mh->version == 10) {
no_loopend = AMF_ScanV10Instruments(modreader, of.numins);
}
q=of.samples;
for(t=0;t<of.numins;t++) {
/* 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.filename,13,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);
if(s.c2spd==8368) s.c2spd=8363;
s.volume =_mm_read_UBYTE(modreader);
/* "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
* 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.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.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)) {

View file

@ -58,8 +58,12 @@ typedef struct MSAMPINFO {
typedef struct MODULEHEADER {
CHAR songname[21];
UBYTE initspeed;
UBYTE inittempo;
UBYTE num_samples;
UBYTE num_patterns; /* number of patterns used */
UBYTE num_orders;
UBYTE reppos;
UBYTE positions[256]; /* which pattern to play at pos */
MSAMPINFO samples[64]; /* all sampleinfo */
} MODULEHEADER;
@ -177,7 +181,7 @@ static int ConvertNote(MODNOTE *n)
if (instrument) {
/* 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);
if (effect == 0xc)
effect = effdat = 0;
@ -194,7 +198,6 @@ static int ConvertNote(MODNOTE *n)
* played */
if (effect || effdat) {
UniInstrument(instrument - 1);
note = lastnote;
} else
UniPTEffect(0xc,
mh->samples[instrument -
@ -294,22 +297,33 @@ static int ASY_Load(int curious)
/* no title in asylum amf files :( */
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_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);
#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*/
for (t = 0; t < 64; t++) {
for (t = 0; t < mh->num_samples; t++) {
s = &mh->samples[t];
_mm_fseek(modreader, 0x126 + (t*37), SEEK_SET);
_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->volume = _mm_read_UBYTE(modreader);
@ -324,14 +338,16 @@ static int ASY_Load(int curious)
return 0;
}
_mm_fseek(modreader, 37*(64-mh->num_samples), SEEK_CUR);
/* set module variables */
of.initspeed = 6;
of.inittempo = 125;
of.initspeed = mh->initspeed;
of.inittempo = mh->inittempo;
of.numchn = 8;
modtype = 0;
of.songname = DupStr(mh->songname, 21, 1);
of.songname = MikMod_strdup("");
of.numpos = mh->num_orders;
of.reppos = 0;
of.reppos = mh->reppos;
of.numpat = mh->num_patterns;
of.numtrk = of.numpat * of.numchn;
@ -348,8 +364,8 @@ static int ASY_Load(int curious)
}
/* Finally, init the sampleinfo structures */
of.numins = 31;
of.numsmp = 31;
of.numins = mh->num_samples;
of.numsmp = mh->num_samples;
if (!AllocSamples())
return 0;
s = mh->samples;

View file

@ -93,6 +93,7 @@ static FARHEADER2 *mh2 = NULL;
static FARNOTE *pat = NULL;
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 */
@ -134,20 +135,36 @@ static UBYTE *FAR_ConvertTrack(FARNOTE* n,int rows)
UniInstrument(n->ins);
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)
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 */
UniPTEffect(0x3,(n->eff&0xf)<<4);
UniEffect(UNI_FAREFFECT3, n->eff & 0xf);
break;
case 0x4: /* retrigger */
UniPTEffect(0x0e, 0x90 | (n->eff & 0x0f));
UniEffect(UNI_FAREFFECT4, n->eff & 0xf);
break;
case 0x5: /* set vibrato depth */
vibdepth=n->eff&0xf;
break;
case 0x6: /* vibrato */
UniPTEffect(0x4,((n->eff&0xf)<<4)|vibdepth);
UniEffect(UNI_FAREFFECT6,((n->eff&0xf)<<4)|vibdepth);
break;
case 0x7: /* volume slide up */
UniPTEffect(0xa,(n->eff&0xf)<<4);
@ -155,11 +172,21 @@ static UBYTE *FAR_ConvertTrack(FARNOTE* n,int rows)
case 0x8: /* volume slide down */
UniPTEffect(0xa,n->eff&0xf);
break;
case 0x9: /* sustained vibrato */
break;
case 0xb: /* panning */
UniPTEffect(0xe,0x80|(n->eff&0xf));
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 */
UniPTEffect(0xf,n->eff&0xf);
UniEffect(UNI_FAREFFECTF,n->eff&0xf);
break;
/* others not yet implemented */
@ -178,11 +205,12 @@ static UBYTE *FAR_ConvertTrack(FARNOTE* n,int rows)
static int FAR_Load(int curious)
{
int t,u,tracks=0;
int r,t,u,tracks=0;
SAMPLE *q;
FARSAMPLE s;
FARNOTE *crow;
UBYTE smap[8];
UBYTE addextrapattern;
(void)curious;
/* try to read module header (first part) */
@ -202,10 +230,9 @@ static int FAR_Load(int curious)
of.modtype = MikMod_strdup(FAR_Version);
of.songname = DupStr(mh1->songname,40,1);
of.numchn = 16;
of.initspeed = mh1->speed;
of.inittempo = 80;
of.reppos = 0;
of.flags |= UF_PANNING;
of.initspeed = mh1->speed != 0 ? mh1->speed : 4;
of.bpmlimit = 5;
of.flags |= UF_PANNING | UF_FARTEMPO | UF_HIGHBPM;
for(t=0;t<16;t++) of.panning[t]=mh1->panning[t]<<4;
/* read songtext into comment field */
@ -225,17 +252,29 @@ static int FAR_Load(int curious)
_mm_read_I_UWORDS(mh2->patsiz,256,modreader);
of.numpos = mh2->snglen;
of.reppos = mh2->loopto;
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 */
of.numpat = 0;
for(t=0;t<256;t++)
if(mh2->patsiz[t])
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;
/* seek across eventual new data */
@ -246,18 +285,17 @@ static int FAR_Load(int curious)
if(!AllocPatterns()) return 0;
for(t=0;t<of.numpat;t++) {
UBYTE rows=0;
UBYTE tempo;
memset(pat,0,256*16*4*sizeof(FARNOTE));
if(mh2->patsiz[t]) {
rows = _mm_read_UBYTE(modreader);
tempo = _mm_read_UBYTE(modreader);
(void)tempo; /* unused */
/* Break position byte is always 1 less than the final row index,
i.e. it is 2 less than the total row count. */
UWORD rows = _mm_read_UBYTE(modreader) + 2;
_mm_skip_BYTE(modreader); /* tempo */
crow = pat;
/* 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;
return 0;
}
@ -280,8 +318,17 @@ static int FAR_Load(int curious)
_mm_errno=MMERR_LOADING_PATTERN;
return 0;
}
} else
tracks+=16;
} else {
// 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 */
@ -319,11 +366,17 @@ static int FAR_Load(int curious)
q->loopend = s.repend;
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;
q->seekpos = _mm_ftell(modreader);
_mm_fseek(modreader,q->length,SEEK_CUR);
_mm_fseek(modreader,s.length,SEEK_CUR);
} else
q->samplename = MikMod_strdup("");
q++;

View file

@ -221,7 +221,7 @@ static UBYTE *GDM_ConvertTrack(GDMNOTE*tr)
if ((ins)&&(ins!=255))
UniInstrument(ins-1);
if (note!=255) {
if (note && note!=255) {
UniNote(((note>>4)*OCTAVE)+(note&0xf)-1);
}
for (i=0;i<4;i++) {
@ -237,18 +237,18 @@ static UBYTE *GDM_ConvertTrack(GDMNOTE*tr)
UniEffect(UNI_ITEFFECTG,inf);
break;
case 4: /* vibrato */
UniEffect(UNI_ITEFFECTH,inf);
UniEffect(UNI_GDMEFFECT4,inf);
break;
case 5: /* portamento+volslide */
UniEffect(UNI_ITEFFECTG,0);
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 6: /* vibrato+volslide */
UniEffect(UNI_ITEFFECTH,0);
UniEffect(UNI_GDMEFFECT4,0);
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 7: /* tremolo */
UniEffect(UNI_S3MEFFECTR,inf);
UniEffect(UNI_GDMEFFECT7,inf);
break;
case 8: /* tremor */
UniEffect(UNI_S3MEFFECTI,inf);
@ -271,37 +271,29 @@ static UBYTE *GDM_ConvertTrack(GDMNOTE*tr)
case 0x0e: /* extended */
switch (inf&0xf0) {
case 0x10: /* fine portamento up */
UniEffect(UNI_S3MEFFECTF, 0x0f|((inf<<4)&0x0f));
UniEffect(UNI_S3MEFFECTF, 0xf0|(inf&0x0f));
break;
case 0x20: /* fine portamento down */
UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f));
break;
case 0x30: /* glissando control */
UniEffect(SS_GLISSANDO, inf&0x0f);
break;
case 0x40: /* vibrato waveform */
UniEffect(SS_VIBWAVE, inf&0x0f);
break;
case 0x50: /* set c4spd */
UniEffect(SS_FINETUNE, inf&0x0f);
break;
case 0x60: /* loop fun */
UniEffect(UNI_ITEFFECTS0, (inf&0x0f)|0xb0);
break;
case 0x70: /* tremolo waveform */
UniEffect(SS_TREMWAVE, inf&0x0f);
UniPTEffect(0xe, inf);
break;
case 0x80: /* extra fine porta up */
UniEffect(UNI_S3MEFFECTF, 0x0e|((inf<<4)&0x0f));
UniEffect(UNI_S3MEFFECTF, 0xe0|(inf&0x0f));
break;
case 0x90: /* extra fine porta down */
UniEffect(UNI_S3MEFFECTE, 0xe0|(inf&0x0f));
break;
case 0xa0: /* fine volslide up */
UniEffect(UNI_S3MEFFECTD, 0x0f|((inf<<4)&0x0f));
UniEffect(UNI_S3MEFFECTD, 0x0f|((inf&0x0f)<<4));
break;
case 0xb0: /* fine volslide down */
UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f));
UniEffect(UNI_S3MEFFECTD, 0xf0|(inf&0x0f));
break;
case 0xc0: /* note cut */
case 0xd0: /* note delay */
@ -320,18 +312,15 @@ static UBYTE *GDM_ConvertTrack(GDMNOTE*tr)
UniEffect(UNI_S3MEFFECTQ,inf);
break;
case 0x13: /* set global volume */
UniEffect(UNI_XMEFFECTG,inf<<1);
UniEffect(UNI_XMEFFECTG,inf);
break;
case 0x14: /* fine vibrato */
UniEffect(UNI_ITEFFECTU,inf);
UniEffect(UNI_GDMEFFECT14,inf);
break;
case 0x1e: /* special */
switch (inf&0xf0) {
case 8: /* set pan position */
if (inf >=128)
UniPTEffect(0x08,255);
else
UniPTEffect(0x08,inf<<1);
case 0x80: /* set pan position */
UniPTEffect(0xe,inf);
break;
}
break;
@ -473,16 +462,21 @@ static int GDM_Load(int curious)
q->length=s.length;
q->loopstart=s.loopbeg;
q->loopend=s.loopend;
q->volume=s.vol;
q->panning=s.pan;
q->volume=64;
q->seekpos=position;
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)
q->flags |=SF_LOOP;
if (s.flags&2)
q->flags |=SF_16BITS;
if ((s.flags&4) && s.vol<=64)
q->volume=s.vol;
if (s.flags&16)
q->flags |=SF_STEREO;
q++;

View file

@ -76,6 +76,7 @@ typedef struct ITHEADER {
/* sample information */
typedef struct ITSAMPLE {
UBYTE id[4]; /* 'IMPS' */
CHAR filename[12];
UBYTE zerobyte;
UBYTE globvol;
@ -102,6 +103,7 @@ typedef struct ITSAMPLE {
#define ITENVCNT 25
#define ITNOTECNT 120
typedef struct ITINSTHEADER {
UBYTE id[4]; /* 'IMPI' */
ULONG size; /* (dword) Instrument size */
CHAR filename[12]; /* (char) Instrument filename */
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(!(poslookup=(UBYTE*)MikMod_malloc(256*sizeof(UBYTE)))) return 0;
if(!(itpat=(ITNOTE*)MikMod_malloc(200*64*sizeof(ITNOTE)))) return 0;
if(!(mask=(UBYTE*)MikMod_malloc(64*sizeof(UBYTE)))) return 0;
if(!(last=(ITNOTE*)MikMod_malloc(64*sizeof(ITNOTE)))) return 0;
if(!(mask=(UBYTE*)MikMod_calloc(64,sizeof(UBYTE)))) return 0;
if(!(last=(ITNOTE*)MikMod_calloc(64,sizeof(ITNOTE)))) return 0;
return 1;
}
@ -277,7 +279,10 @@ static UBYTE* IT_ConvertTrack(ITNOTE* tr,UWORD numrows)
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);
else if(ins==253)
UniWriteByte(UNI_KEYOFF);
@ -632,7 +637,16 @@ static int IT_Load(int curious)
ITSAMPLE s;
/* 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 */
_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&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&4) q->flags|=SF_DELTA;
}
@ -719,7 +734,12 @@ static int IT_Load(int curious)
ITINSTHEADER ih;
/* 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 */
_mm_read_string(ih.filename,12,modreader);
@ -988,8 +1008,6 @@ static int IT_Load(int curious)
if(!AllocTracks()) return 0;
for(t=0;t<of.numpat;t++) {
UWORD packlen;
/* seek to pattern position */
if(!paraptr[mh->insnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */
of.pattrows[t]=64;
@ -1002,8 +1020,7 @@ static int IT_Load(int curious)
}
} else {
_mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET);
packlen=_mm_read_I_UWORD(modreader);
(void)packlen; /* unused */
(void) _mm_read_I_UWORD(modreader); /* packlen */
of.pattrows[t]=_mm_read_I_UWORD(modreader);
_mm_read_I_ULONG(modreader);
if(!IT_ReadPattern(of.pattrows[t])) return 0;

View file

@ -20,8 +20,6 @@
/*==============================================================================
$Id$
Amiga MED module loader
==============================================================================*/
@ -48,6 +46,8 @@ extern int fprintf(FILE *, const char *, ...);
/*========== Module information */
#define MEDNOTECNT 120
typedef struct MEDHEADER {
ULONG id;
ULONG modlen;
@ -137,6 +137,19 @@ typedef struct MEDINSTINFO {
UBYTE name[40];
} 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 */
#define MMD0_string 0x4D4D4430
@ -149,8 +162,11 @@ static ULONG *ba = NULL;
static MMD0NOTE *mmd0pat = NULL;
static MMD1NOTE *mmd1pat = NULL;
static UBYTE medversion;
static int decimalvolumes;
static int bpmtempos;
static int is8channel;
static UWORD rowsperbeat;
#define d0note(row,col) mmd0pat[((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;
}
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) {
/* 0x0 0x1 0x2 0x3 0x4 PT effects */
case 0x5: /* PT vibrato with speed/depth nibbles swapped */
UniPTEffect(0x4, (dat >> 4) | ((dat & 0xf) << 4));
/* 0x0: arpeggio */
case 0x1: /* portamento up (PT compatible, ignore 0) */
if (dat)
UniPTEffect(0x1, dat);
break;
/* 0x6 0x7 not used */
case 0x6:
case 0x7:
case 0x2: /* portamento down (PT compatible, ignore 0) */
if (dat)
UniPTEffect(0x2, dat);
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;
case 0x9:
if (bpmtempos) {
if (!dat)
dat = of.initspeed;
case 0x5: /* tone portamento + volslide (MMD0: old vibrato) */
if (medversion == 0) {
/* Approximate conversion, probably wrong.
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);
} 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;
/* 0xa 0xb PT effects */
/* 0xa: volslide */
/* 0xb: position jump */
case 0xc:
if (decimalvolumes)
dat = (dat >> 4) * 10 + (dat & 0xf);
UniPTEffect(0xc, dat);
break;
case 0xa:
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);
break;
case 0xe: /* synth jmp - midi */
case 0xe: /* synth jump (FIXME- synth instruments not implemented) */
break;
case 0xf:
switch (dat) {
case 0: /* patternbreak */
case 0: /* patternbreak */
UniPTEffect(0xd, 0);
break;
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);
break;
case 0xf2: /* delay note */
@ -251,6 +333,15 @@ static void EffectCvt(UBYTE eff, UBYTE dat)
case 0xf3: /* play note three times */
UniWriteByte(UNI_MEDEFFECTF3);
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 */
UniPTEffect(0xb, of.numpat);
break;
@ -258,18 +349,65 @@ static void EffectCvt(UBYTE eff, UBYTE dat)
UniPTEffect(0xc, 0);
break;
default:
if (dat <= 10)
UniPTEffect(0xf, dat);
else if (dat <= 240) {
if (bpmtempos)
UniPTEffect(0xf, (dat < 32) ? 32 : dat);
else
UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / 33);
}
if (dat <= 240)
UniEffect(UNI_MEDSPEED, MED_ConvertTempo(dat));
}
break;
default: /* all normal PT effects are handled here */
UniPTEffect(eff, dat);
case 0x11: /* fine portamento up */
/* 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;
}
}
@ -286,14 +424,14 @@ static UBYTE *MED_Convert1(int count, int col)
note = n->a & 0x7f;
inst = n->b & 0x3f;
eff = n->c & 0xf;
eff = n->c;
dat = n->d;
if (inst)
UniInstrument(inst - 1);
if (note)
UniNote(note + 3 * OCTAVE - 1);
EffectCvt(eff, dat);
UniNote(note - 1);
EffectCvt(note, eff, dat);
UniNewline();
}
return UniDup();
@ -321,8 +459,8 @@ static UBYTE *MED_Convert0(int count, int col)
if (inst)
UniInstrument(inst - 1);
if (note)
UniNote(note + 3 * OCTAVE - 1);
EffectCvt(eff, dat);
UniNote(note - 1);
EffectCvt(note, eff, dat);
UniNewline();
}
return UniDup();
@ -349,7 +487,7 @@ static int LoadMEDPatterns(void)
return 0;
}
/* 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;
of.numtrk = of.numpat * of.numchn;
@ -375,6 +513,8 @@ static int LoadMEDPatterns(void)
mmdp->b = _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++)
@ -405,7 +545,7 @@ static int LoadMMD1Patterns(void)
return 0;
}
/* 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;
of.numtrk = of.numpat * of.numchn;
@ -434,6 +574,8 @@ static int LoadMMD1Patterns(void)
mmdp->c = _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++)
@ -444,9 +586,10 @@ static int LoadMMD1Patterns(void)
static int MED_Load(int curious)
{
int t;
int t, i;
ULONG sa[64];
MEDINSTHEADER s;
INSTRUMENT *d;
SAMPLE *q;
MEDSAMPLE *mss;
@ -536,7 +679,7 @@ static int MED_Load(int curious)
_mm_errno = MMERR_NOT_A_MODULE;
return 0;
}
/* truncate insane songnamelen (fail instead??) */
/* truncate insane songnamelen (fail instead?) */
if (me->songnamelen > 256)
me->songnamelen = 256;
}
@ -570,46 +713,18 @@ static int MED_Load(int curious)
}
decimalvolumes = (ms->flags & 0x10) ? 0 : 1;
is8channel = (ms->flags & 0x40) ? 1 : 0;
bpmtempos = (ms->flags2 & 0x20) ? 1 : 0;
if (bpmtempos) {
int bpmlen = (ms->flags2 & 0x1f) + 1;
rowsperbeat = (ms->flags2 & 0x1f) + 1;
of.initspeed = ms->tempo2;
of.inittempo = ms->deftempo * bpmlen / 4;
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);
}
of.inittempo = MED_ConvertTempo(ms->deftempo);
} else {
of.initspeed = ms->tempo2;
of.inittempo = ms->deftempo ? ((UWORD)ms->deftempo * 125) / 33 : 128;
if ((ms->deftempo <= 10) && (ms->deftempo))
of.inittempo = (of.inittempo * 33) / 6;
of.flags |= UF_HIGHBPM;
of.inittempo = ms->deftempo ? MED_ConvertTempo(ms->deftempo) : 128;
}
of.flags |= UF_HIGHBPM;
MED_Version[12] = mh->id;
of.modtype = MikMod_strdup(MED_Version);
of.numchn = 0; /* will be counted later */
@ -633,18 +748,29 @@ static int MED_Load(int curious)
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;
of.flags |= UF_INST;
q = of.samples;
d = of.instruments;
for (t = 0; t < of.numins; t++) {
q->flags = SF_SIGNED;
q->volume = 64;
s.type = INST_SAMPLE;
if (sa[t]) {
_mm_fseek(modreader, sa[t], SEEK_SET);
s.length = _mm_read_M_ULONG(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
fprintf(stderr, "\rNon-sample instruments not supported in MED loader yet\n");
#endif
@ -668,6 +794,9 @@ static int MED_Load(int curious)
if (ms->sample[t].replen > 1)
q->flags |= SF_LOOP;
if(ms->sample[t].svol <= 64)
q->volume = ms->sample[t].svol;
/* don't load sample if length>='MMD0'...
such kluges make libmikmod's code unique !!! */
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_read_UBYTES(ii.name, 40, modreader);
q->samplename = DupStr((char*)ii.name, 40, 1);
} else
d->insname = DupStr((char*)ii.name, 40, 1);
} else {
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++;
d++;
}
if (mh->id == MMD0_string) {
medversion = 0;
if (!LoadMEDPatterns()) {
_mm_errno = MMERR_LOADING_PATTERN;
return 0;
}
} else if (mh->id == MMD1_string) {
medversion = 1;
if (!LoadMMD1Patterns()) {
_mm_errno = MMERR_LOADING_PATTERN;
return 0;

View file

@ -84,10 +84,13 @@ typedef struct MODNOTE {
static CHAR protracker[] = "Protracker";
static CHAR startrekker[] = "Startrekker";
static CHAR fasttracker[] = "Fasttracker";
static CHAR oktalyser[] = "Oktalyser";
static CHAR octalyser[] = "Octalyser";
static CHAR oktalyzer[] = "Oktalyzer";
static CHAR taketracker[] = "TakeTracker";
static CHAR digitaltracker[] = "Digital Tracker MOD";
static CHAR orpheus[] = "Imago Orpheus (MOD format)";
static CHAR modsgrave[] = "Mod's Grave";
static CHAR unknown[] = "Unknown tracker MOD";
static MODULEHEADER *mh = NULL;
static MODNOTE *patbuf = NULL;
@ -102,7 +105,7 @@ static int MOD_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)
modtype = trekker = 0;
/* 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;
modtype = 0;
*numchn = 4;
@ -132,11 +135,11 @@ static int MOD_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)
return 1;
}
/* Oktalyser (Atari) */
if (!memcmp(id, "CD81", 4)) {
*descr = oktalyser;
/* Octalyser (Atari) */
if (!memcmp(id, "CD81", 4) || !memcmp(id, "CD61", 4)) {
*descr = octalyser;
modtype = 1;
*numchn = 8;
*numchn = id[2] - '0';
return 1;
}
@ -160,6 +163,27 @@ static int MOD_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)
*numchn = (id[0] - '0') * 10 + (id[1] - '0');
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;
}
@ -368,6 +392,16 @@ static int MOD_Load(int curious)
SAMPLE *q;
MSAMPINFO *s;
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 */
_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->reppos = _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);
@ -394,6 +433,10 @@ static int MOD_Load(int curious)
_mm_read_UBYTES(mh->positions, 128, 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)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
@ -406,6 +449,12 @@ static int MOD_Load(int curious)
_mm_errno = MMERR_NOT_A_MODULE;
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)
for (t = 0; t < 128; t++)
/* 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.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;
if (!AllocPositions(of.numpos))
@ -450,12 +517,16 @@ static int MOD_Load(int curious)
for (t = 0; t < of.numpos; t++)
of.positions[t] = mh->positions[t];
if (!ML_LoadPatterns())
return 0;
/* Finally, init the sampleinfo structures */
of.numins = of.numsmp = 31;
if (!AllocSamples())
return 0;
s = mh->samples;
q = of.samples;
pos = _mm_ftell(modreader);
for (t = 0; t < of.numins; t++) {
/* convert the samplename */
q->samplename = DupStr(s->samplename, 23, 1);
@ -474,15 +545,28 @@ static int MOD_Load(int curious)
if (s->replen > 2)
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++;
q++;
}
of.modtype = MikMod_strdup(descr);
if (!ML_LoadPatterns())
return 0;
return 1;
}

View file

@ -403,6 +403,7 @@ static int S3M_Load(int curious)
if(s.flags&1) q->flags |= SF_LOOP;
if(s.flags&4) q->flags |= SF_16BITS;
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 */
if(memcmp(s.scrs,"SCRS",4)) q->length = 0;

View file

@ -225,7 +225,7 @@ static UBYTE *STM_ConvertTrack(STMNOTE *n)
return UniDup();
}
static int STM_LoadPatterns(void)
static int STM_LoadPatterns(unsigned int pattoload)
{
unsigned int t,s,tracks=0;
@ -233,7 +233,7 @@ static int STM_LoadPatterns(void)
if(!AllocTracks()) return 0;
/* 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++) {
stmbuf[s].note = _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)
{
int blankpattern=0;
int pattoload;
int t;
ULONG MikMod_ISA; /* We must generate our own ISA, it's not stored in stm */
ULONG samplestart;
ULONG sampleend;
SAMPLE *q;
(void)curious;
/* try to read stm header */
_mm_read_string(mh->songname,20,modreader);
_mm_read_string(mh->trackername,8,modreader);
@ -318,22 +320,38 @@ static int STM_Load(int curious)
t=0;
if(!AllocPositions(0x80)) return 0;
/* 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];
/* 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) {
_mm_errno = MMERR_NOT_A_MODULE;
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.numtrk=of.numpat*of.numchn;
of.numins=of.numsmp=31;
if(!AllocSamples()) return 0;
if(!STM_LoadPatterns()) return 0;
MikMod_ISA=_mm_ftell(modreader);
MikMod_ISA=(MikMod_ISA+15)&0xfffffff0; /* normalize */
if(!STM_LoadPatterns(pattoload)) return 0;
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++) {
/* load sample info */
@ -341,19 +359,46 @@ static int STM_Load(int curious)
q->speed = (mh->sample[t].c2spd * 8363) / 8448;
q->volume = mh->sample[t].volume;
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->loopend = mh->sample[t].loopend;
q->seekpos = MikMod_ISA;
q->seekpos = mh->sample[t].reserved << 4;
MikMod_ISA+=q->length;
MikMod_ISA=(MikMod_ISA+15)&0xfffffff0; /* normalize */
/* Sanity checks to make sure samples are bounded within the file. */
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 */
q->flags = SF_SIGNED;
if(q->loopend && q->loopend != 0xffff)
q->flags|=SF_LOOP;
if(q->loopend && q->loopend != 0xffff && q->loopstart < q->length) {
q->flags|=SF_LOOP;
if (q->loopend > q->length)
q->loopend = q->length;
}
else
q->loopstart = q->loopend = 0;
}
return 1;
}

View file

@ -20,8 +20,6 @@
/*==============================================================================
$Id$
Ultratracker (ULT) module loader
==============================================================================*/
@ -183,17 +181,19 @@ static int ULT_Load(int curious)
}
q->samplename=DupStr(s.samplename,32,1);
/* The correct formula for the coefficient would be
pow(2,(double)s.finetume/OCTAVE/32768), but to avoid floating point
here, we'll use a first order approximation here.
/* The correct formula would be
s.speed * pow(2, (double)s.finetune / (OCTAVE * 32768))
but to avoid libm, we'll use a first order approximation.
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->volume = s.volume>>2;
q->loopstart = s.loopstart;
q->loopend = s.loopend;
q->flags = SF_SIGNED;
if(s.flags&ULTS_LOOP) q->flags|=SF_LOOP;
else q->loopstart = q->loopend = 0;
if(s.flags&ULTS_16BITS) {
s.sizeend+=(s.sizeend-s.sizestart);
s.sizestart<<=1;
@ -246,6 +246,11 @@ static int ULT_Load(int curious)
for(t=0;t<of.numtrk;t++) {
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();
while(row<64) {
@ -261,14 +266,22 @@ static int ULT_Load(int curious)
int offset;
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
Thomas Neumann */
eff = ev.eff>>4;
if (continuePortaToNote && (eff != 0x3) && ((ev.eff & 0xf) != 0x3))
UniEffect(UNI_ITEFFECTG, 0);
switch(eff) {
case 0x3: /* tone portamento */
UniEffect(UNI_ITEFFECTG,ev.dat2);
continuePortaToNote = 1;
break;
case 0x5:
break;
@ -293,6 +306,7 @@ static int ULT_Load(int curious)
switch(eff) {
case 0x3: /* tone portamento */
UniEffect(UNI_ITEFFECTG,ev.dat1);
continuePortaToNote = 1;
break;
case 0x5:
break;
@ -344,5 +358,4 @@ MIKMODAPI MLOADER load_ult={
ULT_LoadTitle
};
/* ex:set ts=4: */

View file

@ -29,12 +29,7 @@
*
* UPKG parsing partially based on Unreal Media Ripper (UMR) v0.3
* by Andy Ward <wardwh@swbell.net>, with additional updates
* by O. Sezer - see git repo at https://github.com/sezero/umr/
*
* 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.
* by O. Sezer - see git repo at https://github.com/sezero/umr.git
*/
#ifdef HAVE_CONFIG_H
@ -79,11 +74,10 @@ struct upkg_hdr {
ULONG guid[4];
SLONG generation_count;
#define UPKG_HDR_SIZE 64 /* 64 bytes up until here */
/*struct _genhist *gen;*/
struct _genhist *gen;
};
/* 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 * (sizeof(struct upkg_hdr) == UPKG_HDR_SIZE) - 1];
typedef int _check_hdrsize[2 * (offsetof(struct upkg_hdr, gen) == UPKG_HDR_SIZE) - 1];
/*========== Supported content types */
@ -145,6 +139,7 @@ static int get_objtype (SLONG ofs, int type)
{
char sig[16];
_retry:
memset(sig, 0, sizeof(sig));
_mm_fseek(modreader, ofs, SEEK_SET);
_mm_read_UBYTES(sig, 16, modreader);
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,
int idx, char *out)
int idx, char *out, long end)
{
int i, s;
long l;
char buf[64];
if (idx >= hdr->name_count) return -1;
buf[63] = '\0';
memset(buf, 0, 64);
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_read_UBYTES(buf, 63, modreader);
if (hdr->file_version >= 64) {
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 */
} else {
l += (long)strlen(buf);
@ -244,6 +240,12 @@ static int probe_umx (const struct upkg_hdr *hdr,
_mm_fseek(modreader, 0, SEEK_END);
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
* by parsing the exports table. The umx files should
* 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 (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++) {
if (!strcasecmp(buf, mustype[i])) {
t = i;
@ -282,33 +284,34 @@ static int probe_umx (const struct upkg_hdr *hdr,
return t;
}
static SLONG probe_header (void *header)
static SLONG probe_header (struct upkg_hdr *hdr)
{
struct upkg_hdr *hdr;
unsigned char *p;
ULONG *swp;
int i;
hdr->tag = _mm_read_I_ULONG(modreader);
hdr->file_version = _mm_read_I_SLONG(modreader);
hdr->pkg_flags = _mm_read_I_ULONG(modreader);
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 */
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 (_mm_eof(modreader)) return -1;
if (hdr->tag != UPKG_HDR_TAG) {
return -1;
}
if (hdr->name_count < 0 ||
hdr->name_offset < 0 ||
hdr->export_count < 0 ||
hdr->export_offset < 0 ||
hdr->import_count < 0 ||
hdr->import_offset < 0 ) {
hdr->name_offset < 36 ||
hdr->export_offset < 36 ||
hdr->import_offset < 36 ) {
return -1;
}
#if 1 /* no need being overzealous */
return 0;
#else
switch (hdr->file_version) {
case 35: case 37: /* Unreal beta - */
case 40: case 41: /* 1998 */
@ -324,30 +327,20 @@ static SLONG probe_header (void *header)
}
return -1;
#endif /* #if 0 */
}
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))
return -1;
if (probe_header(header) < 0)
memset(&header, 0, sizeof(header));
if (probe_header(&header) < 0)
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 */
/* 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().
*/
typedef struct _umx_info {
int type;
SLONG ofs, size;
MLOADER* loader;
} umx_info;
static umx_info *umx_data = NULL;
static int UMX_Test(void)
{
int type;
SLONG ofs = 0, size = 0;
if (umx_data) {
#ifdef MIKMOD_DEBUG
#ifdef MIKMOD_DEBUG
fprintf(stderr, "UMX_Test called while a previous instance is active\n");
#endif
#endif
MikMod_free(umx_data);
umx_data = NULL;
}

View file

@ -201,7 +201,7 @@ static UBYTE* readtrack(void)
opcode++;
}
if((!opcode)||(opcode>=UNI_LAST)) {
if((!opcode)||(opcode>=UNI_FORMAT_LAST)) {
MikMod_free(t);
return NULL;
}
@ -477,14 +477,23 @@ static int loadsmp5(void)
/* convert flags */
q->flags=0;
if(s->flags&128) q->flags|=SF_REVERSE;
if(s->flags& 64) q->flags|=SF_SUSTAIN;
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;
if (universion < 5) {
/* UN04 flags, as suggested by Thomas Neumann */
if(s->flags& 64) q->flags|=SF_OWNPAN;
if(s->flags& 32) q->flags|=SF_SIGNED;
if(s->flags& 16) q->flags|=SF_BIDI;
if(s->flags& 8) q->flags|=SF_LOOP;
if(s->flags& 4) q->flags|=SF_DELTA;
} 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;
@ -574,6 +583,8 @@ static int UNI_Load(int curious)
of.bpmlimit=32;
of.songname=readstring();
if(!of.songname)
of.songname=MikMod_strdup("");
if(universion<0x102)
oldtype=readstring();
if(oldtype) {
@ -698,13 +709,16 @@ static CHAR *UNI_LoadTitle(void)
{
UBYTE ver;
int posit[3]={304,306,26};
CHAR *title;
_mm_fseek(modreader,3,SEEK_SET);
ver=_mm_read_UBYTE(modreader);
if(ver=='N') ver='6';
_mm_fseek(modreader,posit[ver-'4'],SEEK_SET);
return readstring();
title=readstring();
if(!title) title=MikMod_strdup("");
return title;
}
/*========== Loader information */

View file

@ -73,7 +73,8 @@ typedef struct XMINSTHEADER {
ULONG ssize;
} XMINSTHEADER;
#define XMENVCNT (12*2)
#define XMENVPTS (12)
#define XMENVCNT (XMENVPTS*2)
#define XMNOTECNT (8*OCTAVE)
typedef struct XMPATCHHEADER {
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)
{
long filend,ck;
@ -513,10 +520,10 @@ static int LoadInstruments(void)
/* we can't trust the envelope point count here, as some
modules have incorrect values (K_OSPACE.XM reports 32 volume
points, for example). */
if(pth.volpts>XMENVCNT/2) pth.volpts=XMENVCNT/2;
if(pth.panpts>XMENVCNT/2) pth.panpts=XMENVCNT/2;
if(pth.volpts>XMENVPTS) pth.volpts=XMENVPTS;
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(wh);wh=NULL;
_mm_errno = MMERR_LOADING_SAMPLEINFO;
@ -529,7 +536,7 @@ static int LoadInstruments(void)
#if defined __STDC__ || defined _MSC_VER || defined __WATCOMC__ || defined MPW_C
#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].val = pth. name##env[(u << 1)+ 1]; \
} \
@ -542,14 +549,14 @@ static int LoadInstruments(void)
d-> name##pts=pth. name##pts; \
\
/* scale envelope */ \
for (p=0;p<XMENVCNT/2;p++) \
for (p = 0; p < XMENVPTS; p++) \
d-> name##env[p].val<<=2; \
\
if ((d-> name##flg&EF_ON)&&(d-> name##pts<2)) \
d-> name##flg&=~EF_ON
#else
#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].val = pth. name/**/env[(u << 1)+ 1]; \
} \
@ -563,7 +570,7 @@ static int LoadInstruments(void)
d-> name/**/pts=pth. name/**/pts; \
\
/* scale envelope */ \
for (p=0;p<XMENVCNT/2;p++) \
for (p = 0; p < XMENVPTS; p++) \
d-> name/**/env[p].val<<=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);
nextwav[of.numsmp+u]=next;
next+=s->length;
if(IsSamplePacked())
next+=((s->length + 1) >> 1) + 16;
else
next+=s->length;
}
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&0x2) q->flags|=SF_BIDI;
if(s->type&0x10) q->flags|=SF_16BITS;
if(IsSamplePacked()) {
q->flags &= ~SF_DELTA;
q->flags |= SF_ADPCM4;
}
}
d=of.instruments;

View file

@ -187,7 +187,7 @@ MIKMODAPI CHAR* MikMod_InfoDriver(void)
MUTEX_LOCK(lists);
/* compute size of buffer */
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((list=(CHAR*)MikMod_malloc(len*sizeof(CHAR))) != NULL) {
@ -195,7 +195,8 @@ MIKMODAPI CHAR* MikMod_InfoDriver(void)
list[0] = 0;
/* list all registered device drivers : */
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);

View file

@ -45,6 +45,7 @@ static int curfile = 0, direction = DIR_NEXT, entries = 0;
/* list of the mod files */
static char **file_pt;
static int inited = 0;
/* The MP3 audio buffer which we will use as heap memory */
static unsigned char* audio_buffer;
@ -532,7 +533,7 @@ static void applysettings(void)
}
#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];
// MikMod_Reset(""); BROKEN!
rb->pcm_play_stop();
@ -993,6 +994,8 @@ enum plugin_status plugin_start(const void* parameter)
return PLUGIN_ERROR;
}
inited = 1;
do
{
retval = playfile(np_file);

View file

@ -41,7 +41,7 @@ extern "C" {
*
* ========== NOTE TO WINDOWS DEVELOPERS:
* 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
* will be assumed.
*/
@ -76,7 +76,7 @@ extern "C" {
#define LIBMIKMOD_VERSION_MAJOR 3L
#define LIBMIKMOD_VERSION_MINOR 3L
#define LIBMIKMOD_REVISION 11L
#define LIBMIKMOD_REVISION 12L
#define LIBMIKMOD_VERSION \
((LIBMIKMOD_VERSION_MAJOR<<16)| \
@ -89,7 +89,7 @@ MIKMODAPI extern long MikMod_GetVersion(void);
* ========== Dependency platform headers
*/
#ifdef _WIN32
#if defined(_WIN32)||defined(__CYGWIN__)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
@ -136,10 +136,8 @@ typedef unsigned char UBYTE;
#endif
/* 2 bytes, signed and unsigned: */
#if !(defined __LCC__ && defined _WIN32)
typedef signed short int SWORD;
#endif
#if !((defined __LCC__ && defined _WIN32) || defined(_MIKMOD_AMIGA))
#if !defined(_MIKMOD_AMIGA)
typedef unsigned short int UWORD;
#endif
@ -147,13 +145,13 @@ typedef unsigned short int UWORD;
#if defined(_LP64) || defined(__LP64__) || defined(__arch64__) || defined(__alpha) || defined(__x86_64) || defined(__powerpc64__)
/* 64 bit architectures: */
typedef signed int SLONG;
#if !(defined(_WIN32) || defined(_MIKMOD_AMIGA))
#if !defined(_MIKMOD_AMIGA)
typedef unsigned int ULONG;
#endif
#else /* 32 bit architectures: */
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;
#endif
#endif
@ -254,14 +252,14 @@ enum {
MMERR_MAC_SPEED,
MMERR_MAC_START,
MMERR_OSX_UNKNOWN_DEVICE,
MMERR_OSX_BAD_PROPERTY,
MMERR_OSX_UNKNOWN_DEVICE, /* obsolete */
MMERR_OSX_BAD_PROPERTY, /* obsolete */
MMERR_OSX_UNSUPPORTED_FORMAT,
MMERR_OSX_SET_STEREO,
MMERR_OSX_BUFFER_ALLOC,
MMERR_OSX_ADD_IO_PROC,
MMERR_OSX_SET_STEREO, /* obsolete */
MMERR_OSX_BUFFER_ALLOC, /* obsolete */
MMERR_OSX_ADD_IO_PROC, /* obsolete */
MMERR_OSX_DEVICE_START,
MMERR_OSX_PTHREAD,
MMERR_OSX_PTHREAD, /* obsolete */
MMERR_DOSWSS_STARTDMA,
MMERR_DOSSB_STARTDMA,
@ -376,8 +374,9 @@ typedef struct MWRITER {
#define SF_BIG_ENDIAN 0x0008
#define SF_DELTA 0x0010
#define SF_ITPACKED 0x0020
#define SF_ADPCM4 0x0040
#define SF_FORMATMASK 0x003F
#define SF_FORMATMASK 0x007F
/* General Playback flags */
@ -551,6 +550,7 @@ struct MP_VOICE;
#define UF_FT2QUIRKS 0x0200 /* emulate some FT2 replay quirks */
#define UF_PANNING 0x0400 /* module uses panning effects or have
non-tracker default initial panning */
#define UF_FARTEMPO 0x0800 /* Module uses Farandole tempo calculations */
typedef struct MODULE {
/* general module information */

View file

@ -70,14 +70,11 @@ typedef long long SLONGLONG;
#endif
typedef int __s64_typetest [(sizeof(SLONGLONG)==8) * 2 - 1];
/* pointer-sized signed int (ssize_t/intptr_t) : */
#if defined(_WIN64) /* win64 is LLP64, not LP64 */
typedef long long SINTPTR_T;
#else
/* long should be pointer-sized for all others : */
typedef long SINTPTR_T;
/* signed size type (ssize_t) */
#if !defined(_WIN32) /* Win32 SDK has SSIZE_T */
typedef long SSIZE_T;
#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 */
@ -106,7 +103,7 @@ extern MikMod_handler_t _mm_errorhandler;
if(_mm_mutex_##name)\
DosReleaseMutexSem(_mm_mutex_##name)
#elif defined(_WIN32)
#elif defined(_WIN32)||defined(__CYGWIN__)
#include <windows.h>
#define DECLARE_MUTEX(name) \
extern HANDLE _mm_mutex_##name
@ -338,6 +335,35 @@ enum {
/* Oktalyzer effects */
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
};
@ -503,6 +529,16 @@ typedef struct MP_CONTROL {
UBYTE s3mrtgspeed;/* last used retrig speed */
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 wavecontrol;
@ -533,7 +569,8 @@ typedef struct MP_CONTROL {
SBYTE panbspd; /* "" speed */
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 voldata; /* Volume Column Data Memory */
@ -748,7 +785,7 @@ extern MikMod_callback_t vc_callback;
#if defined(_WIN64)
# if defined(_MSC_VER)
# define IS_ALIGNED_16(ptr) (!((__int64)(ptr) & 15i64))
# else /* GCC, LCC, .. */
# else /* GCC, etc. */
# define IS_ALIGNED_16(ptr) (!((long long)(ptr) & 15LL))
# endif
#else /* long cast should be OK for all else */
@ -860,7 +897,7 @@ void MikMod_afree(void *); /* frees if ptr != NULL */
#endif
#else /* NO SIMD */
#define MikMod_amalloc MikMod_malloc
#define MikMod_amalloc(s) MikMod_calloc(1,(s))
#define MikMod_afree MikMod_free
#endif

View file

@ -115,18 +115,20 @@ MIKMODAPI void MikMod_RegisterLoader(struct MLOADER* ldr)
int ReadComment(UWORD 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);
/* translate IT linefeeds */
for(i=0;i<len;i++)
if(of.comment[i]=='\r') of.comment[i]='\n';
of.comment[len]=0; /* just in case */
ptr=of.comment;
while(*ptr) {
if(*ptr=='\r') *ptr='\n';
++ptr;
}
}
if(!of.comment[0]) {
if(of.comment && !of.comment[0]) {
MikMod_free(of.comment);
of.comment=NULL;
}
@ -142,16 +144,17 @@ int ReadLinedComment(UWORD len,UWORD linelen)
if (!linelen) return 0;
if (!len) return 1;
if (!(buf = (CHAR *) MikMod_malloc(len))) return 0;
numlines = (len + linelen - 1) / linelen;
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);
return 0;
}
_mm_read_UBYTES(buf,len,modreader);
storage[cnt] = 0;
for (line = 0, fpos = 0, cpos = 0; line < numlines; line++, fpos += linelen, cpos += (linelen + 1))
{
cnt = len - fpos;

View file

@ -182,9 +182,12 @@ void S3MIT_ProcessCmd(UBYTE cmd, UBYTE inf, unsigned int flags)
UniEffect(UNI_ITEFFECTG,inf);
break;
case 8: /* Hxy vibrato */
if (flags & S3MIT_OLDSTYLE)
UniPTEffect(0x4,inf);
else
if (flags & S3MIT_OLDSTYLE) {
if (flags & S3MIT_IT)
UniEffect(UNI_ITEFFECTH_OLD,inf);
else
UniEffect(UNI_S3MEFFECTH,inf);
} else
UniEffect(UNI_ITEFFECTH,inf);
break;
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);
break;
case 0xb: /* Kxy Dual command H00 & Dxy */
if (flags & S3MIT_OLDSTYLE)
UniPTEffect(0x4,0);
else
if (flags & S3MIT_OLDSTYLE) {
if (flags & S3MIT_IT)
UniEffect(UNI_ITEFFECTH_OLD,0);
else
UniEffect(UNI_S3MEFFECTH,0);
} else
UniEffect(UNI_ITEFFECTH,0);
UniEffect(UNI_S3MEFFECTD,inf);
break;
@ -211,7 +217,9 @@ void S3MIT_ProcessCmd(UBYTE cmd, UBYTE inf, unsigned int flags)
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 0xd: /* Mxx Set Channel Volume */
UniEffect(UNI_ITEFFECTM,inf);
/* Ignore invalid values > 64. */
if (inf <= 0x40)
UniEffect(UNI_ITEFFECTM,inf);
break;
case 0xe: /* Nxy Slide Channel Volume */
UniEffect(UNI_ITEFFECTN,inf);
@ -259,9 +267,12 @@ void S3MIT_ProcessCmd(UBYTE cmd, UBYTE inf, unsigned int flags)
}
break;
case 0x15: /* Uxy Fine Vibrato speed x, depth y */
if(flags & S3MIT_OLDSTYLE)
UniEffect(UNI_S3MEFFECTU,inf);
else
if(flags & S3MIT_OLDSTYLE) {
if (flags & S3MIT_IT)
UniEffect(UNI_ITEFFECTU_OLD,inf);
else
UniEffect(UNI_S3MEFFECTU,inf);
} else
UniEffect(UNI_ITEFFECTU,inf);
break;
case 0x16: /* Vxx Set Global Volume */

View file

@ -20,8 +20,6 @@
/*==============================================================================
$Id$
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 */
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 */
@ -134,8 +137,8 @@ CHAR *MikMod_strdup(const CHAR *s)
if (!s) return NULL;
l = strlen(s) + 1;
d = (CHAR *) MikMod_calloc(1, l * sizeof(CHAR));
if (d) strcpy(d, s);
d = (CHAR *) MikMod_malloc(l);
if (d) memcpy(d, s, l);
return d;
}

View file

@ -202,14 +202,14 @@ static const char *_mm_errmsg[MMERR_MAX+1] =
/* MacOS X/Darwin driver errors */
#ifdef DRV_OSX
"Unknown device",
"Bad property",
_mmerr_invalid,
_mmerr_invalid,
"Could not set playback format",
"Could not set mono/stereo setting",
"Could not create playback buffers",
"Could not create playback thread",
_mmerr_invalid,
_mmerr_invalid,
_mmerr_invalid,
"Could not start audio device",
"Could not create buffer thread",
_mmerr_invalid,
#else
_mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
_mmerr_invalid, _mmerr_invalid, _mmerr_invalid,

File diff suppressed because it is too large Load diff

View file

@ -100,6 +100,27 @@ const UWORD unioperands[UNI_LAST] = {
0, /* UNI_MEDEFFECTF2 */
0, /* UNI_MEDEFFECTF3 */
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
@ -262,7 +283,7 @@ void UniNewline(void)
unibuf[lastp]+=0x20;
unipc = unitt+1;
} else {
if (UniExpand(unitt-unipc)) {
if (UniExpand(len)) {
/* current and previous row aren't equal... update the pointers */
unibuf[unitt] = len;
lastp = unitt;

View file

@ -20,8 +20,6 @@
/*==============================================================================
$Id$
Routines for loading samples. The sample loader utilizes the routines
provided by the "registered" sample loader.
@ -56,7 +54,7 @@ typedef struct ITPACK {
int SL_Init(SAMPLOAD* s)
{
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;
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);
}
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;
SWORD *wptr = (SWORD*)buffer;
@ -231,6 +229,10 @@ static int SL_LoadInternal(void* buffer,UWORD infmt,UWORD outfmt,int scalefactor
ITPACK status;
UWORD incnt = 0;
SBYTE compressionTable[16];
SWORD adpcmDelta = 0;
int hasTable = 0;
status.buf = 0;
status.last = 0;
status.bufbits = 0;
@ -260,6 +262,22 @@ static int SL_LoadInternal(void* buffer,UWORD infmt,UWORD outfmt,int scalefactor
return 1;
}
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 {
if(infmt&SF_16BITS) {
if(_mm_eof(reader)) {
@ -368,7 +386,7 @@ SAMPLOAD* SL_RegisterSample(SAMPLE* s,int type,MREADER* reader)
return NULL;
/* 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) {
while(cruise->next) cruise=cruise->next;

View file

@ -20,19 +20,14 @@
/*==============================================================================
$Id$
Sample mixing routines, using a 32 bits mixing buffer.
==============================================================================*/
/*
Optional features include:
(a) 4-step reverb (for 16 bit output only)
(b) Interpolation of sample data during mixing
(c) Dolby Surround Sound
*/
==============================================================================*/
#ifdef HAVE_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(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: */
SWORD sample;
@ -145,7 +140,7 @@ static SINTPTR_T MixSIMDMonoNormal(const SWORD* srce,SLONG* dest,SINTPTR_T idx,S
}
# 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 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 */
/* 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)
{
#if defined HAVE_ALTIVEC || defined HAVE_SSE2
@ -1029,9 +1024,10 @@ static void AddChannel(SLONG* ptr,NATIVE todo)
(vnf->flags&SF_LOOP)?idxlend:idxsize;
/* 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;
else {
} else {
done=MIN((end-vnf->current)/vnf->increment+1,todo);
if(done<0) done=0;
}

View file

@ -20,20 +20,14 @@
/*==============================================================================
$Id$
High-quality sample mixing routines, using a 32 bits mixing buffer,
interpolation, and sample smoothing to improve sound quality and remove
clicks.
==============================================================================*/
/*
Future Additions:
Low-Pass filter to remove annoying staticy buzz.
- Low-Pass filter to remove annoying staticy buzz.
*/
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -1074,9 +1068,10 @@ static void AddChannel(SLONG* ptr,NATIVE todo)
(vnf->flags&SF_LOOP)?idxlend:idxsize;
/* 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;
else {
} else {
done=MIN((end-vnf->current)/vnf->increment+1,todo);
if(done<0) done=0;
}

View file

@ -20,10 +20,8 @@
/*==============================================================================
$Id$
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.
==============================================================================*/