FreeCalypso > hg > freecalypso-tools
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ringtools/fc-pwt-comp.c Mon Mar 28 05:45:31 2022 +0000 @@ -0,0 +1,203 @@ +/* + * This program compiles a FreeCalypso PWT melody from our ASCII source + * format into the compact binary format that will be uploaded into + * FC device FFS for use by our BUZM melody player engine. + * + * The binary format going into FFS consists of 4-byte records; + * each record has the following format: + * + * 1 byte: PWT note code [0,47] going directly into hw register + * 1 byte: tone volume in [1,64] range, or 0 means rest period + * 2 bytes LE: tone or rest duration in TDMA frames + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> + +static struct pwt_note { + char *name; + int code; +} pwt_notes_table[] = { + {"f4", 47}, /* 349 Hz */ + {"fs4", 43}, /* 370 Hz */ + {"g4", 39}, /* 392 Hz */ + {"gs4", 35}, /* 415 Hz */ + {"a4", 31}, /* 440 Hz */ + {"as4", 27}, /* 466 Hz */ + {"b4", 23}, /* 494 Hz */ + {"c5", 19}, /* 523 Hz */ + {"cs5", 15}, /* 554 Hz */ + {"d5", 11}, /* 587 Hz */ + {"ds5", 7}, /* 622 Hz */ + {"e5", 3}, /* 659 Hz */ + {"f5", 46}, /* 698 Hz */ + {"fs5", 42}, /* 740 Hz */ + {"g5", 38}, /* 784 Hz */ + {"gs5", 34}, /* 831 Hz */ + {"a5", 30}, /* 880 Hz */ + {"as5", 26}, /* 932 Hz */ + {"b5", 22}, /* 988 Hz */ + {"c6", 18}, /* 1047 Hz */ + {"cs6", 14}, /* 1109 Hz */ + {"d6", 10}, /* 1175 Hz */ + {"ds6", 6}, /* 1245 Hz */ + {"e6", 2}, /* 1319 Hz */ + {"f6", 45}, /* 1397 Hz */ + {"fs6", 41}, /* 1480 Hz */ + {"g6", 37}, /* 1568 Hz */ + {"gs6", 33}, /* 1661 Hz */ + {"a6", 29}, /* 1760 Hz */ + {"as6", 25}, /* 1865 Hz */ + {"b6", 21}, /* 1976 Hz */ + {"c7", 17}, /* 2093 Hz */ + {"cs7", 13}, /* 2217 Hz */ + {"d7", 9}, /* 2349 Hz */ + {"ds7", 5}, /* 2489 Hz */ + {"e7", 1}, /* 2637 Hz */ + {"f7", 44}, /* 2794 Hz */ + {"fs7", 40}, /* 2960 Hz */ + {"g7", 36}, /* 3136 Hz */ + {"gs7", 32}, /* 3322 Hz */ + {"a7", 28}, /* 3520 Hz */ + {"as7", 24}, /* 3729 Hz */ + {"b7", 20}, /* 3951 Hz */ + {"c8", 16}, /* 4186 Hz */ + {"cs8", 12}, /* 4435 Hz */ + {"d8", 8}, /* 4699 Hz */ + {"ds8", 4}, /* 4978 Hz */ + {"e8", 0}, /* 5274 Hz */ + /* table search terminator */ + {0, -1} +}; + +char *infname, *outfname; +FILE *inf, *outf; +char linebuf[256], *fields[3]; +int lineno, nfields; + +parse_line_into_fields() +{ + char *cp; + + cp = index(linebuf, '\n'); + if (!cp) { + fprintf(stderr, "%s line %d: missing newline\n", + infname, lineno); + exit(1); + } + cp = linebuf; + nfields = 0; + for (;;) { + while (isspace(*cp)) + cp++; + if (*cp == '\0' || *cp == '#') + break; + if (nfields >= 3) { + fprintf(stderr, "%s line %d: too many fields\n", + infname, lineno); + exit(1); + } + fields[nfields++] = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + } +} + +emit_record(freq, volume, duration) + unsigned freq, volume, duration; +{ + putc(freq, outf); + putc(volume, outf); + putc(duration & 0xFF, outf); + putc(duration >> 8, outf); +} + +process_tone_entry() +{ + struct pwt_note *tp; + unsigned note_vol, duration; + + for (tp = pwt_notes_table; tp->name; tp++) + if (!strcmp(tp->name, fields[0])) + break; + if (tp->code < 0) { + fprintf(stderr, "%s line %d: invalid note name\n", + infname, lineno); + exit(1); + } + note_vol = strtoul(fields[1], 0, 0); + if (note_vol < 1 || note_vol > 64) { + fprintf(stderr, "%s line %d: invalid note volume\n", + infname, lineno); + exit(1); + } + duration = strtoul(fields[2], 0, 0); + if (duration < 1 || duration > 0xFFFF) { + fprintf(stderr, + "%s line %d: the duration number is out of range\n", + infname, lineno); + exit(1); + } + emit_record(tp->code, note_vol, duration); +} + +process_rest_entry() +{ + unsigned duration; + + duration = strtoul(fields[1], 0, 0); + if (duration < 1 || duration > 0xFFFF) { + fprintf(stderr, + "%s line %d: the duration number is out of range\n", + infname, lineno); + exit(1); + } + emit_record(0, 0, (unsigned) duration); +} + +main(argc, argv) + char **argv; +{ + if (argc != 3) { + fprintf(stderr, "usage: %s src-file bin-file\n", argv[0]); + exit(1); + } + if (strcmp(argv[1], "-")) { + infname = argv[1]; + inf = fopen(infname, "r"); + if (!inf) { + perror(infname); + exit(1); + } + } else { + infname = "stdin"; + inf = stdin; + } + outfname = argv[2]; + outf = fopen(outfname, "w"); + if (!outf) { + perror(outfname); + exit(1); + } + + for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) { + parse_line_into_fields(); + if (!nfields) + continue; + if (nfields == 3) + process_tone_entry(); + else if (nfields == 2 && !strcmp(fields[0], "rest")) + process_rest_entry(); + else { + fprintf(stderr, "%s line %d: invalid syntax\n", + infname, lineno); + exit(1); + } + } + exit(0); +}