📄 load_it.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_it.c,v 1.39 1999/10/25 16:31:41 miod Exp $ Impulse tracker (IT) module loader==============================================================================*/#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <ctype.h>#include <string.h>#include "unimod_priv.h"/*========== Module structure *//* header */typedef struct ITHEADER { CHAR songname[26]; UBYTE blank01[2]; UWORD ordnum; UWORD insnum; UWORD smpnum; UWORD patnum; UWORD cwt; /* Created with tracker (y.xx = 0x0yxx) */ UWORD cmwt; /* Compatible with tracker ver > than val. */ UWORD flags; UWORD special; /* bit 0 set = song message attached */ UBYTE globvol; UBYTE mixvol; /* mixing volume [ignored] */ UBYTE initspeed; UBYTE inittempo; UBYTE pansep; /* panning separation between channels */ UBYTE zerobyte; UWORD msglength; ULONG msgoffset; UBYTE blank02[4]; UBYTE pantable[64]; UBYTE voltable[64]; }ITHEADER;/* sample information */typedef struct ITSAMPLE { CHAR filename[12]; UBYTE zerobyte; UBYTE globvol; UBYTE flag; UBYTE volume; UBYTE panning; CHAR sampname[28]; UWORD convert; /* sample conversion flag */ ULONG length; ULONG loopbeg; ULONG loopend; ULONG c5spd; ULONG susbegin; ULONG susend; ULONG sampoffset; UBYTE vibspeed; UBYTE vibdepth; UBYTE vibrate; UBYTE vibwave; /* 0=sine, 1=rampdown, 2=square, 3=random (speed ignored) */ }ITSAMPLE;/* instrument information */#define ITENVCNT 25#define ITNOTECNT 120typedef struct ITINSTHEADER { ULONG size; /* (dword) Instrument size */ CHAR filename[12]; /* (char) Instrument filename */ UBYTE zerobyte; /* (byte) Instrument type (always 0) */ UBYTE volflg; UBYTE volpts; UBYTE volbeg; /* (byte) Volume loop start (node) */ UBYTE volend; /* (byte) Volume loop end (node) */ UBYTE volsusbeg; /* (byte) Volume sustain begin (node) */ UBYTE volsusend; /* (byte) Volume Sustain end (node) */ UBYTE panflg; UBYTE panpts; UBYTE panbeg; /* (byte) channel loop start (node) */ UBYTE panend; /* (byte) channel loop end (node) */ UBYTE pansusbeg; /* (byte) channel sustain begin (node) */ UBYTE pansusend; /* (byte) channel Sustain end (node) */ UBYTE pitflg; UBYTE pitpts; UBYTE pitbeg; /* (byte) pitch loop start (node) */ UBYTE pitend; /* (byte) pitch loop end (node) */ UBYTE pitsusbeg; /* (byte) pitch sustain begin (node) */ UBYTE pitsusend; /* (byte) pitch Sustain end (node) */ UWORD blank; UBYTE globvol; UBYTE chanpan; UWORD fadeout; /* Envelope end / NNA volume fadeout */ UBYTE dnc; /* Duplicate note check */ UBYTE dca; /* Duplicate check action */ UBYTE dct; /* Duplicate check type */ UBYTE nna; /* New Note Action [0,1,2,3] */ UWORD trkvers; /* tracker version used to save [files only] */ UBYTE ppsep; /* Pitch-pan Separation */ UBYTE ppcenter; /* Pitch-pan Center */ UBYTE rvolvar; /* random volume varations */ UBYTE rpanvar; /* random panning varations */ UWORD numsmp; /* Number of samples in instrument [files only] */ CHAR name[26]; /* Instrument name */ UBYTE blank01[6]; UWORD samptable[ITNOTECNT]; /* sample for each note [note / samp pairs] */ UBYTE volenv[200]; /* volume envelope (IT 1.x stuff) */ UBYTE oldvoltick[ITENVCNT]; /* volume tick position (IT 1.x stuff) */ UBYTE volnode[ITENVCNT]; /* amplitude of volume nodes */ UWORD voltick[ITENVCNT]; /* tick value of volume nodes */ SBYTE pannode[ITENVCNT]; /* panenv - node points */ UWORD pantick[ITENVCNT]; /* tick value of panning nodes */ SBYTE pitnode[ITENVCNT]; /* pitchenv - node points */ UWORD pittick[ITENVCNT]; /* tick value of pitch nodes */ }ITINSTHEADER;/* unpacked note */typedef struct ITNOTE { UBYTE note, ins, volpan, cmd, inf; }ITNOTE;/*========== Loader data */static ULONG *paraptr = NULL; /* parapointer array (see IT docs) */static ITHEADER *mh = NULL;static ITNOTE *itpat = NULL; /* allocate to space for one full pattern */static UBYTE *mask = NULL; /* arrays allocated to 64 elements and used for */static ITNOTE *last = NULL; /* uncompressing IT's pattern information */static int numtrk = 0;static int old_effect; /* if set, use S3M old-effects stuffs */static CHAR *IT_Version[] ={ "ImpulseTracker . ", "Compressed ImpulseTracker . ", "ImpulseTracker 2.14p3", "Compressed ImpulseTracker 2.14p3", "ImpulseTracker 2.14p4", "Compressed ImpulseTracker 2.14p4",};/* table for porta-to-note command within volume/panning column */static UBYTE portatable[10] ={0, 1, 4, 8, 16, 32, 64, 96, 128, 255};/*========== Loader code */BOOL IT_Test (void){ UBYTE id[4]; if (!_mm_read_UBYTES (id, 4, modreader)) return 0; if (!memcmp (id, "IMPM", 4)) return 1; return 0;}BOOL IT_Init (void){ if (!(mh = (ITHEADER *) _mm_malloc (sizeof (ITHEADER)))) return 0; if (!(poslookup = (UBYTE *) _mm_malloc (256 * sizeof (UBYTE)))) return 0; if (!(itpat = (ITNOTE *) _mm_malloc (200 * 64 * sizeof (ITNOTE)))) return 0; if (!(mask = (UBYTE *) _mm_malloc (64 * sizeof (UBYTE)))) return 0; if (!(last = (ITNOTE *) _mm_malloc (64 * sizeof (ITNOTE)))) return 0; return 1;}void IT_Cleanup (void){ FreeLinear (); _mm_free (mh); _mm_free (poslookup); _mm_free (itpat); _mm_free (mask); _mm_free (last); _mm_free (paraptr); _mm_free (origpositions);}/* Because so many IT files have 64 channels as the set number used, but really only use far less (usually from 8 to 24 still), I had to make this function, which determines the number of channels that are actually USED by a pattern. NOTE: You must first seek to the file location of the pattern before calling this procedure. Returns 1 on error */static BOOL IT_GetNumChannels (UWORD patrows){ int row = 0, flag, ch; do { if ((flag = _mm_read_UBYTE (modreader)) == EOF) { _mm_errno = MMERR_LOADING_PATTERN; return 1; } if (!flag) row++; else { ch = (flag - 1) & 63; remap[ch] = 0; if (flag & 128) mask[ch] = _mm_read_UBYTE (modreader); if (mask[ch] & 1) _mm_read_UBYTE (modreader); if (mask[ch] & 2) _mm_read_UBYTE (modreader); if (mask[ch] & 4) _mm_read_UBYTE (modreader); if (mask[ch] & 8) { _mm_read_UBYTE (modreader); _mm_read_UBYTE (modreader); } } } while (row < patrows); return 0;}static UBYTE *IT_ConvertTrack (ITNOTE * tr, UWORD numrows){ int t; UBYTE note, ins, volpan; UniReset (); for (t = 0; t < numrows; t++) { note = tr[t * of.numchn].note; ins = tr[t * of.numchn].ins; volpan = tr[t * of.numchn].volpan; if (note != 255) { if (note == 253) UniWriteByte (UNI_KEYOFF); else if (note == 254) { UniPTEffect (0xc, -1); /* note cut command */ volpan = 255; } else UniNote (note); } if ((ins) && (ins < 100)) UniInstrument (ins - 1); else if (ins == 253) UniWriteByte (UNI_KEYOFF); else if (ins != 255) { /* crap */ _mm_errno = MMERR_LOADING_PATTERN; return NULL; } /* process volume / panning column volume / panning effects do NOT all share the same memory address yet. */ if (volpan <= 64) UniVolEffect (VOL_VOLUME, volpan); else if (volpan <= 74) /* fine volume slide up (65-74) */ UniVolEffect (VOL_VOLSLIDE, 0x0f + ((volpan - 65) << 4)); else if (volpan <= 84) /* fine volume slide down (75-84) */ UniVolEffect (VOL_VOLSLIDE, 0xf0 + (volpan - 75)); else if (volpan <= 94) /* volume slide up (85-94) */ UniVolEffect (VOL_VOLSLIDE, ((volpan - 85) << 4)); else if (volpan <= 104) /* volume slide down (95-104) */ UniVolEffect (VOL_VOLSLIDE, (volpan - 95)); else if (volpan <= 114) /* pitch slide down (105-114) */ UniVolEffect (VOL_PITCHSLIDEDN, (volpan - 105)); else if (volpan <= 124) /* pitch slide up (115-124) */ UniVolEffect (VOL_PITCHSLIDEUP, (volpan - 115)); else if (volpan <= 127) { /* crap */ _mm_errno = MMERR_LOADING_PATTERN; return NULL; } else if (volpan <= 192) UniVolEffect (VOL_PANNING, ((volpan - 128) == 64) ? 255 : ((volpan - 128) << 2)); else if (volpan <= 202) /* portamento to note */ UniVolEffect (VOL_PORTAMENTO, portatable[volpan - 193]); else if (volpan <= 212) /* vibrato */ UniVolEffect (VOL_VIBRATO, (volpan - 203)); else if ((volpan != 239) && (volpan != 255)) { /* crap */ _mm_errno = MMERR_LOADING_PATTERN; return NULL; } S3MIT_ProcessCmd (tr[t * of.numchn].cmd, tr[t * of.numchn].inf, old_effect | 2); UniNewline (); } return UniDup ();}static BOOL IT_ReadPattern (UWORD patrows){ int row = 0, flag, ch, blah; ITNOTE *itt = itpat, dummy, *n, *l; memset (itt, 255, 200 * 64 * sizeof (ITNOTE)); do { if ((flag = _mm_read_UBYTE (modreader)) == EOF) { _mm_errno = MMERR_LOADING_PATTERN; return 0; } if (!flag) { itt = &itt[of.numchn]; row++; } else { ch = remap[(flag - 1) & 63]; if (ch != -1) { n = &itt[ch]; l = &last[ch]; } else n = l = &dummy; if (flag & 128) mask[ch] = _mm_read_UBYTE (modreader); if (mask[ch] & 1) /* convert IT note off to internal note off */ if ((l->note = n->note = _mm_read_UBYTE (modreader)) == 255) l->note = n->note = 253; if (mask[ch] & 2) l->ins = n->ins = _mm_read_UBYTE (modreader); if (mask[ch] & 4) l->volpan = n->volpan = _mm_read_UBYTE (modreader); if (mask[ch] & 8) { l->cmd = n->cmd = _mm_read_UBYTE (modreader); l->inf = n->inf = _mm_read_UBYTE (modreader); } if (mask[ch] & 16) n->note = l->note; if (mask[ch] & 32) n->ins = l->ins; if (mask[ch] & 64) n->volpan = l->volpan; if (mask[ch] & 128) { n->cmd = l->cmd; n->inf = l->inf; } } } while (row < patrows); for (blah = 0; blah < of.numchn; blah++) { if (!(of.tracks[numtrk++] = IT_ConvertTrack (&itpat[blah], patrows))) return 0; } return 1;}static void LoadMidiString (URL modreader, CHAR * dest){ CHAR *cur, *last; _mm_read_UBYTES (dest, 32, modreader); cur = last = dest; /* remove blanks and uppercase all */ while (*last) { if (isalnum ((int) *last)) *(cur++) = toupper ((int) *last); last++; } *cur = 0;}/* Load embedded midi information for resonant filters */static void IT_LoadMidiConfiguration (URL modreader){ int i; memset (filtermacros, 0, sizeof (filtermacros)); memset (filtersettings, 0, sizeof (filtersettings)); if (modreader) { /* information is embedded in file */ UWORD dat; CHAR midiline[33]; dat = _mm_read_I_UWORD (modreader); _mm_fseek (modreader, 8 * dat + 0x120, SEEK_CUR); /* read midi macros */ for (i = 0; i < 16; i++) { LoadMidiString (modreader, midiline); if ((!strncmp (midiline, "F0F00", 5)) && ((midiline[5] == '0') || (midiline[5] == '1'))) filtermacros[i] = (midiline[5] - '0') | 0x80; } /* read standalone filters */ for (i = 0x80; i < 0x100; i++) { LoadMidiString (modreader, midiline); if ((!strncmp (midiline, "F0F00", 5)) && ((midiline[5] == '0') || (midiline[5] == '1'))) { filtersettings[i].filter = (midiline[5] - '0') | 0x80; dat = (midiline[6]) ? (midiline[6] - '0') : 0; if (midiline[7]) dat = (dat << 4) | (midiline[7] - '0'); filtersettings[i].inf = dat; } } } else { /* use default information */ filtermacros[0] = FILT_CUT; for (i = 0x80; i < 0x90; i++) { filtersettings[i].filter = FILT_RESONANT; filtersettings[i].inf = (i & 0x7f) << 3; } } activemacro = 0; for (i = 0; i < 0x80; i++) { filtersettings[i].filter = filtermacros[0]; filtersettings[i].inf = i; }}BOOL IT_Load (BOOL curious){ int t, u, lp; INSTRUMENT *d; SAMPLE *q; BOOL compressed = 0; numtrk = 0; filters = 0; /* try to read module header */ _mm_read_I_ULONG (modreader); /* kill the 4 byte header */ _mm_read_string (mh->songname, 26, modreader); _mm_read_UBYTES (mh->blank01, 2, modreader); mh->ordnum = _mm_read_I_UWORD (modreader); mh->insnum = _mm_read_I_UWORD (modreader); mh->smpnum = _mm_read_I_UWORD (modreader); mh->patnum = _mm_read_I_UWORD (modreader); mh->cwt = _mm_read_I_UWORD (modreader); mh->cmwt = _mm_read_I_UWORD (modreader); mh->flags = _mm_read_I_UWORD (modreader); mh->special = _mm_read_I_UWORD (modreader); mh->globvol = _mm_read_UBYTE (modreader); mh->mixvol = _mm_read_UBYTE (modreader); mh->initspeed = _mm_read_UBYTE (modreader); mh->inittempo = _mm_read_UBYTE (modreader); mh->pansep = _mm_read_UBYTE (modreader); mh->zerobyte = _mm_read_UBYTE (modreader); mh->msglength = _mm_read_I_UWORD (modreader); mh->msgoffset = _mm_read_I_ULONG (modreader); _mm_read_UBYTES (mh->blank02, 4, modreader); _mm_read_UBYTES (mh->pantable, 64, modreader); _mm_read_UBYTES (mh->voltable, 64, modreader); if (_mm_eof (modreader)) { _mm_errno = MMERR_LOADING_HEADER; return 0; } /* set module variables */ of.songname = DupStr (mh->songname, 26, 0); /* make a cstr of songname */ of.reppos = 0; of.numpat = mh->patnum; of.numins = mh->insnum; of.numsmp = mh->smpnum; of.initspeed = mh->initspeed; of.inittempo = mh->inittempo; of.initvolume = mh->globvol; of.flags |= UF_BGSLIDES | UF_ARPMEM; if (mh->songname[25]) { of.numvoices = 1 + mh->songname[25];#ifdef MIKMOD_DEBUG fprintf (stderr, "Embedded IT limitation to %d voices\n", of.numvoices);#endif } /* set the module type */ /* 2.17 : IT 2.14p4 */ /* 2.16 : IT 2.14p3 with resonant filters */ /* 2.15 : IT 2.14p3 (improved compression) */ if ((mh->cwt <= 0x219) && (mh->cwt >= 0x217)) of.modtype = strdup (IT_Version[mh->cmwt < 0x214 ? 4 : 5]); else if (mh->cwt >= 0x215) of.modtype = strdup (IT_Version[mh->cmwt < 0x214 ? 2 : 3]); else { of.modtype = strdup (IT_Version[mh->cmwt < 0x214 ? 0 : 1]); of.modtype[mh->cmwt < 0x214 ? 15 : 26] = (mh->cwt >> 8) + '0'; of.modtype[mh->cmwt < 0x214 ? 17 : 28] = ((mh->cwt >> 4) & 0xf) + '0'; of.modtype[mh->cmwt < 0x214 ? 18 : 29] = ((mh->cwt) & 0xf) + '0'; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -