FreeCalypso > hg > freecalypso-tools
comparison ringtools/fc-e1gen.c @ 33:cefdc6623322
fc-e1gen utility written, compiles
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Tue, 25 Oct 2016 06:49:27 +0000 |
parents | |
children | c138906889f7 |
comparison
equal
deleted
inserted
replaced
32:ea061975c883 | 33:cefdc6623322 |
---|---|
1 /* | |
2 * This program is an experimental compiler for TI's Melody E1 format | |
3 * based on the description given in the L1M_AS001_1.pdf document | |
4 * found in the Peek/FGW drop. | |
5 */ | |
6 | |
7 #include <sys/types.h> | |
8 #include <stdio.h> | |
9 #include <stdlib.h> | |
10 #include <ctype.h> | |
11 #include <string.h> | |
12 #include <strings.h> | |
13 | |
14 #define MAX_FIELDS 16 | |
15 | |
16 char *infname, *outfname; | |
17 FILE *inf, *outf; | |
18 char linebuf[512], *fields[MAX_FIELDS+1]; | |
19 int lineno, nfields; | |
20 | |
21 int start_time, osc_mask; | |
22 u_short osc_words[8][4]; | |
23 | |
24 get_input_line() | |
25 { | |
26 char *cp; | |
27 int n; | |
28 | |
29 if (!fgets(linebuf, sizeof linebuf, inf)) { | |
30 fprintf(stderr, "%s: unexpected EOF\n", infname); | |
31 exit(1); | |
32 } | |
33 cp = index(linebuf, '\n'); | |
34 if (!cp) { | |
35 fprintf(stderr, "%s line %d: too long or missing newline\n", | |
36 infname, lineno); | |
37 exit(1); | |
38 } | |
39 *cp = '\0'; | |
40 /* parse it into fields */ | |
41 cp = linebuf; | |
42 n = 0; | |
43 for (;;) { | |
44 while (isspace(*cp)) | |
45 cp++; | |
46 if (*cp == '\0' || *cp == '#') | |
47 break; | |
48 if (n >= MAX_FIELDS) { | |
49 fprintf(stderr, "%s line %d: too many fields\n", | |
50 infname, lineno); | |
51 exit(1); | |
52 } | |
53 fields[n++] = cp; | |
54 while (*cp && !isspace(*cp)) | |
55 cp++; | |
56 if (*cp) | |
57 *cp++ = '\0'; | |
58 } | |
59 fields[n] = 0; | |
60 nfields = n; | |
61 } | |
62 | |
63 input_number(str, min, max) | |
64 char *str; | |
65 { | |
66 char *endp; | |
67 long val; | |
68 | |
69 val = strtol(str, &endp, 10); | |
70 if (*endp) { | |
71 fprintf(stderr, | |
72 "%s line %d: \"%s\" is not a valid decimal number\n", | |
73 infname, lineno, str); | |
74 exit(1); | |
75 } | |
76 if (val < min || val > max) { | |
77 fprintf(stderr, "%s line %d: number %ld is out of range\n", | |
78 infname, lineno, val); | |
79 exit(1); | |
80 } | |
81 return val; | |
82 } | |
83 | |
84 handle_time_line() | |
85 { | |
86 if (nfields != 2) { | |
87 fprintf(stderr, "%s line %d: time header takes 1 argument\n", | |
88 infname, lineno); | |
89 exit(1); | |
90 } | |
91 start_time = input_number(fields[1], 1, 255); | |
92 } | |
93 | |
94 check_req_field(n) | |
95 { | |
96 if (n >= nfields) { | |
97 fprintf(stderr, "%s line %d: too few fields\n", | |
98 infname, lineno); | |
99 exit(1); | |
100 } | |
101 } | |
102 | |
103 process_osc_line() | |
104 { | |
105 int p = 1; | |
106 int oscn, osc_bit; | |
107 u_short word0, word1, word2, word3; | |
108 int amp, freq, length; | |
109 int tremT0, tremFreq; | |
110 int sustain, t1, t2, t3, t5; | |
111 | |
112 check_req_field(p); | |
113 oscn = input_number(fields[p], 0, 7); | |
114 p++; | |
115 osc_bit = 1 << oscn; | |
116 if (osc_mask & osc_bit) { | |
117 fprintf(stderr, "%s line %d: osc %d defined more than once\n", | |
118 infname, lineno, oscn); | |
119 exit(1); | |
120 } | |
121 osc_mask |= osc_bit; | |
122 | |
123 /* basic part */ | |
124 check_req_field(p); | |
125 if (!strcmp(fields[p], "df")) { | |
126 p++; | |
127 check_req_field(p); | |
128 freq = input_number(fields[p], -8192, 8191) & 0x3FFF; | |
129 p++; | |
130 check_req_field(p); | |
131 amp = input_number(fields[p], 0, 1023); | |
132 p++; | |
133 word0 = freq << 2 | 2; | |
134 word1 = amp << 6; | |
135 } else { | |
136 word0 = 0; | |
137 if (!strcmp(fields[p], "sq1")) { | |
138 p++; | |
139 word0 |= 4; | |
140 check_req_field(p); | |
141 } | |
142 if (!strcmp(fields[p], "sq2")) { | |
143 p++; | |
144 word0 |= 8; | |
145 check_req_field(p); | |
146 } | |
147 amp = input_number(fields[p], 0, 63); | |
148 p++; | |
149 check_req_field(p); | |
150 freq = input_number(fields[p], 0, 63); | |
151 p++; | |
152 word0 |= (freq << 10) | (amp << 4); | |
153 check_req_field(p); | |
154 length = input_number(fields[p], 0, 1023); | |
155 p++; | |
156 word1 = length << 6; | |
157 } | |
158 | |
159 /* optional 3rd word */ | |
160 if (p < nfields && !strcmp(fields[p], "trem")) { | |
161 p++; | |
162 word1 |= 0x10; | |
163 check_req_field(p); | |
164 tremT0 = input_number(fields[p], 0, 7); | |
165 p++; | |
166 check_req_field(p); | |
167 tremFreq = input_number(fields[p], -16, 15) & 31; | |
168 p++; | |
169 word2 = (tremFreq << 11) | (tremT0 << 8); | |
170 } | |
171 | |
172 /* optional 4th word */ | |
173 if (p < nfields && !strcmp(fields[p], "env")) { | |
174 p++; | |
175 word1 |= 0x20; | |
176 check_req_field(p); | |
177 sustain = input_number(fields[p], 0, 15); | |
178 p++; | |
179 check_req_field(p); | |
180 t1 = input_number(fields[p], 0, 7); | |
181 p++; | |
182 check_req_field(p); | |
183 t2 = input_number(fields[p], 0, 7); | |
184 p++; | |
185 check_req_field(p); | |
186 t3 = input_number(fields[p], 0, 7); | |
187 p++; | |
188 check_req_field(p); | |
189 t5 = input_number(fields[p], 0, 7); | |
190 p++; | |
191 word3 = (t1 << 13) | (t2 << 10) | (t3 << 7) | (t5 << 4) | | |
192 sustain; | |
193 } | |
194 | |
195 if (p != nfields) { | |
196 fprintf(stderr, "%s line %d: unexpected extra fields\n", | |
197 infname, lineno); | |
198 } | |
199 osc_words[oscn][0] = word0; | |
200 osc_words[oscn][1] = word1; | |
201 osc_words[oscn][2] = word2; | |
202 osc_words[oscn][3] = word3; | |
203 } | |
204 | |
205 read_osc_lines() | |
206 { | |
207 osc_mask = 0; | |
208 for (;;) { | |
209 get_input_line(); | |
210 if (!nfields) | |
211 break; | |
212 if (!strcmp(fields[0], "osc")) { | |
213 process_osc_line(); | |
214 continue; | |
215 } | |
216 fprintf(stderr, "%s line %d: osc line expected\n", | |
217 infname, lineno); | |
218 exit(1); | |
219 } | |
220 if (!osc_mask) { | |
221 fprintf(stderr, "%s line %d: no oscillators defined\n", | |
222 infname, lineno); | |
223 exit(1); | |
224 } | |
225 } | |
226 | |
227 emit_16bit_word(word) | |
228 u_short word; | |
229 { | |
230 putc(word & 0xFF, outf); | |
231 putc(word >> 8, outf); | |
232 } | |
233 | |
234 emit_record() | |
235 { | |
236 int oscn, osc_bit; | |
237 | |
238 putc(start_time, outf); | |
239 putc(osc_mask, outf); | |
240 for (oscn = 0; oscn < 8; oscn++) { | |
241 osc_bit = 1 << oscn; | |
242 if (!(osc_mask & osc_bit)) | |
243 continue; | |
244 emit_16bit_word(osc_words[oscn][0]); | |
245 emit_16bit_word(osc_words[oscn][1]); | |
246 if (osc_words[oscn][1] & 0x10) | |
247 emit_16bit_word(osc_words[oscn][2]); | |
248 if (osc_words[oscn][1] & 0x20) | |
249 emit_16bit_word(osc_words[oscn][3]); | |
250 } | |
251 } | |
252 | |
253 main(argc, argv) | |
254 char **argv; | |
255 { | |
256 if (argc != 3) { | |
257 fprintf(stderr, "usage: %s src-file e1-bin-file\n", argv[0]); | |
258 exit(1); | |
259 } | |
260 if (strcmp(argv[1], "-")) { | |
261 infname = argv[1]; | |
262 inf = fopen(infname, "r"); | |
263 if (!inf) { | |
264 perror(infname); | |
265 exit(1); | |
266 } | |
267 } else { | |
268 infname = "stdin"; | |
269 inf = stdin; | |
270 } | |
271 outfname = argv[2]; | |
272 outf = fopen(outfname, "w"); | |
273 if (!outf) { | |
274 perror(outfname); | |
275 exit(1); | |
276 } | |
277 | |
278 /* main loop */ | |
279 for (;;) { | |
280 do | |
281 get_input_line(); | |
282 while (!nfields); | |
283 if (!strcmp(fields[0], "time")) { | |
284 handle_time_line(); | |
285 read_osc_lines(); | |
286 emit_record(); | |
287 } else if (!strcmp(fields[0], "end")) { | |
288 emit_16bit_word(0); | |
289 exit(0); | |
290 } else { | |
291 fprintf(stderr, "%s line %d: expected time or end\n", | |
292 infname, lineno); | |
293 exit(1); | |
294 } | |
295 } | |
296 } |