1 /* MikMod sound library
2 (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
3 complete list.
4
5 This library is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of
8 the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 02111-1307, USA.
19 */
20
21 /*==============================================================================
22
23 $Id$
24
25 MTM module loader
26
27 ==============================================================================*/
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <string.h>
34
35 #include "unimod_priv.h"
36
37 /*========== Module structure */
38
39 typedef struct MTMHEADER
40 {
41 UBYTE id[3]; /* MTM file marker */
42 UBYTE version; /* upper major, lower nibble minor version number */
43 CHAR songname[20]; /* ASCIIZ songname */
44 UWORD numtracks; /* number of tracks saved */
45 UBYTE lastpattern; /* last pattern number saved */
46 UBYTE lastorder; /* last order number to play (songlength-1) */
47 UWORD commentsize; /* length of comment field */
48 UBYTE numsamples; /* number of samples saved */
49 UBYTE attribute; /* attribute byte (unused) */
50 UBYTE beatspertrack;
51 UBYTE numchannels; /* number of channels used */
52 UBYTE panpos[32]; /* voice pan positions */
53 }
54 MTMHEADER;
55
56 typedef struct MTMSAMPLE
57 {
58 CHAR samplename[22];
59 ULONG length;
60 ULONG reppos;
61 ULONG repend;
62 UBYTE finetune;
63 UBYTE volume;
64 UBYTE attribute;
65 }
66 MTMSAMPLE;
67
68 typedef struct MTMNOTE
69 {
70 UBYTE a, b, c;
71 }
72 MTMNOTE;
73
74 /*========== Loader variables */
75
76 static MTMHEADER *mh = NULL;
77 static MTMNOTE *mtmtrk = NULL;
78 static UWORD pat[32];
79
80 static CHAR MTM_Version[] = "MTM";
81
82 /*========== Loader code */
83
84 static BOOL
MTM_Test(void)85 MTM_Test (void)
86 {
87 UBYTE id[3];
88
89 if (!_mm_read_UBYTES (id, 3, modreader))
90 return 0;
91 if (!memcmp (id, "MTM", 3))
92 return 1;
93 return 0;
94 }
95
96 static BOOL
MTM_Init(void)97 MTM_Init (void)
98 {
99 if (!(mtmtrk = (MTMNOTE *) _mm_calloc (64, sizeof (MTMNOTE))))
100 return 0;
101 if (!(mh = (MTMHEADER *) _mm_malloc (sizeof (MTMHEADER))))
102 return 0;
103
104 return 1;
105 }
106
107 static void
MTM_Cleanup(void)108 MTM_Cleanup (void)
109 {
110 _mm_free (mtmtrk);
111 _mm_free (mh);
112 }
113
114 static UBYTE *
MTM_Convert(void)115 MTM_Convert (void)
116 {
117 int t;
118 UBYTE a, b, inst, note, eff, dat;
119
120 UniReset ();
121 for (t = 0; t < 64; t++)
122 {
123 a = mtmtrk[t].a;
124 b = mtmtrk[t].b;
125 inst = ((a & 0x3) << 4) | (b >> 4);
126 note = a >> 2;
127 eff = b & 0xf;
128 dat = mtmtrk[t].c;
129
130 if (inst)
131 UniInstrument (inst - 1);
132 if (note)
133 UniNote (note + 2 * OCTAVE);
134
135 /* MTM bug workaround : when the effect is volslide, slide-up *always*
136 overrides slide-down. */
137 if (eff == 0xa && (dat & 0xf0))
138 dat &= 0xf0;
139
140 /* Convert pattern jump from Dec to Hex */
141 if (eff == 0xd)
142 dat = (((dat & 0xf0) >> 4) * 10) + (dat & 0xf);
143 UniPTEffect (eff, dat);
144 UniNewline ();
145 }
146 return UniDup ();
147 }
148
149 static BOOL
MTM_Load(BOOL curious)150 MTM_Load (BOOL curious)
151 {
152 int t, u;
153 MTMSAMPLE s;
154 SAMPLE *q;
155
156 /* try to read module header */
157 _mm_read_UBYTES (mh->id, 3, modreader);
158 mh->version = _mm_read_UBYTE (modreader);
159 _mm_read_string (mh->songname, 20, modreader);
160 mh->numtracks = _mm_read_I_UWORD (modreader);
161 mh->lastpattern = _mm_read_UBYTE (modreader);
162 mh->lastorder = _mm_read_UBYTE (modreader);
163 mh->commentsize = _mm_read_I_UWORD (modreader);
164 mh->numsamples = _mm_read_UBYTE (modreader);
165 mh->attribute = _mm_read_UBYTE (modreader);
166 mh->beatspertrack = _mm_read_UBYTE (modreader);
167 mh->numchannels = _mm_read_UBYTE (modreader);
168 _mm_read_UBYTES (mh->panpos, 32, modreader);
169
170 if (_mm_eof (modreader))
171 {
172 _mm_errno = MMERR_LOADING_HEADER;
173 return 0;
174 }
175
176 /* set module variables */
177 of.initspeed = 6;
178 of.inittempo = 125;
179 of.modtype = strdup (MTM_Version);
180 of.numchn = mh->numchannels;
181 of.numtrk = mh->numtracks + 1; /* get number of channels */
182 of.songname = DupStr (mh->songname, 20, 1); /* make a cstr of songname */
183 of.numpos = mh->lastorder + 1; /* copy the songlength */
184 of.numpat = mh->lastpattern + 1;
185 of.reppos = 0;
186 for (t = 0; t < 32; t++)
187 of.panning[t] = mh->panpos[t] << 4;
188 of.numins = of.numsmp = mh->numsamples;
189
190 if (!AllocSamples ())
191 return 0;
192 q = of.samples;
193 for (t = 0; t < of.numins; t++)
194 {
195 /* try to read sample info */
196 _mm_read_string (s.samplename, 22, modreader);
197 s.length = _mm_read_I_ULONG (modreader);
198 s.reppos = _mm_read_I_ULONG (modreader);
199 s.repend = _mm_read_I_ULONG (modreader);
200 s.finetune = _mm_read_UBYTE (modreader);
201 s.volume = _mm_read_UBYTE (modreader);
202 s.attribute = _mm_read_UBYTE (modreader);
203
204 if (_mm_eof (modreader))
205 {
206 _mm_errno = MMERR_LOADING_SAMPLEINFO;
207 return 0;
208 }
209
210 q->samplename = DupStr (s.samplename, 22, 1);
211 q->seekpos = 0;
212 q->speed = finetune[s.finetune];
213 q->length = s.length;
214 q->loopstart = s.reppos;
215 q->loopend = s.repend;
216 q->volume = s.volume;
217 if ((s.repend - s.reppos) > 2)
218 q->flags |= SF_LOOP;
219
220 if (s.attribute & 1)
221 {
222 /* If the sample is 16-bits, convert the length and replen
223 byte-values into sample-values */
224 q->flags |= SF_16BITS;
225 q->length >>= 1;
226 q->loopstart >>= 1;
227 q->loopend >>= 1;
228 }
229
230 q++;
231 }
232
233 if (!AllocPositions (of.numpos))
234 return 0;
235 for (t = 0; t < of.numpos; t++)
236 of.positions[t] = _mm_read_UBYTE (modreader);
237 for (; t < 128; t++)
238 _mm_read_UBYTE (modreader);
239 if (_mm_eof (modreader))
240 {
241 _mm_errno = MMERR_LOADING_HEADER;
242 return 0;
243 }
244
245 if (!AllocTracks ())
246 return 0;
247 if (!AllocPatterns ())
248 return 0;
249
250 of.tracks[0] = MTM_Convert (); /* track 0 is empty */
251 for (t = 1; t < of.numtrk; t++)
252 {
253 int s;
254
255 for (s = 0; s < 64; s++)
256 {
257 mtmtrk[s].a = _mm_read_UBYTE (modreader);
258 mtmtrk[s].b = _mm_read_UBYTE (modreader);
259 mtmtrk[s].c = _mm_read_UBYTE (modreader);
260 }
261
262 if (_mm_eof (modreader))
263 {
264 _mm_errno = MMERR_LOADING_TRACK;
265 return 0;
266 }
267
268 if (!(of.tracks[t] = MTM_Convert ()))
269 return 0;
270 }
271
272 for (t = 0; t < of.numpat; t++)
273 {
274 _mm_read_I_UWORDS (pat, 32, modreader);
275 for (u = 0; u < of.numchn; u++)
276 of.patterns[((long) t * of.numchn) + u] = pat[u];
277 }
278
279 /* read comment field */
280 if (mh->commentsize)
281 if (!ReadLinedComment (mh->commentsize / 40, 40))
282 return 0;
283
284 return 1;
285 }
286
287 static CHAR *
MTM_LoadTitle(void)288 MTM_LoadTitle (void)
289 {
290 CHAR s[20];
291
292 _mm_fseek (modreader, 4, SEEK_SET);
293 if (!_mm_read_UBYTES (s, 20, modreader))
294 return NULL;
295
296 return (DupStr (s, 20, 1));
297 }
298
299 /*========== Loader information */
300
301 MLOADER load_mtm =
302 {
303 NULL,
304 "MTM",
305 "MTM (MultiTracker Module editor)",
306 MTM_Init,
307 MTM_Test,
308 MTM_Load,
309 MTM_Cleanup,
310 MTM_LoadTitle
311 };
312
313 /* ex:set ts=4: */
314