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 #define NEED_BYTESWAP
24
25 #include "headers.h"
26 #include "fmt.h"
27
28 #include "it.h"
29 #include "song.h"
30
31 #include "sndfile.h"
32
33 #include <string.h>
34 #include <stdlib.h>
35
36 /* --------------------------------------------------------------------- */
37
38 #pragma pack(push, 1)
39
40 struct xm_point {
41 uint16_t ticks; // Time in tracker ticks
42 uint16_t val; // Value from 0x00 to 0x40.
43 };
44
45 struct xm_sample_header {
46 uint32_t samplen;
47 uint32_t loopstart;
48 uint32_t looplen;
49 uint8_t vol;
50 signed char finetune;
51 uint8_t type;
52 uint8_t pan;
53 signed char relnote;
54 uint8_t res;
55 char name[22];
56 };
57
58 struct xi_sample_header {
59 uint8_t snum[96];
60
61 union {
62 uint16_t env[48]; // Occupies same mem as venv,penv
63 struct {
64 struct xm_point venv[12], penv[12];
65 };
66 };
67
68 uint8_t vnum, pnum;
69 uint8_t vsustain, vloops, vloope, psustain, ploops, ploope;
70 uint8_t vtype, ptype;
71 uint8_t vibtype, vibsweep, vibdepth, vibrate;
72 uint16_t volfade;
73 uint8_t reserved1[0x16];
74 uint16_t nsamples;
75 };
76
77 struct xi_file_header {
78 int8_t header[0x15]; // "Extended Instrument: "
79 int8_t name[0x16]; // Name of instrument
80 uint8_t magic; // 0x1a, DOS EOF char so you can 'type file.xi'
81 int8_t tracker[0x14]; // Name of tracker
82 uint16_t version; // big-endian 0x0102
83 struct xi_sample_header xish;
84 struct xm_sample_header sheader[];
85 };
86 #pragma pack(pop)
87
validate_xi(const struct xi_file_header * xi,size_t length)88 static int validate_xi(const struct xi_file_header *xi, size_t length)
89 {
90 if (length <= sizeof(struct xi_file_header))
91 return 0;
92 if (memcmp(xi->header, "Extended Instrument: ", 21) != 0)
93 return 0;
94 if (xi->magic != 0x1a)
95 return 0;
96 if (bswapLE16(xi->version) != 0x0102)
97 return(0);
98 return(1);
99 }
100
101 /* --------------------------------------------------------------------- */
fmt_xi_read_info(dmoz_file_t * file,const uint8_t * data,size_t length)102 int fmt_xi_read_info(dmoz_file_t *file, const uint8_t *data, size_t length)
103 {
104 struct xi_file_header *xi = (struct xi_file_header *) data;
105
106 if (!validate_xi(xi, length))
107 return 0;
108
109 file->description = "FastTracker Instrument";
110 file->title = strn_dup((const char *)xi->name, 22);
111 file->type = TYPE_INST_XI;
112 return 1;
113 }
114
fmt_xi_load_instrument(const uint8_t * data,size_t length,int slot)115 int fmt_xi_load_instrument(const uint8_t *data, size_t length, int slot)
116 {
117 const struct xi_file_header *xi = (const struct xi_file_header *) data;
118 struct xi_sample_header xmsh;
119 struct instrumentloader ii;
120 song_instrument_t *g;
121 const uint8_t *sampledata, *end;
122 int k, prevtick;
123
124 if (!slot)
125 return 0;
126 if (!validate_xi(xi, length))
127 return 0;
128
129 end = data + length;
130
131 song_delete_instrument(slot, 0);
132
133 g = instrument_loader_init(&ii, slot);
134 memcpy(g->name, xi->name, 22);
135 g->name[22] = '\0';
136
137 xmsh = xi->xish;
138
139 for (k = 0; k < 96; k++) {
140 if (xmsh.snum[k] > 15)
141 xmsh.snum[k] = 15;
142 xmsh.snum[k] = instrument_loader_sample(&ii, xmsh.snum[k] + 1);
143 g->note_map[k + 12] = k + 1 + 12;
144 if (xmsh.snum[k])
145 g->sample_map[k + 12] = xmsh.snum[k];
146 }
147
148 for (k = 0; k < 12; k++) {
149 g->note_map[k] = 0;
150 g->sample_map[k] = 0;
151 g->note_map[k + 108] = 0;
152 g->sample_map[k + 108] = 0;
153 }
154
155 // bswap all volume and panning envelope points
156 for (k = 0; k < 48; k++)
157 xmsh.env[k] = bswapLE16(xmsh.env[k]);
158
159 // Set up envelope types in instrument
160 if (xmsh.vtype & 0x01) g->flags |= ENV_VOLUME;
161 if (xmsh.vtype & 0x02) g->flags |= ENV_VOLSUSTAIN;
162 if (xmsh.vtype & 0x04) g->flags |= ENV_VOLLOOP;
163 if (xmsh.ptype & 0x01) g->flags |= ENV_PANNING;
164 if (xmsh.ptype & 0x02) g->flags |= ENV_PANSUSTAIN;
165 if (xmsh.ptype & 0x04) g->flags |= ENV_PANLOOP;
166
167 prevtick = -1;
168 // Copy envelopes into instrument
169 for (k = 0; k < xmsh.vnum; k++) {
170 if (xmsh.venv[k].ticks < prevtick)
171 prevtick++;
172 else
173 prevtick = xmsh.venv[k].ticks;
174 g->vol_env.ticks[k] = prevtick;
175 g->vol_env.values[k] = xmsh.venv[k].val;
176 }
177
178 prevtick = -1;
179 for (k = 0; k < xmsh.pnum; k++) {
180 if (xmsh.penv[k].ticks < prevtick)
181 prevtick++;
182 else
183 prevtick = xmsh.penv[k].ticks;
184 g->pan_env.ticks[k] = prevtick;
185 g->pan_env.values[k] = xmsh.penv[k].val;
186 }
187
188 g->vol_env.loop_start = xmsh.vloops;
189 g->vol_env.loop_end = xmsh.vloope;
190 g->vol_env.sustain_start = xmsh.vsustain;
191 g->vol_env.nodes = xmsh.vnum;
192
193 g->pan_env.loop_start = xmsh.ploops;
194 g->pan_env.loop_end = xmsh.ploope;
195 g->pan_env.sustain_start = xmsh.psustain;
196 g->pan_env.nodes = xmsh.pnum;
197
198 xmsh.volfade = bswapLE16(xmsh.volfade);
199 xmsh.nsamples = bswapLE16(xmsh.nsamples);
200
201 // Sample data begins at the end of the sample headers
202 sampledata = (const uint8_t *) (xi->sheader + xmsh.nsamples);
203
204 for (k = 0; k < xmsh.nsamples; k++) {
205 struct xm_sample_header xmss = xi->sheader[k];
206 song_sample_t *smp;
207 unsigned int rs, samplesize, n;
208
209 xmss.samplen = bswapLE32(xmss.samplen);
210 xmss.loopstart = bswapLE32(xmss.loopstart);
211 xmss.looplen = bswapLE32(xmss.looplen);
212
213 rs = SF_LE | SF_PCMD; // endianness; encoding
214 rs |= (xmss.type & 0x20) ? SF_SS : SF_M; // channels
215 rs |= (xmss.type & 0x10) ? SF_16 : SF_8; // bits
216
217 if (xmss.type & 0x10) {
218 xmss.looplen >>= 1;
219 xmss.loopstart >>= 1;
220 xmss.samplen >>= 1;
221 }
222 if (xmss.type & 0x20) {
223 xmss.looplen >>= 1;
224 xmss.loopstart >>= 1;
225 xmss.samplen >>= 1;
226 }
227 if (xmss.loopstart >= xmss.samplen)
228 xmss.type &= ~3;
229 xmss.looplen += xmss.loopstart;
230 if (xmss.looplen > xmss.samplen)
231 xmss.looplen = xmss.samplen;
232 if (!xmss.looplen)
233 xmss.type &= ~3;
234
235 n = instrument_loader_sample(&ii, k + 1);
236 smp = song_get_sample(n);
237 smp->flags = 0;
238 memcpy(smp->name, xmss.name, 22);
239 smp->name[21] = '\0';
240
241 samplesize = xmss.samplen;
242 smp->length = samplesize;
243 smp->loop_start = xmss.loopstart;
244 smp->loop_end = xmss.looplen;
245 if (smp->loop_end < smp->loop_start)
246 smp->loop_end = smp->length;
247 if (smp->loop_start >= smp->loop_end)
248 smp->loop_start = smp->loop_end = 0;
249 switch (xmss.type & 3) {
250 case 3: case 2: smp->flags |= CHN_PINGPONGLOOP;
251 case 1: smp->flags |= CHN_LOOP;
252 }
253 smp->volume = xmss.vol << 2;
254 if (smp->volume > 256)
255 smp->volume = 256;
256 smp->global_volume = 64;
257 smp->panning = xmss.pan;
258 smp->flags |= CHN_PANNING;
259 smp->vib_type = xmsh.vibtype;
260 smp->vib_speed = xmsh.vibsweep;
261 smp->vib_depth = xmsh.vibdepth;
262 smp->vib_rate = xmsh.vibrate / 4; // XXX xm.c does not divide here, which is wrong?
263
264 smp->c5speed = transpose_to_frequency(xmss.relnote, xmss.finetune);
265 sampledata += csf_read_sample(current_song->samples + n, rs, sampledata, (end-sampledata));
266 }
267
268 return 1;
269 }
270
271