FreeCalypso > hg > freecalypso-tools
view ringtools/fc-pwt-comp.c @ 979:c5133c3c11b1
fc-loadtool flash: implement PL-J PPB programming functions
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 02 Dec 2023 04:21:59 +0000 |
parents | 16e259bff02b |
children |
line wrap: on
line source
/* * 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, duration); } main(argc, argv) char **argv; { int nonempty; 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); } nonempty = 0; 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); } nonempty = 1; } if (nonempty) exit(0); else { fprintf(stderr, "error: %s is empty\n", infname); exit(1); } }