📄 load_it.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_it.c,v 1.2 2005/03/30 19:09:58 realtech Exp $ Impulse tracker (IT) module loader==============================================================================*/#ifdef HAVE_CONFIG_H#include "config.h"#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include <ctype.h>#include <stdio.h>#ifdef HAVE_MEMORY_H#include <memory.h>#endif#include <string.h>#include "..\include\mikmod_internals.h"#ifdef SUNOSextern int fprintf(FILE *, const char *, ...);extern int toupper(int);#endif/*========== 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 unsigned 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*)MikMod_malloc(sizeof(ITHEADER)))) return 0; if(!(poslookup=(UBYTE*)MikMod_malloc(256*sizeof(UBYTE)))) return 0; if(!(itpat=(ITNOTE*)MikMod_malloc(200*64*sizeof(ITNOTE)))) return 0; if(!(mask=(UBYTE*)MikMod_malloc(64*sizeof(UBYTE)))) return 0; if(!(last=(ITNOTE*)MikMod_malloc(64*sizeof(ITNOTE)))) return 0; return 1;}void IT_Cleanup(void){ FreeLinear(); MikMod_free(mh); MikMod_free(poslookup); MikMod_free(itpat); MikMod_free(mask); MikMod_free(last); MikMod_free(paraptr); MikMod_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==65) /* fine volume slide up (65-74) - A0 case */ UniVolEffect(VOL_VOLSLIDE,0); else if(volpan<=74) { /* fine volume slide up (65-74) - general case */ UniVolEffect(VOL_VOLSLIDE,0x0f+((volpan-65)<<4)); } else if(volpan==75) /* fine volume slide down (75-84) - B0 case */ UniVolEffect(VOL_VOLSLIDE,0); else if(volpan<=84) { /* fine volume slide down (75-84) - general case*/ 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|S3MIT_IT); 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(MREADER* 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(MREADER* 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<UF_MAXMACRO;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->flags & 1)) of.flags |= UF_PANNING; of.bpmlimit=32; 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -