📄 load_xm.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_xm.c,v 1.2 2004/02/06 19:29:03 raph Exp $ Fasttracker (XM) 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 */typedef struct XMHEADER { CHAR id[17]; /* ID text: 'Extended module: ' */ CHAR songname[21]; /* Module name */ CHAR trackername[20]; /* Tracker name */ UWORD version; /* Version number */ ULONG headersize; /* Header size */ UWORD songlength; /* Song length (in patten order table) */ UWORD restart; /* Restart position */ UWORD numchn; /* Number of channels (2,4,6,8,10,...,32) */ UWORD numpat; /* Number of patterns (max 256) */ UWORD numins; /* Number of instruments (max 128) */ UWORD flags; UWORD tempo; /* Default tempo */ UWORD bpm; /* Default BPM */ UBYTE orders[256]; /* Pattern order table */} XMHEADER;typedef struct XMINSTHEADER { ULONG size; /* Instrument size */ CHAR name[22]; /* Instrument name */ UBYTE type; /* Instrument type (always 0) */ UWORD numsmp; /* Number of samples in instrument */ ULONG ssize;} XMINSTHEADER;#define XMENVCNT (12*2)#define XMNOTECNT (8*OCTAVE)typedef struct XMPATCHHEADER { UBYTE what[XMNOTECNT]; /* Sample number for all notes */ UWORD volenv[XMENVCNT]; /* Points for volume envelope */ UWORD panenv[XMENVCNT]; /* Points for panning envelope */ UBYTE volpts; /* Number of volume points */ UBYTE panpts; /* Number of panning points */ UBYTE volsus; /* Volume sustain point */ UBYTE volbeg; /* Volume loop start point */ UBYTE volend; /* Volume loop end point */ UBYTE pansus; /* Panning sustain point */ UBYTE panbeg; /* Panning loop start point */ UBYTE panend; /* Panning loop end point */ UBYTE volflg; /* Volume type: bit 0: On; 1: Sustain; 2: Loop */ UBYTE panflg; /* Panning type: bit 0: On; 1: Sustain; 2: Loop */ UBYTE vibflg; /* Vibrato type */ UBYTE vibsweep; /* Vibrato sweep */ UBYTE vibdepth; /* Vibrato depth */ UBYTE vibrate; /* Vibrato rate */ UWORD volfade; /* Volume fadeout */} XMPATCHHEADER;typedef struct XMWAVHEADER { ULONG length; /* Sample length */ ULONG loopstart; /* Sample loop start */ ULONG looplength; /* Sample loop length */ UBYTE volume; /* Volume */ SBYTE finetune; /* Finetune (signed byte -128..+127) */ UBYTE type; /* Loop type */ UBYTE panning; /* Panning (0-255) */ SBYTE relnote; /* Relative note number (signed byte) */ UBYTE reserved; CHAR samplename[22]; /* Sample name */ UBYTE vibtype; /* Vibrato type */ UBYTE vibsweep; /* Vibrato sweep */ UBYTE vibdepth; /* Vibrato depth */ UBYTE vibrate; /* Vibrato rate */} XMWAVHEADER;typedef struct XMPATHEADER { ULONG size; /* Pattern header length */ UBYTE packing; /* Packing type (always 0) */ UWORD numrows; /* Number of rows in pattern (1..256) */ SWORD packsize; /* Packed patterndata size */} XMPATHEADER;typedef struct XMNOTE { UBYTE note,ins,vol,eff,dat;} XMNOTE;/*========== Loader variables */static XMNOTE *xmpat=NULL;static XMHEADER *mh=NULL;/* increment unit for sample array reallocation */#define XM_SMPINCR 64static ULONG *nextwav=NULL;static XMWAVHEADER *wh=NULL,*s=NULL;/*========== Loader code */BOOL XM_Test(void){ UBYTE id[38]; if(!_mm_read_UBYTES(id,38,modreader)) return 0; if(memcmp(id,"Extended Module: ",17)) return 0; if(id[37]==0x1a) return 1; return 0;}BOOL XM_Init(void){ if(!(mh=(XMHEADER *)_mm_malloc(sizeof(XMHEADER)))) return 0; return 1;}void XM_Cleanup(void){ _mm_free(mh);}static int XM_ReadNote(XMNOTE* n){ UBYTE cmp,result=1; memset(n,0,sizeof(XMNOTE)); cmp=_mm_read_UBYTE(modreader); if(cmp&0x80) { if(cmp&1) { result++;n->note = _mm_read_UBYTE(modreader); } if(cmp&2) { result++;n->ins = _mm_read_UBYTE(modreader); } if(cmp&4) { result++;n->vol = _mm_read_UBYTE(modreader); } if(cmp&8) { result++;n->eff = _mm_read_UBYTE(modreader); } if(cmp&16) { result++;n->dat = _mm_read_UBYTE(modreader); } } else { n->note = cmp; n->ins = _mm_read_UBYTE(modreader); n->vol = _mm_read_UBYTE(modreader); n->eff = _mm_read_UBYTE(modreader); n->dat = _mm_read_UBYTE(modreader); result += 4; } return result;}static UBYTE* XM_Convert(XMNOTE* xmtrack,UWORD rows){ int t; UBYTE note,ins,vol,eff,dat; UniReset(); for(t=0;t<rows;t++) { note = xmtrack->note; ins = xmtrack->ins; vol = xmtrack->vol; eff = xmtrack->eff; dat = xmtrack->dat; if(note) { if(note>XMNOTECNT) UniEffect(UNI_KEYFADE,0); else UniNote(note-1); } if(ins) UniInstrument(ins-1); switch(vol>>4) { case 0x6: /* volslide down */ if(vol&0xf) UniEffect(UNI_XMEFFECTA,vol&0xf); break; case 0x7: /* volslide up */ if(vol&0xf) UniEffect(UNI_XMEFFECTA,vol<<4); break; /* volume-row fine volume slide is compatible with protracker EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as opposed to 'take the last sliding value'. */ case 0x8: /* finevol down */ UniPTEffect(0xe,0xb0|(vol&0xf)); break; case 0x9: /* finevol up */ UniPTEffect(0xe,0xa0|(vol&0xf)); break; case 0xa: /* set vibrato speed */ UniEffect(UNI_XMEFFECT4,vol<<4); break; case 0xb: /* vibrato */ UniEffect(UNI_XMEFFECT4,vol&0xf); break; case 0xc: /* set panning */ UniPTEffect(0x8,vol<<4); break; case 0xd: /* panning slide left (only slide when data not zero) */ if(vol&0xf) UniEffect(UNI_XMEFFECTP,vol&0xf); break; case 0xe: /* panning slide right (only slide when data not zero) */ if(vol&0xf) UniEffect(UNI_XMEFFECTP,vol<<4); break; case 0xf: /* tone porta */ UniPTEffect(0x3,vol<<4); break; default: if((vol>=0x10)&&(vol<=0x50)) UniPTEffect(0xc,vol-0x10); } switch(eff) { case 0x4: UniEffect(UNI_XMEFFECT4,dat); break; case 0x6: UniEffect(UNI_XMEFFECT6,dat); break; case 0xa: UniEffect(UNI_XMEFFECTA,dat); break; case 0xe: /* Extended effects */ switch(dat>>4) { case 0x1: /* XM fine porta up */ UniEffect(UNI_XMEFFECTE1,dat&0xf); break; case 0x2: /* XM fine porta down */ UniEffect(UNI_XMEFFECTE2,dat&0xf); break; case 0xa: /* XM fine volume up */ UniEffect(UNI_XMEFFECTEA,dat&0xf); break; case 0xb: /* XM fine volume down */ UniEffect(UNI_XMEFFECTEB,dat&0xf); break; default: UniPTEffect(eff,dat); } break; case 'G'-55: /* G - set global volume */ UniEffect(UNI_XMEFFECTG,dat>64?128:dat<<1); break; case 'H'-55: /* H - global volume slide */ UniEffect(UNI_XMEFFECTH,dat); break; case 'K'-55: /* K - keyOff and KeyFade */ UniEffect(UNI_KEYFADE,dat); break; case 'L'-55: /* L - set envelope position */ UniEffect(UNI_XMEFFECTL,dat); break; case 'P'-55: /* P - panning slide */ UniEffect(UNI_XMEFFECTP,dat); break; case 'R'-55: /* R - multi retrig note */ UniEffect(UNI_S3MEFFECTQ,dat); break; case 'T'-55: /* T - Tremor */ UniEffect(UNI_S3MEFFECTI,dat); break; case 'X'-55: switch(dat>>4) { case 1: /* X1 - Extra Fine Porta up */ UniEffect(UNI_XMEFFECTX1,dat&0xf); break; case 2: /* X2 - Extra Fine Porta down */ UniEffect(UNI_XMEFFECTX2,dat&0xf); break; } break; default: if(eff<=0xf) { /* the pattern jump destination is written in decimal, but it seems some poor tracker software writes them in hexadecimal... (sigh) */ if (eff==0xd) /* don't change anything if we're sure it's in hexa */ if ((((dat&0xf0)>>4)<=9)&&((dat&0xf)<=9)) /* otherwise, convert from dec to hex */ dat=(((dat&0xf0)>>4)*10)+(dat&0xf); UniPTEffect(eff,dat); } break; } UniNewline(); xmtrack++; } return UniDup();}static BOOL LoadPatterns(BOOL dummypat){ int t,u,v,numtrk; if(!AllocTracks()) return 0; if(!AllocPatterns()) return 0; numtrk=0; for(t=0;t<mh->numpat;t++) { XMPATHEADER ph; ph.size =_mm_read_I_ULONG(modreader); if (ph.size<(mh->version==0x0102?8:9)) { _mm_errno=MMERR_LOADING_PATTERN; return 0; } ph.packing =_mm_read_UBYTE(modreader); if(ph.packing) { _mm_errno=MMERR_LOADING_PATTERN; return 0; } if(mh->version==0x0102) ph.numrows =_mm_read_UBYTE(modreader)+1; else ph.numrows =_mm_read_I_UWORD(modreader); ph.packsize =_mm_read_I_UWORD(modreader); ph.size-=(mh->version==0x0102?8:9); if(ph.size) _mm_fseek(modreader,ph.size,SEEK_CUR); of.pattrows[t]=ph.numrows; if(ph.numrows) { if(!(xmpat=(XMNOTE*)_mm_calloc(ph.numrows*of.numchn,sizeof(XMNOTE)))) return 0; /* when packsize is 0, don't try to load a pattern.. it's empty. */ if(ph.packsize) for(u=0;u<ph.numrows;u++) for(v=0;v<of.numchn;v++) { if(!ph.packsize) break; ph.packsize-=XM_ReadNote(&xmpat[(v*ph.numrows)+u]); if(ph.packsize<0) { free(xmpat);xmpat=NULL; _mm_errno=MMERR_LOADING_PATTERN; return 0; } } if(ph.packsize) { _mm_fseek(modreader,ph.packsize,SEEK_CUR); } if(_mm_eof(modreader)) { free(xmpat);xmpat=NULL; _mm_errno=MMERR_LOADING_PATTERN; return 0; } for(v=0;v<of.numchn;v++) of.tracks[numtrk++]=XM_Convert(&xmpat[v*ph.numrows],ph.numrows); free(xmpat);xmpat=NULL; } else { for(v=0;v<of.numchn;v++) of.tracks[numtrk++]=XM_Convert(NULL,ph.numrows); } } if(dummypat) { of.pattrows[t]=64; if(!(xmpat=(XMNOTE*)_mm_calloc(64*of.numchn,sizeof(XMNOTE)))) return 0; for(v=0;v<of.numchn;v++) of.tracks[numtrk++]=XM_Convert(&xmpat[v*64],64); free(xmpat);xmpat=NULL; } return 1;}static void FixEnvelope(ENVPT *cur, int pts){ int u, old, tmp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -