4
|
1 /*
|
|
2
|
|
3 Name: LOAD_MTM.C
|
|
4
|
|
5 Description:
|
|
6 MTM module loader
|
|
7
|
|
8 Portability:
|
|
9 All systems - all compilers (hopefully)
|
|
10
|
|
11 If this module is found to not be portable to any particular platform,
|
|
12 please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for
|
|
13 more information on contacting the author).
|
|
14
|
|
15 */
|
|
16
|
|
17 #include <string.h>
|
|
18 #include "mikmod.h"
|
|
19
|
|
20 /**************************************************************************
|
|
21 **************************************************************************/
|
|
22
|
|
23
|
|
24 typedef struct MTMSAMPLE
|
|
25 { CHAR samplename[22];
|
|
26 ULONG length;
|
|
27 ULONG reppos;
|
|
28 ULONG repend;
|
|
29 UBYTE finetune;
|
|
30 UBYTE volume;
|
|
31 UBYTE attribute;
|
|
32 } MTMSAMPLE;
|
|
33
|
|
34
|
|
35
|
|
36 typedef struct MTMHEADER
|
|
37 { UBYTE id[3]; // MTM file marker
|
|
38 UBYTE version; // upper major, lower nibble minor version number
|
|
39 char songname[20]; // ASCIIZ songname
|
|
40 UWORD numtracks; // number of tracks saved
|
|
41 UBYTE lastpattern; // last pattern number saved
|
|
42 UBYTE lastorder; // last order number to play (songlength-1)
|
|
43 UWORD commentsize; // length of comment field
|
|
44 UBYTE numsamples; // number of samples saved
|
|
45 UBYTE attribute; // attribute byte (unused)
|
|
46 UBYTE beatspertrack; //
|
|
47 UBYTE numchannels; // number of channels used
|
|
48 UBYTE panpos[32]; // voice pan positions
|
|
49 } MTMHEADER;
|
|
50
|
|
51
|
|
52 typedef struct MTMNOTE
|
|
53 { UBYTE a,b,c;
|
|
54 } MTMNOTE;
|
|
55
|
|
56
|
|
57 /**************************************************************************
|
|
58 **************************************************************************/
|
|
59
|
|
60
|
|
61 static MTMHEADER *mh = NULL;
|
|
62 static MTMNOTE *mtmtrk = NULL;
|
|
63 static UWORD pat[32];
|
|
64
|
|
65 char MTM_Version[] = "MTM";
|
|
66
|
|
67
|
|
68
|
|
69 BOOL MTM_Test(void)
|
|
70 {
|
|
71 UBYTE id[3];
|
|
72 if(!_mm_read_UBYTES(id,3,modfp)) return 0;
|
|
73 if(!memcmp(id,"MTM",3)) return 1;
|
|
74 return 0;
|
|
75 }
|
|
76
|
|
77
|
|
78 BOOL MTM_Init(void)
|
|
79 {
|
|
80 if(!(mtmtrk=(MTMNOTE *)_mm_calloc(64,sizeof(MTMNOTE)))) return 0;
|
|
81 if(!(mh=(MTMHEADER *)_mm_calloc(1,sizeof(MTMHEADER)))) return 0;
|
|
82
|
|
83 return 1;
|
|
84 }
|
|
85
|
|
86
|
|
87 void MTM_Cleanup(void)
|
|
88 {
|
|
89 if(mtmtrk!=NULL) free(mtmtrk);
|
|
90 if(mh!=NULL) free(mh);
|
|
91
|
|
92 mtmtrk = NULL;
|
|
93 mh = NULL;
|
|
94 }
|
|
95
|
|
96
|
|
97 UBYTE *MTM_Convert(void)
|
|
98 {
|
|
99 int t;
|
|
100 UBYTE a,b,c,inst,note,eff,dat;
|
|
101
|
|
102 UniReset();
|
|
103 for(t=0; t<64; t++)
|
|
104 { a = mtmtrk[t].a;
|
|
105 b = mtmtrk[t].b;
|
|
106 c = mtmtrk[t].c;
|
|
107
|
|
108 inst = ((a&0x3)<<4)|(b>>4);
|
|
109 note = a>>2;
|
|
110
|
|
111 eff = b&0xf;
|
|
112 dat = c;
|
|
113
|
|
114 if(inst!=0) UniInstrument(inst-1);
|
|
115 if(note!=0) UniNote(note+24);
|
|
116
|
|
117 // mtm bug bugfix: when the effect is volslide,
|
|
118 // slide-up _always_ overrides slide-dn.
|
|
119
|
|
120 if(eff==0xa && dat&0xf0) dat&=0xf0;
|
|
121
|
|
122 // Convert pattern jump from Dec to Hex
|
|
123 if(eff == 0xd)
|
|
124 dat = (((dat&0xf0)>>4)*10)+(dat&0xf);
|
|
125 UniPTEffect(eff,dat);
|
|
126 UniNewline();
|
|
127 }
|
|
128 return UniDup();
|
|
129 }
|
|
130
|
|
131
|
|
132 BOOL MTM_Load(void)
|
|
133 {
|
|
134 MTMSAMPLE s;
|
|
135 SAMPLE *q;
|
|
136
|
|
137 int t,u;
|
|
138
|
|
139 // try to read module header
|
|
140
|
|
141 _mm_read_UBYTES(mh->id,3,modfp);
|
|
142 mh->version =_mm_read_UBYTE(modfp);
|
|
143 _mm_read_string(mh->songname,20,modfp);
|
|
144 mh->numtracks =_mm_read_I_UWORD(modfp);
|
|
145 mh->lastpattern =_mm_read_UBYTE(modfp);
|
|
146 mh->lastorder =_mm_read_UBYTE(modfp);
|
|
147 mh->commentsize =_mm_read_I_UWORD(modfp);
|
|
148 mh->numsamples =_mm_read_UBYTE(modfp);
|
|
149 mh->attribute =_mm_read_UBYTE(modfp);
|
|
150 mh->beatspertrack=_mm_read_UBYTE(modfp);
|
|
151 mh->numchannels =_mm_read_UBYTE(modfp);
|
|
152 _mm_read_UBYTES(mh->panpos,32,modfp);
|
|
153
|
|
154 if(feof(modfp))
|
|
155 { _mm_errno = MMERR_LOADING_HEADER;
|
|
156 return 0;
|
|
157 }
|
|
158
|
|
159 // set module variables
|
|
160
|
|
161 of.initspeed = 6;
|
|
162 of.inittempo = 125;
|
|
163 of.modtype = strdup(MTM_Version);
|
|
164 of.numchn = mh->numchannels;
|
|
165 of.numtrk = mh->numtracks+1; // get number of channels
|
|
166 of.songname = DupStr(mh->songname,20); // make a cstr of songname
|
|
167 of.numpos = mh->lastorder+1; // copy the songlength
|
|
168 of.numpat = mh->lastpattern+1;
|
|
169 for(t=0; t<32; t++) of.panning[t] = mh->panpos[t] << 4;
|
|
170
|
|
171 of.numins = of.numsmp = mh->numsamples;
|
|
172 if(!AllocSamples()) return 0;
|
|
173
|
|
174 q = of.samples;
|
|
175
|
|
176 for(t=0; t<of.numins; t++)
|
|
177 { // try to read sample info
|
|
178 _mm_read_string(s.samplename,22,modfp);
|
|
179 s.length =_mm_read_I_ULONG(modfp);
|
|
180 s.reppos =_mm_read_I_ULONG(modfp);
|
|
181 s.repend =_mm_read_I_ULONG(modfp);
|
|
182 s.finetune =_mm_read_UBYTE(modfp);
|
|
183 s.volume =_mm_read_UBYTE(modfp);
|
|
184 s.attribute =_mm_read_UBYTE(modfp);
|
|
185
|
|
186 if(feof(modfp))
|
|
187 { _mm_errno = MMERR_LOADING_SAMPLEINFO;
|
|
188 return 0;
|
|
189 }
|
|
190
|
|
191 q->samplename = DupStr(s.samplename,22);
|
|
192 q->seekpos = 0;
|
|
193 q->speed = finetune[s.finetune];
|
|
194 q->length = s.length;
|
|
195 q->loopstart = s.reppos;
|
|
196 q->loopend = s.repend;
|
|
197 q->volume = s.volume;
|
|
198
|
|
199 if((s.repend-s.reppos) > 2) q->flags |= SF_LOOP;
|
|
200
|
|
201 if(s.attribute & 1)
|
|
202 { // If the sample is 16-bits, convert the length
|
|
203 // and replen byte-values into sample-values
|
|
204
|
|
205 q->flags|=SF_16BITS;
|
|
206 q->length>>=1;
|
|
207 q->loopstart>>=1;
|
|
208 q->loopend>>=1;
|
|
209 }
|
|
210
|
|
211 q++;
|
|
212 }
|
|
213
|
|
214 if(!AllocPositions(of.numpos)) return 0;
|
|
215 for(t=0; t<of.numpos; t++)
|
|
216 of.positions[t] = _mm_read_UBYTE(modfp);
|
|
217 for(; t<128; t++) _mm_read_UBYTE(modfp);
|
|
218
|
|
219 if(feof(modfp))
|
|
220 { _mm_errno = MMERR_LOADING_HEADER;
|
|
221 return 0;
|
|
222 }
|
|
223
|
|
224 if(!AllocTracks()) return 0;
|
|
225 if(!AllocPatterns()) return 0;
|
|
226
|
|
227 of.tracks[0] = MTM_Convert(); // track 0 is empty
|
|
228
|
|
229 for(t=1; t<of.numtrk; t++)
|
|
230 { int s;
|
|
231
|
|
232 for(s=0; s<64; s++)
|
|
233 { mtmtrk[s].a=_mm_read_UBYTE(modfp);
|
|
234 mtmtrk[s].b=_mm_read_UBYTE(modfp);
|
|
235 mtmtrk[s].c=_mm_read_UBYTE(modfp);
|
|
236 }
|
|
237
|
|
238 if(feof(modfp))
|
|
239 { _mm_errno = MMERR_LOADING_TRACK;
|
|
240 return 0;
|
|
241 }
|
|
242
|
|
243 if(!(of.tracks[t]=MTM_Convert())) return 0;
|
|
244 }
|
|
245
|
|
246 for(t=0; t<of.numpat; t++)
|
|
247 { _mm_read_I_UWORDS(pat,32,modfp);
|
|
248
|
|
249 for(u=0; u<of.numchn; u++)
|
|
250 of.patterns[((long)t*of.numchn)+u]=pat[u];
|
|
251 }
|
|
252
|
|
253 // read comment field
|
|
254
|
|
255 if(!ReadComment(mh->commentsize)) return 0;
|
|
256
|
|
257 return 1;
|
|
258 }
|
|
259
|
|
260
|
|
261 CHAR *MTM_LoadTitle(void)
|
|
262 {
|
|
263 CHAR s[20];
|
|
264
|
|
265 _mm_fseek(modfp,4,SEEK_SET);
|
|
266 if(!fread(s,20,1,modfp)) return NULL;
|
|
267
|
|
268 return(DupStr(s,20));
|
|
269 }
|
|
270
|
|
271
|
|
272 MLOADER load_mtm =
|
|
273 { NULL,
|
|
274 "MTM",
|
|
275 "Portable MTM loader v0.1",
|
|
276 MTM_Init,
|
|
277 MTM_Test,
|
|
278 MTM_Load,
|
|
279 MTM_Cleanup,
|
|
280 MTM_LoadTitle
|
|
281 };
|
|
282
|