1 /*
2 * GoatTracker V2.0 Instrument -> Sound effect convertor
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <ctype.h>
9 #include "bme_end.h"
10 #include "gcommon.h"
11
12 unsigned char swapnybbles(unsigned char n);
13 void outputbyte(unsigned char c);
14
15 int covert = 0;
16 int binary = 0;
17 int bytecount = 0;
18 FILE *handle;
19 FILE *out;
20
main(int argc,char ** argv)21 int main(int argc, char **argv)
22 {
23 int c,d;
24 int prevwave = 0xff;
25 int currwave = 0;
26 int fileok = 0;
27 INSTR instr;
28 int wavelen,pulselen,filtlen;
29 unsigned char ident[4] = {0};
30 unsigned char wavetable[MAX_TABLELEN*2];
31 unsigned char pulsetable[MAX_TABLELEN*2];
32 unsigned char filttable[MAX_TABLELEN*2];
33 unsigned char pulse = 0;
34
35
36 if (argc < 3)
37 {
38 printf("Usage: INS2SND2 <instrumentfile> <sourcecodefile> <options>\n"
39 "-b Produce binary output\n"
40 "-c Produce output in CovertScript format (deprecated)\n\n"
41 "Takes a GoatTracker V1.xx or V2 instrument and outputs the corresponding sound\n"
42 "effect data as source code (default) or binary. Things that can't be converted\n"
43 "and will result in an error:\n"
44 "- Waveforms greater than $81\n"
45 "- Relative notes\n"
46 "- Wavetable longer than 128 bytes\n"
47 "- Absolute notes C-0 & C#0\n"
48 "Things that will be lost in conversion:\n"
49 "- Wavetable loops\n"
50 "- Pulsewidth modulation\n"
51 "- Filter settings\n");
52 return EXIT_FAILURE;
53 }
54
55 if (argc > 3)
56 {
57 for (c = 3; c < argc; c++)
58 {
59 if (((argv[c][0] == '-') || (argv[c][0] == '/')) && (strlen(argv[c]) > 1))
60 {
61 int ch = tolower(argv[c][1]);
62 switch(ch)
63 {
64 case 'b':
65 binary = 1;
66 break;
67
68 case 'c':
69 covert = 1;
70 break;
71 }
72 }
73 }
74 }
75
76
77 handle = fopen(argv[1], "rb");
78 if (!handle)
79 {
80 printf("ERROR: Can't open instrumentfile\n");
81 return EXIT_FAILURE;
82 }
83
84 memset(wavetable, 0, MAX_TABLELEN*2);
85 memset(pulsetable, 0, MAX_TABLELEN*2);
86 memset(filttable, 0, MAX_TABLELEN*2);
87
88 fread(ident, 4, 1, handle);
89 if (!memcmp(ident, "GTI!", 4))
90 {
91 fileok = 1;
92 instr.ad = fread8(handle);
93 instr.sr = fread8(handle);
94 pulse = fread8(handle) & 0xfe;
95 fread8(handle); // Throw away pulse speed
96 fread8(handle); // Throw away pulse limit low
97 fread8(handle); // Throw away pulse limit high
98 fread8(handle); // Throw away filtersetting
99 wavelen = fread8(handle);
100 fread(&instr.name, MAX_INSTRNAMELEN, 1, handle);
101 fread(wavetable, wavelen, 1, handle);
102 }
103 if (!memcmp(ident, "GTI2", 4))
104 {
105 fileok = 1;
106 instr.ad = fread8(handle);
107 instr.sr = fread8(handle);
108 instr.ptr[0] = fread8(handle);
109 instr.ptr[1] = fread8(handle);
110 instr.ptr[2] = fread8(handle);
111 instr.vibdelay = fread8(handle);
112 instr.ptr[3] = fread8(handle);
113 instr.gatetimer = fread8(handle);
114 instr.firstwave = fread8(handle);
115 fread(&instr.name, MAX_INSTRNAMELEN, 1, handle);
116 wavelen = fread8(handle);
117 for (c = 0; c < wavelen; c++)
118 wavetable[c*2] = fread8(handle);
119 for (c = 0; c < wavelen; c++)
120 wavetable[c*2+1] = fread8(handle);
121 pulselen = fread8(handle);
122 for (c = 0; c < pulselen; c++)
123 pulsetable[c*2] = fread8(handle);
124 for (c = 0; c < pulselen; c++)
125 pulsetable[c*2+1] = fread8(handle);
126 filtlen = fread8(handle);
127 for (c = 0; c < filtlen; c++)
128 filttable[c*2] = fread8(handle);
129 for (c = 0; c < filtlen; c++)
130 filttable[c*2+1] = fread8(handle);
131 pulse = (pulsetable[0] << 4) | (pulsetable[1] >> 4);
132 }
133 if ((!memcmp(ident, "GTI3", 4)) || (!memcmp(ident, "GTI4", 4) || (!memcmp(ident, "GTI5", 4))))
134 {
135 fileok = 1;
136 instr.ad = fread8(handle);
137 instr.sr = fread8(handle);
138 instr.ptr[0] = fread8(handle);
139 instr.ptr[1] = fread8(handle);
140 instr.ptr[2] = fread8(handle);
141 instr.ptr[3] = fread8(handle);
142 instr.vibdelay = fread8(handle);
143 instr.gatetimer = fread8(handle);
144 instr.firstwave = fread8(handle);
145 fread(&instr.name, MAX_INSTRNAMELEN, 1, handle);
146 wavelen = fread8(handle);
147 for (c = 0; c < wavelen; c++)
148 wavetable[c*2] = fread8(handle);
149 for (c = 0; c < wavelen; c++)
150 wavetable[c*2+1] = fread8(handle);
151 pulselen = fread8(handle);
152 for (c = 0; c < pulselen; c++)
153 pulsetable[c*2] = fread8(handle);
154 for (c = 0; c < pulselen; c++)
155 pulsetable[c*2+1] = fread8(handle);
156 filtlen = fread8(handle);
157 for (c = 0; c < filtlen; c++)
158 filttable[c*2] = fread8(handle);
159 for (c = 0; c < filtlen; c++)
160 filttable[c*2+1] = fread8(handle);
161 pulse = (pulsetable[0] << 4) | (pulsetable[1] >> 4);
162 }
163 fclose(handle);
164 if (!fileok)
165 {
166 printf("ERROR: File is not a GoatTracker instrument!\n");
167 return EXIT_FAILURE;
168 }
169
170 if (!binary)
171 out = fopen(argv[2], "wt");
172 else
173 out = fopen(argv[2], "wb");
174
175 if (!out)
176 {
177 printf("ERROR: Can't write to output file.\n");
178 return EXIT_FAILURE;
179 }
180
181 d = 0;
182 outputbyte(instr.ad);
183 d++;
184 outputbyte(instr.sr);
185 d++;
186 outputbyte(swapnybbles(pulse));
187 d++;
188
189 for (c = 0; c < MAX_TABLELEN; c++)
190 {
191 if (wavetable[c*2] == 0xff)
192 {
193 outputbyte(0);
194 d++;
195 break;
196 }
197 if (wavetable[c*2+1] < 0x82)
198 {
199 printf("ERROR: Relative note or absolute C-0, C#0 found\n");
200 fclose(out);
201 return EXIT_FAILURE;
202 }
203 if (wavetable[c*2] > 0x81)
204 {
205 printf("ERROR: Waveform greater than $81 found\n");
206 fclose(out);
207 return EXIT_FAILURE;
208 }
209 if (wavetable[c*2])
210 {
211 currwave = wavetable[c*2];
212 }
213 outputbyte(wavetable[c*2+1]);
214 d++;
215 if (currwave != prevwave)
216 {
217 outputbyte(currwave);
218 prevwave = currwave;
219 d++;
220 }
221 }
222 if (d > 255)
223 {
224 fclose(out);
225 printf("ERROR: Sound effect exceeds 255 bytes\n");
226 return EXIT_FAILURE;
227 }
228 fclose(out);
229 return EXIT_SUCCESS;
230 }
231
outputbyte(unsigned char c)232 void outputbyte(unsigned char c)
233 {
234 if (binary)
235 fwrite8(out, c);
236 else
237 {
238 if (!covert)
239 {
240 if (!bytecount)
241 {
242 fprintf(out, " dc.b ");
243 }
244 else fprintf(out, ",");
245 fprintf(out, "$%02X", c);
246 bytecount++;
247 if (bytecount == 16)
248 {
249 bytecount = 0;
250 fprintf(out, "\n");
251 }
252 }
253 else
254 {
255 if (bytecount)
256 {
257 fprintf(out,",");
258 }
259 if (bytecount == 16)
260 {
261 fprintf(out,"\n");
262 bytecount = 0;
263 }
264 bytecount++;
265 fprintf(out, "0x%02x", c);
266 }
267 }
268 }
269
swapnybbles(unsigned char n)270 unsigned char swapnybbles(unsigned char n)
271 {
272 unsigned char highnybble = n >> 4;
273 unsigned char lownybble = n & 0xf;
274
275 return (lownybble << 4) | highnybble;
276 }
277