1 /* 2 * Schism Tracker - a cross-platform Impulse Tracker clone 3 * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com> 4 * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org> 5 * copyright (c) 2009 Storlek & Mrs. Brisby 6 * copyright (c) 2010-2012 Storlek 7 * URL: http://schismtracker.org/ 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23 24 #define NEED_BYTESWAP 25 #include "headers.h" 26 #include "fmt.h" 27 #include "song.h" 28 #include "tables.h" 29 #include "log.h" 30 31 #include <stdint.h> 32 33 /* --------------------------------------------------------------------- */ 34 35 #pragma pack(push, 1) 36 typedef struct mtm_header { 37 char filever[4]; /* M T M \x10 */ 38 char title[20]; /* asciz */ 39 uint16_t ntracks; 40 uint8_t last_pattern; 41 uint8_t last_order; /* songlength - 1 */ 42 uint16_t msglen; 43 uint8_t nsamples; 44 uint8_t flags; /* always 0 */ 45 uint8_t rows; /* prob. 64 */ 46 uint8_t nchannels; 47 uint8_t panpos[32]; 48 } mtm_header_t; 49 50 typedef struct mtm_sample { 51 char name[22]; 52 uint32_t length, loop_start, loop_end; 53 uint8_t finetune, volume, flags; 54 } mtm_sample_t; 55 #pragma pack(pop) 56 57 /* --------------------------------------------------------------------- */ 58 59 int fmt_mtm_read_info(dmoz_file_t *file, const uint8_t *data, size_t length) 60 { 61 if (!(length > 24 && memcmp(data, "MTM", 3) == 0)) 62 return 0; 63 64 file->description = "MultiTracker Module"; 65 /*file->extension = str_dup("mtm");*/ 66 file->title = strn_dup((const char *)data + 4, 20); 67 file->type = TYPE_MODULE_MOD; 68 return 1; 69 } 70 71 /* --------------------------------------------------------------------------------------------------------- */ 72 73 static void mtm_unpack_track(const uint8_t *b, song_note_t *note, int rows) 74 { 75 int n; 76 77 for (n = 0; n < rows; n++, note++, b += 3) { 78 note->note = ((b[0] & 0xfc) ? ((b[0] >> 2) + 36 + 1) : NOTE_NONE); 79 note->instrument = ((b[0] & 0x3) << 4) | (b[1] >> 4); 80 note->voleffect = VOLFX_NONE; 81 note->volparam = 0; 82 note->effect = b[1] & 0xf; 83 note->param = b[2]; 84 /* From mikmod: volume slide up always overrides slide down */ 85 if (note->effect == 0xa && (note->param & 0xf0)) 86 note->param &= 0xf0; 87 csf_import_mod_effect(note, 0); 88 } 89 } 90 91 int fmt_mtm_load_song(song_t *song, slurp_t *fp, unsigned int lflags) 92 { 93 uint8_t b[192]; 94 uint8_t nchan, nord, npat, nsmp; 95 uint16_t ntrk, comment_len; 96 int n, pat, chan, smp, rows, todo = 0; 97 song_note_t *note; 98 uint16_t tmp; 99 uint32_t tmplong; 100 song_note_t **trackdata, *tracknote; 101 song_sample_t *sample; 102 103 slurp_read(fp, b, 3); 104 if (memcmp(b, "MTM", 3) != 0) 105 return LOAD_UNSUPPORTED; 106 n = slurp_getc(fp); 107 sprintf(song->tracker_id, "MultiTracker %d.%d", n >> 4, n & 0xf); 108 slurp_read(fp, song->title, 20); 109 song->title[20] = 0; 110 slurp_read(fp, &ntrk, 2); 111 ntrk = bswapLE16(ntrk); 112 npat = slurp_getc(fp); 113 nord = slurp_getc(fp) + 1; 114 115 slurp_read(fp, &comment_len, 2); 116 comment_len = bswapLE16(comment_len); 117 118 nsmp = slurp_getc(fp); 119 slurp_getc(fp); /* attribute byte (unused) */ 120 rows = slurp_getc(fp); /* beats per track (translation: number of rows in every pattern) */ 121 if (rows != 64) 122 todo |= 64; 123 rows = MIN(rows, 64); 124 nchan = slurp_getc(fp); 125 126 if (slurp_eof(fp)) { 127 return LOAD_FORMAT_ERROR; 128 } 129 130 for (n = 0; n < 32; n++) { 131 int pan = slurp_getc(fp) & 0xf; 132 pan = SHORT_PANNING(pan); 133 pan *= 4; //mphack 134 song->channels[n].panning = pan; 135 } 136 for (n = nchan; n < MAX_CHANNELS; n++) 137 song->channels[n].flags = CHN_MUTE; 138 139 /* samples */ 140 if (nsmp > MAX_SAMPLES) { 141 log_appendf(4, " Warning: Too many samples"); 142 } 143 for (n = 1, sample = song->samples + 1; n <= nsmp; n++, sample++) { 144 if (n > MAX_SAMPLES) { 145 slurp_seek(fp, 37, SEEK_CUR); 146 continue; 147 } 148 149 /* IT truncates .mtm sample names at the first \0 rather than the normal behavior 150 of presenting them as spaces (k-achaet.mtm has some "junk" in the sample text) */ 151 char name[23]; 152 slurp_read(fp, name, 22); 153 name[22] = '\0'; 154 strcpy(sample->name, name); 155 slurp_read(fp, &tmplong, 4); 156 sample->length = bswapLE32(tmplong); 157 slurp_read(fp, &tmplong, 4); 158 sample->loop_start = bswapLE32(tmplong); 159 slurp_read(fp, &tmplong, 4); 160 sample->loop_end = bswapLE32(tmplong); 161 if ((sample->loop_end - sample->loop_start) > 2) { 162 sample->flags |= CHN_LOOP; 163 } else { 164 /* Both Impulse Tracker and Modplug do this */ 165 sample->loop_start = 0; 166 sample->loop_end = 0; 167 } 168 song->samples[n].c5speed = MOD_FINETUNE(slurp_getc(fp)); 169 sample->volume = slurp_getc(fp); 170 sample->volume *= 4; //mphack 171 sample->global_volume = 64; 172 if (slurp_getc(fp) & 1) { 173 todo |= 16; 174 sample->flags |= CHN_16BIT; 175 sample->length >>= 1; 176 sample->loop_start >>= 1; 177 sample->loop_end >>= 1; 178 } 179 song->samples[n].vib_type = 0; 180 song->samples[n].vib_rate = 0; 181 song->samples[n].vib_depth = 0; 182 song->samples[n].vib_speed = 0; 183 } 184 185 /* orderlist */ 186 slurp_read(fp, song->orderlist, 128); 187 memset(song->orderlist + nord, ORDER_LAST, MAX_ORDERS - nord); 188 189 /* tracks */ 190 trackdata = mem_calloc(ntrk, sizeof(song_note_t *)); 191 for (n = 0; n < ntrk; n++) { 192 slurp_read(fp, b, 3 * rows); 193 trackdata[n] = mem_calloc(rows, sizeof(song_note_t)); 194 mtm_unpack_track(b, trackdata[n], rows); 195 } 196 197 /* patterns */ 198 if (npat >= MAX_PATTERNS) { 199 log_appendf(4, " Warning: Too many patterns"); 200 } 201 for (pat = 0; pat <= npat; pat++) { 202 // skip ones that can't be loaded 203 if (pat >= MAX_PATTERNS) { 204 slurp_seek(fp, 64, SEEK_CUR); 205 continue; 206 } 207 208 song->patterns[pat] = csf_allocate_pattern(MAX(rows, 32)); 209 song->pattern_size[pat] = song->pattern_alloc_size[pat] = 64; 210 for (chan = 0; chan < 32; chan++) { 211 slurp_read(fp, &tmp, 2); 212 tmp = bswapLE16(tmp); 213 if (tmp == 0) { 214 continue; 215 } else if (tmp > ntrk) { 216 for (n = 0; n < ntrk; n++) 217 free(trackdata[n]); 218 free(trackdata); 219 return LOAD_FORMAT_ERROR; 220 } 221 note = song->patterns[pat] + chan; 222 tracknote = trackdata[tmp - 1]; 223 for (n = 0; n < rows; n++, tracknote++, note += MAX_CHANNELS) 224 *note = *tracknote; 225 } 226 if (rows < 32) { 227 /* stick a pattern break on the first channel with an empty effect column 228 * (XXX don't do this if there's already one in another column) */ 229 note = song->patterns[pat] + 64 * (rows - 1); 230 while (note->effect || note->param) 231 note++; 232 note->effect = FX_PATTERNBREAK; 233 } 234 } 235 236 /* free willy */ 237 for (n = 0; n < ntrk; n++) 238 free(trackdata[n]); 239 free(trackdata); 240 241 read_lined_message(song->message, fp, comment_len, 40); 242 243 /* sample data */ 244 if (!(lflags & LOAD_NOSAMPLES)) { 245 for (smp = 1; smp <= nsmp && smp <= MAX_SAMPLES; smp++) { 246 uint32_t ssize; 247 248 if (song->samples[smp].length == 0) 249 continue; 250 ssize = csf_read_sample(song->samples + smp, 251 (SF_LE | SF_PCMU | SF_M 252 | ((song->samples[smp].flags & CHN_16BIT) ? SF_16 : SF_8)), 253 fp->data + fp->pos, fp->length - fp->pos); 254 slurp_seek(fp, ssize, SEEK_CUR); 255 } 256 } 257 258 /* set the rest of the stuff */ 259 song->flags = SONG_ITOLDEFFECTS | SONG_COMPATGXX; 260 261 // if (ferror(fp)) { 262 // return LOAD_FILE_ERROR; 263 // } 264 265 if (todo & 64) 266 log_appendf(2, " TODO: test this file with other players (beats per track != 64)"); 267 if (todo & 16) 268 log_appendf(2, " TODO: double check 16 bit sample loading"); 269 270 /* done! */ 271 return LOAD_SUCCESS; 272 } 273 274