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 } |
