FreeCalypso > hg > freecalypso-tools
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 } |