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 "slurp.h"
27 #include "fmt.h"
28 #include "log.h"
29 
30 #include "sndfile.h"
31 
32 /* --------------------------------------------------------------------------------------------------------- */
33 
34 /* None of the sfx files on Modland are of the 31-instrument type that xmp recognizes.
35 However, there are a number of 31-instrument files with a different tag, under "SoundFX 2". */
36 
37 static struct sfxfmt {
38 	size_t tagpos;
39 	const char tag[4];
40 	int nsmp;
41 	int dunno;
42 	const char *id;
43 } sfxfmts[] = {
44 	{124, "SO31", 31, 4, "SoundFX 2"},
45 	{124, "SONG", 31, 0, "SoundFX 2 (?)"},
46 	{ 60, "SONG", 15, 0, "SoundFX"},
47 	{  0, ""    ,  0, 0, NULL},
48 };
49 
50 
fmt_sfx_read_info(dmoz_file_t * file,const uint8_t * data,size_t length)51 int fmt_sfx_read_info(dmoz_file_t *file, const uint8_t *data, size_t length)
52 {
53 	int n;
54 	for (n = 0; sfxfmts[n].nsmp; n++) {
55 		if (length >= sfxfmts[n].tagpos + 4
56 		    && memcmp(data + sfxfmts[n].tagpos, sfxfmts[n].tag, 4) == 0) {
57 			file->description = sfxfmts[n].id;
58 			/*file->extension = str_dup("sfx");*/
59 			file->title = strdup(""); // whatever
60 			file->type = TYPE_MODULE_MOD;
61 			return 1;
62 		}
63 	}
64 	return 0;
65 }
66 
67 /* --------------------------------------------------------------------------------------------------------- */
68 
69 /* Loader taken mostly from XMP.
70 
71 Why did I write a loader for such an obscure format? That is, besides the fact that neither Modplug nor
72 Mikmod support SFX (and for good reason; it's a particularly dumb format) */
73 
fmt_sfx_load_song(song_t * song,slurp_t * fp,unsigned int lflags)74 int fmt_sfx_load_song(song_t *song, slurp_t *fp, unsigned int lflags)
75 {
76 	uint8_t tag[4];
77 	int n, nord, npat, pat, chan, restart, nsmp = 0;
78 	uint32_t smpsize[31];
79 	uint16_t tmp;
80 	song_note_t *note;
81 	song_sample_t *sample;
82 	unsigned int effwarn = 0;
83 	struct sfxfmt *fmt = sfxfmts;
84 
85 	do {
86 		slurp_seek(fp, fmt->tagpos, SEEK_SET);
87 		slurp_read(fp, tag, 4);
88 		if (memcmp(tag, fmt->tag, 4) == 0) {
89 			nsmp = fmt->nsmp;
90 			break;
91 		}
92 		fmt++;
93 	} while (fmt->nsmp);
94 
95 	if (!nsmp)
96 		return LOAD_UNSUPPORTED;
97 
98 
99 	slurp_rewind(fp);
100 	slurp_read(fp, smpsize, 4 * nsmp);
101 	slurp_seek(fp, 4, SEEK_CUR); /* the tag again */
102 	slurp_read(fp, &tmp, 2);
103 	if (!tmp)
104 		return LOAD_UNSUPPORTED; // erf
105 	tmp = 14565 * 122 / bswapBE16(tmp);
106 	song->initial_tempo = CLAMP(tmp, 31, 255);
107 
108 	slurp_seek(fp, 14, SEEK_CUR); /* unknown bytes (reserved?) - see below */
109 
110 	if (lflags & LOAD_NOSAMPLES) {
111 		slurp_seek(fp, 30 * nsmp, SEEK_CUR);
112 	} else {
113 		for (n = 0, sample = song->samples + 1; n < nsmp; n++, sample++) {
114 			slurp_read(fp, sample->name, 22);
115 			sample->name[22] = 0;
116 			slurp_read(fp, &tmp, 2); /* seems to be half the sample size, minus two bytes? */
117 			tmp = bswapBE16(tmp);
118 			sample->length = bswapBE32(smpsize[n]);
119 
120 			song->samples[n].c5speed = MOD_FINETUNE(slurp_getc(fp)); // ?
121 			sample->volume = slurp_getc(fp);
122 			if (sample->volume > 64)
123 				sample->volume = 64;
124 			sample->volume *= 4; //mphack
125 			sample->global_volume = 64;
126 			slurp_read(fp, &tmp, 2);
127 			sample->loop_start = bswapBE16(tmp);
128 			slurp_read(fp, &tmp, 2);
129 			tmp = bswapBE16(tmp) * 2; /* loop length */
130 			if (tmp > 2) {
131 				sample->loop_end = sample->loop_start + tmp;
132 				sample->flags |= CHN_LOOP;
133 			} else {
134 				sample->loop_start = sample->loop_end = 0;
135 			}
136 		}
137 	}
138 
139 	/* pattern/order stuff */
140 	nord = slurp_getc(fp);
141 	nord = MIN(nord, 127);
142 	restart = slurp_getc(fp);
143 	slurp_read(fp, song->orderlist, nord);
144 	slurp_seek(fp, 128 - nord, SEEK_CUR);
145 	npat = 0;
146 	for (n = 0; n < nord; n++) {
147 		if (song->orderlist[n] > npat)
148 			npat = song->orderlist[n];
149 	}
150 	npat++;
151 
152 	/* Not sure what this is about, but skipping a few bytes here seems to make SO31's load right.
153 	(they all seem to have zero here) */
154 	slurp_seek(fp, fmt->dunno, SEEK_CUR);
155 
156 	if (lflags & LOAD_NOPATTERNS) {
157 		slurp_seek(fp, npat * 1024, SEEK_CUR);
158 	} else {
159 		for (pat = 0; pat < npat; pat++) {
160 			note = song->patterns[pat] = csf_allocate_pattern(64);
161 			song->pattern_size[pat] = song->pattern_alloc_size[pat] = 64;
162 			for (n = 0; n < 64; n++, note += 60) {
163 				for (chan = 0; chan < 4; chan++, note++) {
164 					uint8_t p[4];
165 					slurp_read(fp, p, 4);
166 					mod_import_note(p, note);
167 					/* Note events starting with FF all seem to be special in some way:
168 						bytes   apparent use    example file on modland
169 						-----   ------------    -----------------------
170 						FF FE   note cut        1st intro.sfx
171 						FF FD   unknown!        another world (intro).sfx
172 						FF FC   pattern break   orbit wanderer.sfx2 */
173 					if (p[0] == 0xff) {
174 						switch (p[1]) {
175 						case 0xfc:
176 							note->note = NOTE_NONE;
177 							note->instrument = 0;
178 							// stuff a C00 in channel 5
179 							note[4 - chan].effect = FX_PATTERNBREAK;
180 							break;
181 						case 0xfe:
182 							note->note = NOTE_CUT;
183 							note->instrument = 0;
184 							break;
185 						}
186 					}
187 					switch (note->effect) {
188 					case 0:
189 						break;
190 					case 1: /* arpeggio */
191 						note->effect = FX_ARPEGGIO;
192 						break;
193 					case 2: /* pitch bend */
194 						if (note->param >> 4) {
195 							note->effect = FX_PORTAMENTODOWN;
196 							note->param >>= 4;
197 						} else if (note->param & 0xf) {
198 							note->effect = FX_PORTAMENTOUP;
199 							note->param &= 0xf;
200 						} else {
201 							note->effect = 0;
202 						}
203 						break;
204 					case 5: /* volume up */
205 						note->effect = FX_VOLUMESLIDE;
206 						note->param = (note->param & 0xf) << 4;
207 						break;
208 					case 6: /* set volume */
209 						if (note->param > 64)
210 							note->param = 64;
211 						note->voleffect = VOLFX_VOLUME;
212 						note->volparam = 64 - note->param;
213 						note->effect = 0;
214 						note->param = 0;
215 						break;
216 					case 3: /* LED on (wtf!) */
217 					case 4: /* LED off (ditto) */
218 					case 7: /* set step up */
219 					case 8: /* set step down */
220 					default:
221 						effwarn |= (1 << note->effect);
222 						note->effect = FX_UNIMPLEMENTED;
223 						break;
224 					}
225 				}
226 			}
227 		}
228 		for (n = 0; n < 16; n++) {
229 			if (effwarn & (1 << n))
230 				log_appendf(4, " Warning: Unimplemented effect %Xxx", n);
231 		}
232 
233 		if (restart < npat)
234 			csf_insert_restart_pos(song, restart);
235 	}
236 
237 	/* sample data */
238 	if (!(lflags & LOAD_NOSAMPLES)) {
239 		for (n = 0, sample = song->samples + 1; n < fmt->nsmp; n++, sample++) {
240 			uint32_t ssize;
241 
242 			if (sample->length <= 2)
243 				continue;
244 			ssize = csf_read_sample(sample, SF_8 | SF_LE | SF_PCMS | SF_M,
245 				fp->data + fp->pos, fp->length - fp->pos);
246 			slurp_seek(fp, ssize, SEEK_CUR);
247 		}
248 	}
249 
250 	/* more header info */
251 	song->flags = SONG_ITOLDEFFECTS | SONG_COMPATGXX;
252 	for (n = 0; n < 4; n++)
253 		song->channels[n].panning = PROTRACKER_PANNING(n); /* ??? */
254 	for (; n < MAX_CHANNELS; n++)
255 		song->channels[n].flags = CHN_MUTE;
256 
257 	strcpy(song->tracker_id, fmt->id);
258 	song->pan_separation = 64;
259 
260 //      if (ferror(fp)) {
261 //              return LOAD_FILE_ERROR;
262 //      }
263 
264 	/* done! */
265 	return LOAD_SUCCESS;
266 }
267 
268 
269 /*
270 most of modland's sfx files have all zeroes for those 14 "unknown" bytes, with the following exceptions:
271 
272 64 00 00 00 00 00 00 00 00 00 00 00 00 00  d............. - unknown/antitrax.sfx
273 74 63 68 33 00 00 00 00 00 00 00 00 00 00  tch3.......... - unknown/axel f.sfx
274 61 6c 6b 00 00 00 00 00 00 00 00 00 00 00  alk........... Andreas Hommel/cyberblast-intro.sfx
275 21 00 00 00 00 00 00 00 00 00 00 00 00 00  !............. - unknown/dugger.sfx
276 00 00 00 00 00 0d 00 00 00 00 00 00 00 00  .............. Jean Baudlot/future wars - time travellers - dugger (title).sfx
277 00 00 00 00 00 00 00 00 0d 00 00 00 00 00  .............. Jean Baudlot/future wars - time travellers - escalator.sfx
278 6d 65 31 34 00 00 00 00 00 00 00 00 00 00  me14.......... - unknown/melodious.sfx
279 0d 0d 0d 53 46 58 56 31 2e 38 00 00 00 00  ...SFXV1.8.... AM-FM/sunday morning.sfx
280 61 6c 6b 00 00 00 00 00 00 00 00 00 00 00  alk........... - unknown/sunday morning.sfx
281 6f 67 00 00 00 00 00 00 00 00 00 00 00 00  og............ Philip Jespersen/supaplex.sfx
282 6e 74 20 73 6f 6e 67 00 00 00 00 00 00 00  nt song....... - unknown/sweety.sfx
283 61 6c 6b 00 00 00 00 00 00 00 00 00 00 00  alk........... - unknown/thrust.sfx
284 */
285 
286