📄 load_xm.c
字号:
ENVPT *prev;
/* Some broken XM editing program will only save the low byte
of the position value. Try to compensate by adding the
missing high byte. */
prev = cur++;
old = prev->pos;
for (u = 1; u < pts; u++, prev++, cur++) {
if (cur->pos < prev->pos) {
if (cur->pos < 0x100) {
if (cur->pos > old) /* same hex century */
tmp = cur->pos + (prev->pos - old);
else
tmp = cur->pos | ((prev->pos + 0x100) & 0xff00);
old = cur->pos;
cur->pos = tmp;
#ifdef MIKMOD_DEBUG
fprintf(stderr, "\rbroken envelope position(%d/%d), %d %d -> %d\n",
u, pts, prev->pos, old, cur->pos);
#endif
} else {
#ifdef MIKMOD_DEBUG
/* different brokenness style... fix unknown */
fprintf(stderr, "\rbroken envelope position(%d/%d), %d %d\n",
u, pts, old, cur->pos);
#endif
old = cur->pos;
}
} else
old = cur->pos;
}
}
static BOOL LoadInstruments(void)
{
int t,u;
INSTRUMENT *d;
ULONG next=0;
UWORD wavcnt=0;
if(!AllocInstruments()) return 0;
d=of.instruments;
for(t=0;t<of.numins;t++,d++) {
XMINSTHEADER ih;
long headend;
memset(d->samplenumber,0xff,INSTNOTES*sizeof(UWORD));
/* read instrument header */
headend = _mm_ftell(modreader);
ih.size = _mm_read_I_ULONG(modreader);
headend += ih.size;
_mm_read_string(ih.name, 22, modreader);
ih.type = _mm_read_UBYTE(modreader);
ih.numsmp = _mm_read_I_UWORD(modreader);
d->insname = DupStr(ih.name,22,1);
if((SWORD)ih.size>29) {
ih.ssize = _mm_read_I_ULONG(modreader);
if(((SWORD)ih.numsmp>0)&&(ih.numsmp<=XMNOTECNT)) {
XMPATCHHEADER pth;
int p;
_mm_read_UBYTES (pth.what,XMNOTECNT,modreader);
_mm_read_I_UWORDS (pth.volenv, XMENVCNT, modreader);
_mm_read_I_UWORDS (pth.panenv, XMENVCNT, modreader);
pth.volpts = _mm_read_UBYTE(modreader);
pth.panpts = _mm_read_UBYTE(modreader);
pth.volsus = _mm_read_UBYTE(modreader);
pth.volbeg = _mm_read_UBYTE(modreader);
pth.volend = _mm_read_UBYTE(modreader);
pth.pansus = _mm_read_UBYTE(modreader);
pth.panbeg = _mm_read_UBYTE(modreader);
pth.panend = _mm_read_UBYTE(modreader);
pth.volflg = _mm_read_UBYTE(modreader);
pth.panflg = _mm_read_UBYTE(modreader);
pth.vibflg = _mm_read_UBYTE(modreader);
pth.vibsweep = _mm_read_UBYTE(modreader);
pth.vibdepth = _mm_read_UBYTE(modreader);
pth.vibrate = _mm_read_UBYTE(modreader);
pth.volfade = _mm_read_I_UWORD(modreader);
/* read the remainder of the header
(2 bytes for 1.03, 22 for 1.04) */
for(u=headend-_mm_ftell(modreader);u;u--) _mm_read_UBYTE(modreader);
/* 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((_mm_eof(modreader))||(pth.volpts>XMENVCNT/2)||(pth.panpts>XMENVCNT/2)) {
if(nextwav) { free(nextwav);nextwav=NULL; }
if(wh) { free(wh);wh=NULL; }
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
for(u=0;u<XMNOTECNT;u++)
d->samplenumber[u]=pth.what[u]+of.numsmp;
d->volfade = pth.volfade;
#if defined __STDC__ || defined _MSC_VER || defined MPW_C
#define XM_ProcessEnvelope(name) \
for (u = 0; u < (XMENVCNT >> 1); u++) { \
d-> name##env[u].pos = pth. name##env[u << 1]; \
d-> name##env[u].val = pth. name##env[(u << 1)+ 1]; \
} \
if (pth. name##flg&1) d-> name##flg|=EF_ON; \
if (pth. name##flg&2) d-> name##flg|=EF_SUSTAIN; \
if (pth. name##flg&4) d-> name##flg|=EF_LOOP; \
d-> name##susbeg=d-> name##susend=pth. name##sus; \
d-> name##beg=pth. name##beg; \
d-> name##end=pth. name##end; \
d-> name##pts=pth. name##pts; \
\
/* scale envelope */ \
for (p=0;p<XMENVCNT/2;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++) { \
d-> name/**/env[u].pos = pth. name/**/env[u << 1]; \
d-> name/**/env[u].val = pth. name/**/env[(u << 1)+ 1]; \
} \
if (pth. name/**/flg&1) d-> name/**/flg|=EF_ON; \
if (pth. name/**/flg&2) d-> name/**/flg|=EF_SUSTAIN; \
if (pth. name/**/flg&4) d-> name/**/flg|=EF_LOOP; \
d-> name/**/susbeg=d-> name/**/susend= \
pth. name/**/sus; \
d-> name/**/beg=pth. name/**/beg; \
d-> name/**/end=pth. name/**/end; \
d-> name/**/pts=pth. name/**/pts; \
\
/* scale envelope */ \
for (p=0;p<XMENVCNT/2;p++) \
d-> name/**/env[p].val<<=2; \
\
if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \
d-> name/**/flg&=~EF_ON
#endif
XM_ProcessEnvelope(vol);
XM_ProcessEnvelope(pan);
#undef XM_ProcessEnvelope
if (d->volflg & EF_ON)
FixEnvelope(d->volenv, d->volpts);
if (d->panflg & EF_ON)
FixEnvelope(d->panenv, d->panpts);
/* Samples are stored outside the instrument struct now, so we
have to load them all into a temp area, count the of.numsmp
along the way and then do an AllocSamples() and move
everything over */
if(mh->version>0x0103) next = 0;
for(u=0;u<ih.numsmp;u++,s++) {
/* Allocate more room for sample information if necessary */
if(of.numsmp+u==wavcnt) {
wavcnt+=XM_SMPINCR;
if(!(nextwav=realloc(nextwav,wavcnt*sizeof(ULONG)))){
if(wh) { free(wh);wh=NULL; }
_mm_errno = MMERR_OUT_OF_MEMORY;
return 0;
}
if(!(wh=realloc(wh,wavcnt*sizeof(XMWAVHEADER)))) {
free(nextwav);nextwav=NULL;
_mm_errno = MMERR_OUT_OF_MEMORY;
return 0;
}
s=wh+(wavcnt-XM_SMPINCR);
}
s->length =_mm_read_I_ULONG (modreader);
s->loopstart =_mm_read_I_ULONG (modreader);
s->looplength =_mm_read_I_ULONG (modreader);
s->volume =_mm_read_UBYTE (modreader);
s->finetune =_mm_read_SBYTE (modreader);
s->type =_mm_read_UBYTE (modreader);
s->panning =_mm_read_UBYTE (modreader);
s->relnote =_mm_read_SBYTE (modreader);
s->vibtype = pth.vibflg;
s->vibsweep = pth.vibsweep;
s->vibdepth = pth.vibdepth*4;
s->vibrate = pth.vibrate;
s->reserved =_mm_read_UBYTE (modreader);
_mm_read_string(s->samplename, 22, modreader);
nextwav[of.numsmp+u]=next;
next+=s->length;
if(_mm_eof(modreader)) {
free(nextwav);free(wh);
nextwav=NULL;wh=NULL;
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
}
if(mh->version>0x0103) {
for(u=0;u<ih.numsmp;u++)
nextwav[of.numsmp++]+=_mm_ftell(modreader);
_mm_fseek(modreader,next,SEEK_CUR);
} else
of.numsmp+=ih.numsmp;
} else {
/* read the remainder of the header */
for(u=headend-_mm_ftell(modreader);u;u--) _mm_read_UBYTE(modreader);
if(_mm_eof(modreader)) {
free(nextwav);free(wh);
nextwav=NULL;wh=NULL;
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
}
}
}
/* sanity check */
if(!of.numsmp) {
if(nextwav) { free(nextwav);nextwav=NULL; }
if(wh) { free(wh);wh=NULL; }
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
return 1;
}
BOOL XM_Load(BOOL curious)
{
INSTRUMENT *d;
SAMPLE *q;
int t,u;
BOOL dummypat=0;
char tracker[21],modtype[60];
/* try to read module header */
_mm_read_string(mh->id,17,modreader);
_mm_read_string(mh->songname,21,modreader);
_mm_read_string(mh->trackername,20,modreader);
mh->version =_mm_read_I_UWORD(modreader);
if((mh->version<0x102)||(mh->version>0x104)) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
mh->headersize =_mm_read_I_ULONG(modreader);
mh->songlength =_mm_read_I_UWORD(modreader);
mh->restart =_mm_read_I_UWORD(modreader);
mh->numchn =_mm_read_I_UWORD(modreader);
mh->numpat =_mm_read_I_UWORD(modreader);
mh->numins =_mm_read_I_UWORD(modreader);
mh->flags =_mm_read_I_UWORD(modreader);
mh->tempo =_mm_read_I_UWORD(modreader);
mh->bpm =_mm_read_I_UWORD(modreader);
if(!mh->bpm) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
_mm_read_UBYTES(mh->orders,256,modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* set module variables */
of.initspeed = mh->tempo;
of.inittempo = mh->bpm;
strncpy(tracker,mh->trackername,20);tracker[20]=0;
for(t=20;(tracker[t]<=' ')&&(t>=0);t--) tracker[t]=0;
/* some modules have the tracker name empty */
if (!tracker[0])
strcpy(tracker,"Unknown tracker");
#ifdef HAVE_SNPRINTF
snprintf(modtype,60,"%s (XM format %d.%02d)",
tracker,mh->version>>8,mh->version&0xff);
#else
sprintf(modtype,"%s (XM format %d.%02d)",
tracker,mh->version>>8,mh->version&0xff);
#endif
of.modtype = strdup(modtype);
of.numchn = mh->numchn;
of.numpat = mh->numpat;
of.numtrk = (UWORD)of.numpat*of.numchn; /* get number of channels */
of.songname = DupStr(mh->songname,20,1);
of.numpos = mh->songlength; /* copy the songlength */
of.reppos = mh->restart<mh->songlength?mh->restart:0;
of.numins = mh->numins;
of.flags |= UF_XMPERIODS | UF_INST | UF_NOWRAP | UF_FT2QUIRKS |
UF_PANNING;
if(mh->flags&1) of.flags |= UF_LINEAR;
of.bpmlimit = 32;
memset(of.chanvol,64,of.numchn); /* store channel volumes */
if(!AllocPositions(of.numpos+1)) return 0;
for(t=0;t<of.numpos;t++)
of.positions[t]=mh->orders[t];
/* We have to check for any pattern numbers in the order list greater than
the number of patterns total. If one or more is found, we set it equal to
the pattern total and make a dummy pattern to workaround the problem */
for(t=0;t<of.numpos;t++) {
if(of.positions[t]>=of.numpat) {
of.positions[t]=of.numpat;
dummypat=1;
}
}
if(dummypat) {
of.numpat++;of.numtrk+=of.numchn;
}
if(mh->version<0x0104) {
if(!LoadInstruments()) return 0;
if(!LoadPatterns(dummypat)) return 0;
for(t=0;t<of.numsmp;t++)
nextwav[t]+=_mm_ftell(modreader);
} else {
if(!LoadPatterns(dummypat)) return 0;
if(!LoadInstruments()) return 0;
}
if(!AllocSamples()) {
free(nextwav);free(wh);
nextwav=NULL;wh=NULL;
return 0;
}
q = of.samples;
s = wh;
for(u=0;u<of.numsmp;u++,q++,s++) {
q->samplename = DupStr(s->samplename,22,1);
q->length = s->length;
q->loopstart = s->loopstart;
q->loopend = s->loopstart+s->looplength;
q->volume = s->volume;
q->speed = s->finetune+128;
q->panning = s->panning;
q->seekpos = nextwav[u];
q->vibtype = s->vibtype;
q->vibsweep = s->vibsweep;
q->vibdepth = s->vibdepth;
q->vibrate = s->vibrate;
if(s->type & 0x10) {
q->length >>= 1;
q->loopstart >>= 1;
q->loopend >>= 1;
}
q->flags|=SF_OWNPAN|SF_DELTA|SF_SIGNED;
if(s->type&0x3) q->flags|=SF_LOOP;
if(s->type&0x2) q->flags|=SF_BIDI;
if(s->type&0x10) q->flags|=SF_16BITS;
}
d=of.instruments;
s=wh;
for(u=0;u<of.numins;u++,d++)
for(t=0;t<XMNOTECNT;t++) {
if (d->samplenumber[t]>=of.numsmp)
d->samplenote[t]=255;
else {
int note=t+s[d->samplenumber[t]].relnote;
d->samplenote[t]=(note<0)?0:note;
}
}
free(wh);free(nextwav);
wh=NULL;nextwav=NULL;
return 1;
}
CHAR *XM_LoadTitle(void)
{
CHAR s[21];
_mm_fseek(modreader,17,SEEK_SET);
if(!_mm_read_UBYTES(s,21,modreader)) return NULL;
return(DupStr(s,21,1));
}
/*========== Loader information */
MIKMODAPI MLOADER load_xm={
NULL,
"XM",
"XM (FastTracker 2)",
XM_Init,
XM_Test,
XM_Load,
XM_Cleanup,
XM_LoadTitle
};
/* ex:set ts=4: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -