📄 load_xm.c
字号:
/* MikMod sound library (c) 1998, 1999 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.32 1999/10/25 16:31:41 miod Exp $ Fasttracker (XM) module loader==============================================================================*/#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <string.h>extern char *safe_strdup(const char *s);#include "unimod_priv.h"/*========== 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 */ UniPTEffect (0x4, vol << 4); break; case 0xb: /* vibrato */ UniPTEffect (0x4, 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 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 ? 64 : dat); 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -