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 }