comparison ringtools/fc-pwt-comp.c @ 867:dfd98dd46068

ringtools: fc-pwt-comp utility written
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 28 Mar 2022 05:45:31 +0000
parents
children 8eb1f60f6676
comparison
equal deleted inserted replaced
866:1976ce568ccd 867:dfd98dd46068
1 /*
2 * This program compiles a FreeCalypso PWT melody from our ASCII source
3 * format into the compact binary format that will be uploaded into
4 * FC device FFS for use by our BUZM melody player engine.
5 *
6 * The binary format going into FFS consists of 4-byte records;
7 * each record has the following format:
8 *
9 * 1 byte: PWT note code [0,47] going directly into hw register
10 * 1 byte: tone volume in [1,64] range, or 0 means rest period
11 * 2 bytes LE: tone or rest duration in TDMA frames
12 */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <ctype.h>
17 #include <string.h>
18 #include <strings.h>
19
20 static struct pwt_note {
21 char *name;
22 int code;
23 } pwt_notes_table[] = {
24 {"f4", 47}, /* 349 Hz */
25 {"fs4", 43}, /* 370 Hz */
26 {"g4", 39}, /* 392 Hz */
27 {"gs4", 35}, /* 415 Hz */
28 {"a4", 31}, /* 440 Hz */
29 {"as4", 27}, /* 466 Hz */
30 {"b4", 23}, /* 494 Hz */
31 {"c5", 19}, /* 523 Hz */
32 {"cs5", 15}, /* 554 Hz */
33 {"d5", 11}, /* 587 Hz */
34 {"ds5", 7}, /* 622 Hz */
35 {"e5", 3}, /* 659 Hz */
36 {"f5", 46}, /* 698 Hz */
37 {"fs5", 42}, /* 740 Hz */
38 {"g5", 38}, /* 784 Hz */
39 {"gs5", 34}, /* 831 Hz */
40 {"a5", 30}, /* 880 Hz */
41 {"as5", 26}, /* 932 Hz */
42 {"b5", 22}, /* 988 Hz */
43 {"c6", 18}, /* 1047 Hz */
44 {"cs6", 14}, /* 1109 Hz */
45 {"d6", 10}, /* 1175 Hz */
46 {"ds6", 6}, /* 1245 Hz */
47 {"e6", 2}, /* 1319 Hz */
48 {"f6", 45}, /* 1397 Hz */
49 {"fs6", 41}, /* 1480 Hz */
50 {"g6", 37}, /* 1568 Hz */
51 {"gs6", 33}, /* 1661 Hz */
52 {"a6", 29}, /* 1760 Hz */
53 {"as6", 25}, /* 1865 Hz */
54 {"b6", 21}, /* 1976 Hz */
55 {"c7", 17}, /* 2093 Hz */
56 {"cs7", 13}, /* 2217 Hz */
57 {"d7", 9}, /* 2349 Hz */
58 {"ds7", 5}, /* 2489 Hz */
59 {"e7", 1}, /* 2637 Hz */
60 {"f7", 44}, /* 2794 Hz */
61 {"fs7", 40}, /* 2960 Hz */
62 {"g7", 36}, /* 3136 Hz */
63 {"gs7", 32}, /* 3322 Hz */
64 {"a7", 28}, /* 3520 Hz */
65 {"as7", 24}, /* 3729 Hz */
66 {"b7", 20}, /* 3951 Hz */
67 {"c8", 16}, /* 4186 Hz */
68 {"cs8", 12}, /* 4435 Hz */
69 {"d8", 8}, /* 4699 Hz */
70 {"ds8", 4}, /* 4978 Hz */
71 {"e8", 0}, /* 5274 Hz */
72 /* table search terminator */
73 {0, -1}
74 };
75
76 char *infname, *outfname;
77 FILE *inf, *outf;
78 char linebuf[256], *fields[3];
79 int lineno, nfields;
80
81 parse_line_into_fields()
82 {
83 char *cp;
84
85 cp = index(linebuf, '\n');
86 if (!cp) {
87 fprintf(stderr, "%s line %d: missing newline\n",
88 infname, lineno);
89 exit(1);
90 }
91 cp = linebuf;
92 nfields = 0;
93 for (;;) {
94 while (isspace(*cp))
95 cp++;
96 if (*cp == '\0' || *cp == '#')
97 break;
98 if (nfields >= 3) {
99 fprintf(stderr, "%s line %d: too many fields\n",
100 infname, lineno);
101 exit(1);
102 }
103 fields[nfields++] = cp;
104 while (*cp && !isspace(*cp))
105 cp++;
106 if (*cp)
107 *cp++ = '\0';
108 }
109 }
110
111 emit_record(freq, volume, duration)
112 unsigned freq, volume, duration;
113 {
114 putc(freq, outf);
115 putc(volume, outf);
116 putc(duration & 0xFF, outf);
117 putc(duration >> 8, outf);
118 }
119
120 process_tone_entry()
121 {
122 struct pwt_note *tp;
123 unsigned note_vol, duration;
124
125 for (tp = pwt_notes_table; tp->name; tp++)
126 if (!strcmp(tp->name, fields[0]))
127 break;
128 if (tp->code < 0) {
129 fprintf(stderr, "%s line %d: invalid note name\n",
130 infname, lineno);
131 exit(1);
132 }
133 note_vol = strtoul(fields[1], 0, 0);
134 if (note_vol < 1 || note_vol > 64) {
135 fprintf(stderr, "%s line %d: invalid note volume\n",
136 infname, lineno);
137 exit(1);
138 }
139 duration = strtoul(fields[2], 0, 0);
140 if (duration < 1 || duration > 0xFFFF) {
141 fprintf(stderr,
142 "%s line %d: the duration number is out of range\n",
143 infname, lineno);
144 exit(1);
145 }
146 emit_record(tp->code, note_vol, duration);
147 }
148
149 process_rest_entry()
150 {
151 unsigned duration;
152
153 duration = strtoul(fields[1], 0, 0);
154 if (duration < 1 || duration > 0xFFFF) {
155 fprintf(stderr,
156 "%s line %d: the duration number is out of range\n",
157 infname, lineno);
158 exit(1);
159 }
160 emit_record(0, 0, (unsigned) duration);
161 }
162
163 main(argc, argv)
164 char **argv;
165 {
166 if (argc != 3) {
167 fprintf(stderr, "usage: %s src-file bin-file\n", argv[0]);
168 exit(1);
169 }
170 if (strcmp(argv[1], "-")) {
171 infname = argv[1];
172 inf = fopen(infname, "r");
173 if (!inf) {
174 perror(infname);
175 exit(1);
176 }
177 } else {
178 infname = "stdin";
179 inf = stdin;
180 }
181 outfname = argv[2];
182 outf = fopen(outfname, "w");
183 if (!outf) {
184 perror(outfname);
185 exit(1);
186 }
187
188 for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) {
189 parse_line_into_fields();
190 if (!nfields)
191 continue;
192 if (nfields == 3)
193 process_tone_entry();
194 else if (nfields == 2 && !strcmp(fields[0], "rest"))
195 process_rest_entry();
196 else {
197 fprintf(stderr, "%s line %d: invalid syntax\n",
198 infname, lineno);
199 exit(1);
200 }
201 }
202 exit(0);
203 }