/ source / libxmp-lite / src / mtm_load.c
mtm_load.c
  1  /* Extended Module Player
  2   * Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
  3   *
  4   * Permission is hereby granted, free of charge, to any person obtaining a
  5   * copy of this software and associated documentation files (the "Software"),
  6   * to deal in the Software without restriction, including without limitation
  7   * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8   * and/or sell copies of the Software, and to permit persons to whom the
  9   * Software is furnished to do so, subject to the following conditions:
 10   *
 11   * The above copyright notice and this permission notice shall be included in
 12   * all copies or substantial portions of the Software.
 13   *
 14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20   * THE SOFTWARE.
 21   */
 22  
 23  #include "loader.h"
 24  
 25  struct mtm_file_header {
 26  	uint8 magic[3];		/* "MTM" */
 27  	uint8 version;		/* MSN=major, LSN=minor */
 28  	uint8 name[20];		/* ASCIIZ Module name */
 29  	uint16 tracks;		/* Number of tracks saved */
 30  	uint8 patterns;		/* Number of patterns saved */
 31  	uint8 modlen;		/* Module length */
 32  	uint16 extralen;	/* Length of the comment field */
 33  	uint8 samples;		/* Number of samples */
 34  	uint8 attr;		/* Always zero */
 35  	uint8 rows;		/* Number rows per track */
 36  	uint8 channels;		/* Number of tracks per pattern */
 37  	uint8 pan[32];		/* Pan positions for each channel */
 38  };
 39  
 40  struct mtm_instrument_header {
 41  	uint8 name[22];		/* Instrument name */
 42  	uint32 length;		/* Instrument length in bytes */
 43  	uint32 loop_start;	/* Sample loop start */
 44  	uint32 loopend;		/* Sample loop end */
 45  	uint8 finetune;		/* Finetune */
 46  	uint8 volume;		/* Playback volume */
 47  	uint8 attr;		/* &0x01: 16bit sample */
 48  };
 49  
 50  static int mtm_test(HIO_HANDLE *, char *, const int);
 51  static int mtm_load(struct module_data *, HIO_HANDLE *, const int);
 52  
 53  const struct format_loader libxmp_loader_mtm = {
 54  	"Multitracker",
 55  	mtm_test,
 56  	mtm_load
 57  };
 58  
 59  static int mtm_test(HIO_HANDLE *f, char *t, const int start)
 60  {
 61  	uint8 buf[4];
 62  
 63  	if (hio_read(buf, 1, 4, f) < 4)
 64  		return -1;
 65  	if (memcmp(buf, "MTM", 3))
 66  		return -1;
 67  	if (buf[3] != 0x10)
 68  		return -1;
 69  
 70  	libxmp_read_title(f, t, 20);
 71  
 72  	return 0;
 73  }
 74  
 75  static int mtm_load(struct module_data *m, HIO_HANDLE *f, const int start)
 76  {
 77  	struct xmp_module *mod = &m->mod;
 78  	int i, j, k;
 79  	struct mtm_file_header mfh;
 80  	struct mtm_instrument_header mih;
 81  	uint8 mt[192];
 82  	int fxx[2];
 83  
 84  	LOAD_INIT();
 85  
 86  	hio_read(mfh.magic, 3, 1, f);	/* "MTM" */
 87  	mfh.version = hio_read8(f);	/* MSN=major, LSN=minor */
 88  	hio_read(mfh.name, 20, 1, f);	/* ASCIIZ Module name */
 89  	mfh.tracks = hio_read16l(f);	/* Number of tracks saved */
 90  	mfh.patterns = hio_read8(f);	/* Number of patterns saved */
 91  	mfh.modlen = hio_read8(f);	/* Module length */
 92  	mfh.extralen = hio_read16l(f);	/* Length of the comment field */
 93  
 94  	mfh.samples = hio_read8(f);	/* Number of samples */
 95  	if (mfh.samples > 63) {
 96  		return -1;
 97  	}
 98  
 99  	mfh.attr = hio_read8(f);	/* Always zero */
100  
101  	mfh.rows = hio_read8(f);	/* Number rows per track */
102  	if (mfh.rows != 64)
103  		return -1;
104  
105  	mfh.channels = hio_read8(f);	/* Number of tracks per pattern */
106  	if (mfh.channels > MIN(32, XMP_MAX_CHANNELS)) {
107  		return -1;
108  	}
109  
110  	hio_read(mfh.pan, 32, 1, f);	/* Pan positions for each channel */
111  
112  	if (hio_error(f)) {
113  		return -1;
114  	}
115  
116  #if 0
117  	if (strncmp((char *)mfh.magic, "MTM", 3))
118  		return -1;
119  #endif
120  
121  	mod->trk = mfh.tracks + 1;
122  	mod->pat = mfh.patterns + 1;
123  	mod->len = mfh.modlen + 1;
124  	mod->ins = mfh.samples;
125  	mod->smp = mod->ins;
126  	mod->chn = mfh.channels;
127  	mod->spd = 6;
128  	mod->bpm = 125;
129  
130  	strncpy(mod->name, (char *)mfh.name, 20);
131  	libxmp_set_type(m, "MultiTracker %d.%02d MTM", MSN(mfh.version),
132  		 LSN(mfh.version));
133  
134  	MODULE_INFO();
135  
136  	if (libxmp_init_instrument(m) < 0)
137  		return -1;
138  
139  	/* Read and convert instruments */
140  	for (i = 0; i < mod->ins; i++) {
141  		struct xmp_instrument *xxi = &mod->xxi[i];
142  		struct xmp_sample *xxs = &mod->xxs[i];
143  		struct xmp_subinstrument *sub;
144  
145  		if (libxmp_alloc_subinstrument(mod, i, 1) < 0)
146  			return -1;
147  
148  		sub = &xxi->sub[0];
149  
150  		hio_read(mih.name, 22, 1, f);	/* Instrument name */
151  		mih.length = hio_read32l(f);	/* Instrument length in bytes */
152  
153  		if (mih.length > MAX_SAMPLE_SIZE)
154  			return -1;
155  
156  		mih.loop_start = hio_read32l(f); /* Sample loop start */
157  		mih.loopend = hio_read32l(f);	/* Sample loop end */
158  		mih.finetune = hio_read8(f);	/* Finetune */
159  		mih.volume = hio_read8(f);	/* Playback volume */
160  		mih.attr = hio_read8(f);	/* &0x01: 16bit sample */
161  
162  		xxs->len = mih.length;
163  		xxs->lps = mih.loop_start;
164  		xxs->lpe = mih.loopend;
165  		xxs->flg = (xxs->lpe > 2) ? XMP_SAMPLE_LOOP : 0;	/* 1 == Forward loop */
166  		if (mfh.attr & 1) {
167  			xxs->flg |= XMP_SAMPLE_16BIT;
168  			xxs->len >>= 1;
169  			xxs->lps >>= 1;
170  			xxs->lpe >>= 1;
171  		}
172  
173  		sub->vol = mih.volume;
174  		sub->fin = mih.finetune;
175  		sub->pan = 0x80;
176  		sub->sid = i;
177  
178  		libxmp_instrument_name(mod, i, mih.name, 22);
179  
180  		if (xxs->len > 0)
181  			mod->xxi[i].nsm = 1;
182  
183  		D_(D_INFO "[%2X] %-22.22s %04x%c%04x %04x %c V%02x F%+03d\n", i,
184  		   xxi->name, xxs->len, xxs->flg & XMP_SAMPLE_16BIT ? '+' : ' ',
185  		   xxs->lps, xxs->lpe, xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ',
186  		   sub->vol, sub->fin - 0x80);
187  	}
188  
189  	hio_read(mod->xxo, 1, 128, f);
190  
191  	if (libxmp_init_pattern(mod) < 0)
192  		return -1;
193  
194  	D_(D_INFO "Stored tracks: %d", mod->trk - 1);
195  
196  	fxx[0] = fxx[1] = 0;
197  	for (i = 0; i < mod->trk; i++) {
198  
199  		if (libxmp_alloc_track(mod, i, mfh.rows) < 0)
200  			return -1;
201  
202  		if (i == 0)
203  			continue;
204  
205  		if (hio_read(mt, 3, 64, f) != 64)
206  			return -1;
207  
208  		for (j = 0; j < 64; j++) {
209  			struct xmp_event *e = &mod->xxt[i]->event[j];
210  			uint8 *d = mt + j * 3;
211  
212  			e->note = d[0] >> 2;
213  			if (e->note) {
214  				e->note += 37;
215  			}
216  			e->ins = ((d[0] & 0x3) << 4) + MSN(d[1]);
217  			e->fxt = LSN(d[1]);
218  			e->fxp = d[2];
219  			if (e->fxt > FX_SPEED) {
220  				e->fxt = e->fxp = 0;
221  			}
222  
223  			/* See tempo mode detection below. */
224  			if (e->fxt == FX_SPEED) {
225  				fxx[e->fxp >= 0x20] = 1;
226  			}
227  
228  			/* Set pan effect translation */
229  			if (e->fxt == FX_EXTENDED && MSN(e->fxp) == 0x8) {
230  				e->fxt = FX_SETPAN;
231  				e->fxp <<= 4;
232  			}
233  		}
234  	}
235  
236  	/* Read patterns */
237  	D_(D_INFO "Stored patterns: %d", mod->pat - 1);
238  
239  	for (i = 0; i < mod->pat; i++) {
240  		if (libxmp_alloc_pattern(mod, i) < 0)
241  			return -1;
242  
243  		mod->xxp[i]->rows = 64;
244  		for (j = 0; j < 32; j++) {
245  			int track = hio_read16l(f);
246  
247  			if (track >= mod->trk) {
248  				track = 0;
249  			}
250  
251  			if (j < mod->chn) {
252  				mod->xxp[i]->index[j] = track;
253  			}
254  		}
255  	}
256  
257  	/* Tempo mode detection.
258  	 *
259  	 * The MTM tempo effect has an unusual property: when speed is set, the
260  	 * tempo resets to 125, and when tempo is set, the speed resets to 6.
261  	 * Modules that use both speed and tempo effects need to emulate this.
262  	 * See: Absolve the Ambience by Sybaris, Soma by Ranger Rick.
263  	 *
264  	 * Dual Module Player and other DOS players did not know about this and
265  	 * did not implement support for it, and instead used Protracker Fxx.
266  	 * Many MTM authors created modules that rely on this which are various
267  	 * degrees of broken in the tracker they were made with! Several MTMs
268  	 * by Phoenix and Silent Mode expect this. The majority of them can be
269  	 * detected by checking for high Fxx and low Fxx on the same row.
270  	 */
271  	if (fxx[0] && fxx[1]) {
272  		/* Both used, check patterns. */
273  		D_(D_INFO "checking patterns for MT or DMP Fxx effect usage");
274  		for (i = 0; i < mod->pat; i++) {
275  			for (j = 0; j < mfh.rows; j++) {
276  				fxx[0] = fxx[1] = 0;
277  				for (k = 0; k < mod->chn; k++) {
278  					struct xmp_event *e = &EVENT(i, k, j);
279  					if (e->fxt == FX_SPEED) {
280  						fxx[e->fxp >= 0x20] = 1;
281  					}
282  				}
283  				if (fxx[0] && fxx[1]) {
284  					/* Same row, no change required */
285  					D_(D_INFO "probably DMP (%d:%d)", i, j);
286  					goto probably_dmp;
287  				}
288  			}
289  		}
290  		D_(D_INFO "probably MT; injecting speed/BPM reset effects");
291  		for (i = 0; i < mod->pat; i++) {
292  			for (j = 0; j < mfh.rows; j++) {
293  				for (k = 0; k < mod->chn; k++) {
294  					struct xmp_event *e = &EVENT(i, k, j);
295  					if (e->fxt == FX_SPEED) {
296  						e->f2t = FX_SPEED;
297  						e->f2p = (e->fxp < 0x20) ? 125 : 6;
298  					}
299  				}
300  			}
301  		}
302  	}
303      probably_dmp:
304  
305  	/* Comments */
306  	if (mfh.extralen) {
307  		m->comment = (char *)Xmalloc(mfh.extralen + 1);
308  		if (m->comment) {
309  			/* Comments are stored in 40 byte ASCIIZ lines. */
310  			int len = hio_read(m->comment, 1, mfh.extralen, f);
311  			int line, last_line = 0;
312  
313  			for (i = 0; i + 40 <= len; i += 40) {
314  				if (m->comment[i] != '\0')
315  					last_line = i + 40;
316  			}
317  			for (j = 0, line = 0; line < last_line; line += 40) {
318  				char *pos = m->comment + line;
319  				for (i = 0; i < 39; i++) {
320  					if (pos[i] == '\0')
321  						break;
322  					m->comment[j++] = pos[i];
323  				}
324  				m->comment[j++] = '\n';
325  			}
326  			m->comment[j] = '\0';
327  		} else {
328  			hio_seek(f, mfh.extralen, SEEK_CUR);
329  		}
330  	}
331  
332  	/* Read samples */
333  	D_(D_INFO "Stored samples: %d", mod->smp);
334  
335  	for (i = 0; i < mod->ins; i++) {
336  		if (libxmp_load_sample(m, f, SAMPLE_FLAG_UNS, &mod->xxs[i], NULL) < 0)
337  			return -1;
338  	}
339  
340  	for (i = 0; i < mod->chn; i++)
341  		mod->xxc[i].pan = mfh.pan[i] << 4;
342  
343  	return 0;
344  }