changeset 33:cefdc6623322

fc-e1gen utility written, compiles
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 25 Oct 2016 06:49:27 +0000
parents ea061975c883
children 5ae8f6e55371
files .hgignore ringtools/Makefile ringtools/examples/example.e1src ringtools/fc-e1gen.c
diffstat 4 files changed, 327 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Sun Oct 23 21:52:29 2016 +0000
+++ b/.hgignore	Tue Oct 25 06:49:27 2016 +0000
@@ -22,6 +22,8 @@
 ^miscutil/fc-tch2fr$
 ^miscutil/imei-luhn$
 
+^ringtools/fc-e1gen$
+
 ^rvinterf/asyncshell/fc-shell$
 ^rvinterf/ctracedec/ctracedec$
 ^rvinterf/etmsync/fc-dspapidump$
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ringtools/Makefile	Tue Oct 25 06:49:27 2016 +0000
@@ -0,0 +1,16 @@
+CC=	gcc
+CFLAGS=	-O2
+PROGS=	fc-e1gen
+INSTBIN=/usr/local/bin
+
+all:	${PROGS}
+
+fc-e1gen:	fc-e1gen.c
+	${CC} ${CFLAGS} -o $@ $@.c
+
+install:
+	mkdir -p ${INSTBIN}
+	install -c ${PROGS} ${INSTBIN}
+
+clean:
+	rm -f ${PROGS} *.o *errs *.out
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ringtools/examples/example.e1src	Tue Oct 25 06:49:27 2016 +0000
@@ -0,0 +1,13 @@
+time 1
+osc 0 df 8135 120
+
+time 25
+osc 0 df 0 0
+
+time 25
+osc 0 df 8135 120
+
+time 25
+osc 0 df 0 0
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ringtools/fc-e1gen.c	Tue Oct 25 06:49:27 2016 +0000
@@ -0,0 +1,296 @@
+/*
+ * This program is an experimental compiler for TI's Melody E1 format
+ * based on the description given in the L1M_AS001_1.pdf document
+ * found in the Peek/FGW drop.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+
+#define	MAX_FIELDS	16
+
+char *infname, *outfname;
+FILE *inf, *outf;
+char linebuf[512], *fields[MAX_FIELDS+1];
+int lineno, nfields;
+
+int start_time, osc_mask;
+u_short osc_words[8][4];
+
+get_input_line()
+{
+	char *cp;
+	int n;
+
+	if (!fgets(linebuf, sizeof linebuf, inf)) {
+		fprintf(stderr, "%s: unexpected EOF\n", infname);
+		exit(1);
+	}
+	cp = index(linebuf, '\n');
+	if (!cp) {
+		fprintf(stderr, "%s line %d: too long or missing newline\n",
+			infname, lineno);
+		exit(1);
+	}
+	*cp = '\0';
+	/* parse it into fields */
+	cp = linebuf;
+	n = 0;
+	for (;;) {
+		while (isspace(*cp))
+			cp++;
+		if (*cp == '\0' || *cp == '#')
+			break;
+		if (n >= MAX_FIELDS) {
+			fprintf(stderr, "%s line %d: too many fields\n",
+				infname, lineno);
+			exit(1);
+		}
+		fields[n++] = cp;
+		while (*cp && !isspace(*cp))
+			cp++;
+		if (*cp)
+			*cp++ = '\0';
+	}
+	fields[n] = 0;
+	nfields = n;
+}
+
+input_number(str, min, max)
+	char *str;
+{
+	char *endp;
+	long val;
+
+	val = strtol(str, &endp, 10);
+	if (*endp) {
+		fprintf(stderr,
+			"%s line %d: \"%s\" is not a valid decimal number\n",
+			infname, lineno, str);
+		exit(1);
+	}
+	if (val < min || val > max) {
+		fprintf(stderr, "%s line %d: number %ld is out of range\n",
+			infname, lineno, val);
+		exit(1);
+	}
+	return val;
+}
+
+handle_time_line()
+{
+	if (nfields != 2) {
+		fprintf(stderr, "%s line %d: time header takes 1 argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	start_time = input_number(fields[1], 1, 255);
+}
+
+check_req_field(n)
+{
+	if (n >= nfields) {
+		fprintf(stderr, "%s line %d: too few fields\n",
+			infname, lineno);
+		exit(1);
+	}
+}
+
+process_osc_line()
+{
+	int p = 1;
+	int oscn, osc_bit;
+	u_short word0, word1, word2, word3;
+	int amp, freq, length;
+	int tremT0, tremFreq;
+	int sustain, t1, t2, t3, t5;
+
+	check_req_field(p);
+	oscn = input_number(fields[p], 0, 7);
+	p++;
+	osc_bit = 1 << oscn;
+	if (osc_mask & osc_bit) {
+		fprintf(stderr, "%s line %d: osc %d defined more than once\n",
+			infname, lineno, oscn);
+		exit(1);
+	}
+	osc_mask |= osc_bit;
+
+	/* basic part */
+	check_req_field(p);
+	if (!strcmp(fields[p], "df")) {
+		p++;
+		check_req_field(p);
+		freq = input_number(fields[p], -8192, 8191) & 0x3FFF;
+		p++;
+		check_req_field(p);
+		amp = input_number(fields[p], 0, 1023);
+		p++;
+		word0 = freq << 2 | 2;
+		word1 = amp << 6;
+	} else {
+		word0 = 0;
+		if (!strcmp(fields[p], "sq1")) {
+			p++;
+			word0 |= 4;
+			check_req_field(p);
+		}
+		if (!strcmp(fields[p], "sq2")) {
+			p++;
+			word0 |= 8;
+			check_req_field(p);
+		}
+		amp = input_number(fields[p], 0, 63);
+		p++;
+		check_req_field(p);
+		freq = input_number(fields[p], 0, 63);
+		p++;
+		word0 |= (freq << 10) | (amp << 4);
+		check_req_field(p);
+		length = input_number(fields[p], 0, 1023);
+		p++;
+		word1 = length << 6;
+	}
+
+	/* optional 3rd word */
+	if (p < nfields && !strcmp(fields[p], "trem")) {
+		p++;
+		word1 |= 0x10;
+		check_req_field(p);
+		tremT0 = input_number(fields[p], 0, 7);
+		p++;
+		check_req_field(p);
+		tremFreq = input_number(fields[p], -16, 15) & 31;
+		p++;
+		word2 = (tremFreq << 11) | (tremT0 << 8);
+	}
+
+	/* optional 4th word */
+	if (p < nfields && !strcmp(fields[p], "env")) {
+		p++;
+		word1 |= 0x20;
+		check_req_field(p);
+		sustain = input_number(fields[p], 0, 15);
+		p++;
+		check_req_field(p);
+		t1 = input_number(fields[p], 0, 7);
+		p++;
+		check_req_field(p);
+		t2 = input_number(fields[p], 0, 7);
+		p++;
+		check_req_field(p);
+		t3 = input_number(fields[p], 0, 7);
+		p++;
+		check_req_field(p);
+		t5 = input_number(fields[p], 0, 7);
+		p++;
+		word3 = (t1 << 13) | (t2 << 10) | (t3 << 7) | (t5 << 4) |
+			sustain;
+	}
+
+	if (p != nfields) {
+		fprintf(stderr, "%s line %d: unexpected extra fields\n",
+			infname, lineno);
+	}
+	osc_words[oscn][0] = word0;
+	osc_words[oscn][1] = word1;
+	osc_words[oscn][2] = word2;
+	osc_words[oscn][3] = word3;
+}
+
+read_osc_lines()
+{
+	osc_mask = 0;
+	for (;;) {
+		get_input_line();
+		if (!nfields)
+			break;
+		if (!strcmp(fields[0], "osc")) {
+			process_osc_line();
+			continue;
+		}
+		fprintf(stderr, "%s line %d: osc line expected\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (!osc_mask) {
+		fprintf(stderr, "%s line %d: no oscillators defined\n",
+			infname, lineno);
+		exit(1);
+	}
+}
+
+emit_16bit_word(word)
+	u_short word;
+{
+	putc(word & 0xFF, outf);
+	putc(word >> 8, outf);
+}
+
+emit_record()
+{
+	int oscn, osc_bit;
+
+	putc(start_time, outf);
+	putc(osc_mask, outf);
+	for (oscn = 0; oscn < 8; oscn++) {
+		osc_bit = 1 << oscn;
+		if (!(osc_mask & osc_bit))
+			continue;
+		emit_16bit_word(osc_words[oscn][0]);
+		emit_16bit_word(osc_words[oscn][1]);
+		if (osc_words[oscn][1] & 0x10)
+			emit_16bit_word(osc_words[oscn][2]);
+		if (osc_words[oscn][1] & 0x20)
+			emit_16bit_word(osc_words[oscn][3]);
+	}
+}
+
+main(argc, argv)
+	char **argv;
+{
+	if (argc != 3) {
+		fprintf(stderr, "usage: %s src-file e1-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);
+	}
+
+	/* main loop */
+	for (;;) {
+		do
+			get_input_line();
+		while (!nfields);
+		if (!strcmp(fields[0], "time")) {
+			handle_time_line();
+			read_osc_lines();
+			emit_record();
+		} else if (!strcmp(fields[0], "end")) {
+			emit_16bit_word(0);
+			exit(0);
+		} else {
+			fprintf(stderr, "%s line %d: expected time or end\n",
+				infname, lineno);
+			exit(1);
+		}
+	}
+}