📄 load_stm.c
字号:
/* MikMod sound library (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file AUTHORS for complete list. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*//*============================================================================== $Id: load_stm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $ Screamtracker 2 (STM) module loader==============================================================================*/#ifdef HAVE_CONFIG_H#include "config.h"#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include <stdio.h>#ifdef HAVE_MEMORY_H#include <memory.h>#endif#include <string.h>#include "mikmod_internals.h"#ifdef SUNOSextern int fprintf(FILE *, const char *, ...);#endif/*========== Module structure *//* sample information */typedef struct STMSAMPLE { CHAR filename[12]; UBYTE unused; /* 0x00 */ UBYTE instdisk; /* Instrument disk */ UWORD reserved; UWORD length; /* Sample length */ UWORD loopbeg; /* Loop start point */ UWORD loopend; /* Loop end point */ UBYTE volume; /* Volume */ UBYTE reserved2; UWORD c2spd; /* Good old c2spd */ ULONG reserved3; UWORD isa;} STMSAMPLE;/* header */typedef struct STMHEADER { CHAR songname[20]; CHAR trackername[8]; /* !Scream! for ST 2.xx */ UBYTE unused; /* 0x1A */ UBYTE filetype; /* 1=song, 2=module */ UBYTE ver_major; UBYTE ver_minor; UBYTE inittempo; /* initspeed= stm inittempo>>4 */ UBYTE numpat; /* number of patterns */ UBYTE globalvol; UBYTE reserved[13]; STMSAMPLE sample[31]; /* STM sample data */ UBYTE patorder[128]; /* Docs say 64 - actually 128 */} STMHEADER;typedef struct STMNOTE { UBYTE note,insvol,volcmd,cmdinf;} STMNOTE;/*========== Loader variables */static STMNOTE *stmbuf = NULL;static STMHEADER *mh = NULL;/* tracker identifiers */static CHAR* STM_Version[STM_NTRACKERS] = { "Screamtracker 2", "Converted by MOD2STM (STM format)", "Wuzamod (STM format)"};/*========== Loader code */BOOL STM_Test(void){ UBYTE str[44]; int t; _mm_fseek(modreader,20,SEEK_SET); _mm_read_UBYTES(str,44,modreader); if(str[9]!=2) return 0; /* STM Module = filetype 2 */ /* Prevent false positives for S3M files */ if(!memcmp(str+40,"SCRM",4)) return 0; for (t=0;t<STM_NTRACKERS;t++) if(!memcmp(str,STM_Signatures[t],8)) return 1; return 0;}BOOL STM_Init(void){ if(!(mh=(STMHEADER*)_mm_malloc(sizeof(STMHEADER)))) return 0; if(!(stmbuf=(STMNOTE*)_mm_calloc(64U*4,sizeof(STMNOTE)))) return 0; return 1;}static void STM_Cleanup(void){ _mm_free(mh); _mm_free(stmbuf);}static void STM_ConvertNote(STMNOTE *n){ UBYTE note,ins,vol,cmd,inf; /* extract the various information from the 4 bytes that make up a note */ note = n->note; ins = n->insvol>>3; vol = (n->insvol&7)+((n->volcmd&0x70)>>1); cmd = n->volcmd&15; inf = n->cmdinf; if((ins)&&(ins<32)) UniInstrument(ins-1); /* special values of [SBYTE0] are handled here we have no idea if these strange values will ever be encountered. but it appears as those stms sound correct. */ if((note==254)||(note==252)) { UniPTEffect(0xc,0); /* note cut */ n->volcmd|=0x80; } else /* if note < 251, then all three bytes are stored in the file */ if(note<251) UniNote((((note>>4)+2)*OCTAVE)+(note&0xf)); if((!(n->volcmd&0x80))&&(vol<65)) UniPTEffect(0xc,vol); if(cmd!=255) switch(cmd) { case 1: /* Axx set speed to xx */ UniPTEffect(0xf,inf>>4); break; case 2: /* Bxx position jump */ UniPTEffect(0xb,inf); break; case 3: /* Cxx patternbreak to row xx */ UniPTEffect(0xd,(((inf&0xf0)>>4)*10)+(inf&0xf)); break; case 4: /* Dxy volumeslide */ UniEffect(UNI_S3MEFFECTD,inf); break; case 5: /* Exy toneslide down */ UniEffect(UNI_S3MEFFECTE,inf); break; case 6: /* Fxy toneslide up */ UniEffect(UNI_S3MEFFECTF,inf); break; case 7: /* Gxx Tone portamento,speed xx */ UniPTEffect(0x3,inf); break; case 8: /* Hxy vibrato */ UniPTEffect(0x4,inf); break; case 9: /* Ixy tremor, ontime x, offtime y */ UniEffect(UNI_S3MEFFECTI,inf); break; case 0: /* protracker arpeggio */ if(!inf) break; /* fall through */ case 0xa: /* Jxy arpeggio */ UniPTEffect(0x0,inf); break; case 0xb: /* Kxy Dual command H00 & Dxy */ UniPTEffect(0x4,0); UniEffect(UNI_S3MEFFECTD,inf); break; case 0xc: /* Lxy Dual command G00 & Dxy */ UniPTEffect(0x3,0); UniEffect(UNI_S3MEFFECTD,inf); break; /* Support all these above, since ST2 can LOAD these values but can actually only play up to J - and J is only half-way implemented in ST2 */ case 0x18: /* Xxx amiga panning command 8xx */ UniPTEffect(0x8,inf); of.flags |= UF_PANNING; break; }}static UBYTE *STM_ConvertTrack(STMNOTE *n){ int t; UniReset(); for(t=0;t<64;t++) { STM_ConvertNote(n); UniNewline(); n+=of.numchn; } return UniDup();}static BOOL STM_LoadPatterns(void){ int t,s,tracks=0; if(!AllocPatterns()) return 0; if(!AllocTracks()) return 0; /* Allocate temporary buffer for loading and converting the patterns */ for(t=0;t<of.numpat;t++) { for(s=0;s<(64U*of.numchn);s++) { stmbuf[s].note = _mm_read_UBYTE(modreader); stmbuf[s].insvol = _mm_read_UBYTE(modreader); stmbuf[s].volcmd = _mm_read_UBYTE(modreader); stmbuf[s].cmdinf = _mm_read_UBYTE(modreader); } if(_mm_eof(modreader)) { _mm_errno = MMERR_LOADING_PATTERN; return 0; } for(s=0;s<of.numchn;s++) if(!(of.tracks[tracks++]=STM_ConvertTrack(stmbuf+s))) return 0; } return 1;}BOOL STM_Load(BOOL curious){ int t; ULONG MikMod_ISA; /* We must generate our own ISA, it's not stored in stm */ SAMPLE *q; /* try to read stm header */ _mm_read_string(mh->songname,20,modreader); _mm_read_string(mh->trackername,8,modreader); mh->unused =_mm_read_UBYTE(modreader); mh->filetype =_mm_read_UBYTE(modreader); mh->ver_major =_mm_read_UBYTE(modreader); mh->ver_minor =_mm_read_UBYTE(modreader); mh->inittempo =_mm_read_UBYTE(modreader); if(!mh->inittempo) { _mm_errno=MMERR_NOT_A_MODULE; return 0; } mh->numpat =_mm_read_UBYTE(modreader); mh->globalvol =_mm_read_UBYTE(modreader); _mm_read_UBYTES(mh->reserved,13,modreader); for(t=0;t<31;t++) { STMSAMPLE *s=&mh->sample[t]; /* STM sample data */ _mm_read_string(s->filename,12,modreader); s->unused =_mm_read_UBYTE(modreader); s->instdisk =_mm_read_UBYTE(modreader); s->reserved =_mm_read_I_UWORD(modreader); s->length =_mm_read_I_UWORD(modreader); s->loopbeg =_mm_read_I_UWORD(modreader); s->loopend =_mm_read_I_UWORD(modreader); s->volume =_mm_read_UBYTE(modreader); s->reserved2=_mm_read_UBYTE(modreader); s->c2spd =_mm_read_I_UWORD(modreader); s->reserved3=_mm_read_I_ULONG(modreader); s->isa =_mm_read_I_UWORD(modreader); } _mm_read_UBYTES(mh->patorder,128,modreader); if(_mm_eof(modreader)) { _mm_errno = MMERR_LOADING_HEADER; return 0; } /* set module variables */ for(t=0;t<STM_NTRACKERS;t++) if(!memcmp(mh->trackername,STM_Signatures[t],8)) break; of.modtype = strdup(STM_Version[t]); of.songname = DupStr(mh->songname,20,1); /* make a cstr of songname */ of.numpat = mh->numpat; of.inittempo = 125; /* mh->inittempo+0x1c; */ of.initspeed = mh->inittempo>>4; of.numchn = 4; /* get number of channels */ of.reppos = 0; of.flags |= UF_S3MSLIDES; of.bpmlimit = 32; t=0; if(!AllocPositions(0x80)) return 0; /* 99 terminates the patorder list */ while((mh->patorder[t]<=99)&&(mh->patorder[t]<mh->numpat)) { of.positions[t]=mh->patorder[t]; t++; } if(mh->patorder[t]<=99) t++; 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 */ for(q=of.samples,t=0;t<of.numsmp;t++,q++) { /* load sample info */ q->samplename = DupStr(mh->sample[t].filename,12,1); 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; q->loopstart = mh->sample[t].loopbeg; q->loopend = mh->sample[t].loopend; q->seekpos = MikMod_ISA; MikMod_ISA+=q->length; MikMod_ISA=(MikMod_ISA+15)&0xfffffff0; /* normalize */ /* contrary to the STM specs, sample data is signed */ q->flags = SF_SIGNED; if(q->loopend && q->loopend != 0xffff) q->flags|=SF_LOOP; } return 1;}CHAR *STM_LoadTitle(void){ CHAR s[20]; _mm_fseek(modreader,0,SEEK_SET); if(!_mm_read_UBYTES(s,20,modreader)) return NULL; return(DupStr(s,20,1));}/*========== Loader information */MIKMODAPI MLOADER load_stm={ NULL, "STM", "STM (Scream Tracker)", STM_Init, STM_Test, STM_Load, STM_Cleanup, STM_LoadTitle};/* ex:set ts=4: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -