1 /* MikMod sound library 2 (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for 3 complete list. 4 sel_registerNamenull5 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 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 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 108 MTM_Cleanup (void) 109 { 110 _mm_free (mtmtrk); 111 _mm_free (mh); 112 } 113 114 static UBYTE * 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 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 * 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