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