changeset 24:8e9bbb83bd16

trau-ul-compile program written
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 24 Jun 2024 01:01:17 +0000
parents bffbe80ffade
children 118a4e4268b2
files .hgignore trau-ul-compile/Makefile trau-ul-compile/trau-ul-compile.c
diffstat 3 files changed, 410 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Sun Jun 23 23:21:45 2024 +0000
+++ b/.hgignore	Mon Jun 24 01:01:17 2024 +0000
@@ -11,5 +11,7 @@
 ^trau-files/.*\.gsmx$
 ^trau-files/.*\.wav$
 
+^trau-ul-compile/trau-ul-compile$
+
 ^trau-ul-prep/efrdec2tsrc$
 ^trau-ul-prep/gsmx2tsrc$
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trau-ul-compile/Makefile	Mon Jun 24 01:01:17 2024 +0000
@@ -0,0 +1,11 @@
+CC=	gcc
+CFLAGS=	-O2
+PROGS=	trau-ul-compile
+
+all:	${PROGS}
+
+trau-ul-compile:	trau-ul-compile.c
+	${CC} ${CFLAGS} -o $@ $@.c -lgsmfr2 -lgsmefr
+
+clean:
+	rm -f *.o ${PROGS}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trau-ul-compile/trau-ul-compile.c	Mon Jun 24 01:01:17 2024 +0000
@@ -0,0 +1,397 @@
+/*
+ * This program compile *.tsrc source format into *.tul binary format,
+ * see ../doc/TRAU-UL-testing article.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <tw_gsmfr.h>
+#include <gsm_efr.h>
+
+#define	MAX_FIELDS	18
+
+static char *infname, *outfname;
+static FILE *inf, *outf;
+
+static int lineno;
+static char linebuf[256];
+static char *fields[MAX_FIELDS];
+static unsigned nfields;
+
+static int is_efr;
+static int16_t speech_params[GSMFR_NUM_PARAMS];
+static int global_params_set, subframe_count;
+static int bfi, bfi_set, sid, sid_set;
+static uint8_t crc_inv, crc_inv_set;
+
+static int
+get_line()
+{
+	char *cp;
+
+	if (!fgets(linebuf, sizeof linebuf, inf))
+		return 1;
+	lineno++;
+	if (!index(linebuf, '\n')) {
+		fprintf(stderr, "%s line %d: too long or missing newline\n",
+			infname, lineno);
+		exit(1);
+	}
+	nfields = 0;
+	for (cp = linebuf; ; ) {
+		while (isspace(*cp))
+			cp++;
+		if (*cp == '\0' || *cp == '#')
+			break;
+		if (nfields >= MAX_FIELDS) {
+			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';
+	}
+	return 0;
+}
+
+static int
+get_line_nonempty()
+{
+	int rc;
+
+	for (;;) {
+		rc = get_line();
+		if (rc)
+			return rc;
+		if (nfields)
+			return 0;
+	}
+}
+
+static void
+start_new_frame()
+{
+	if (nfields != 2 || strcmp(fields[1], "{")) {
+		fprintf(stderr, "%s line %d: invalid frame opening line\n",
+			infname, lineno);
+		exit(1);
+	}
+	global_params_set = 0;
+	subframe_count = 0;
+	bfi = 0;
+	bfi_set = 0;
+	sid_set = 0;
+	crc_inv = 0;
+	crc_inv_set = 0;
+}
+
+static void
+set_speech_params(start_param)
+	unsigned start_param;
+{
+	unsigned ni, no;
+	u_long val;
+	char *cp;
+
+	no = start_param;
+	for (ni = 1; ni < nfields; ni++) {
+		if (!isdigit(fields[ni][0])) {
+inv_number:		fprintf(stderr,
+			"%s line %d: field \"%s\" is not a valid number\n",
+				infname, lineno, fields[ni]);
+			exit(1);
+		}
+		val = strtoul(fields[ni], &cp, 0);
+		if (*cp)
+			goto inv_number;
+		if (val > 0x1FF) {
+			fprintf(stderr,
+	"%s line %d: number \"%s\" is too large for a speech parameter\n",
+				infname, lineno, fields[ni]);
+			exit(1);
+		}
+		speech_params[no++] = val;
+	}
+}
+
+static void
+handle_larc()
+{
+	if (is_efr) {
+		fprintf(stderr, "%s line %d: LARc not valid for EFR\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (nfields != 9) {
+		fprintf(stderr,
+			"%s line %d: wrong number of arguments for LARc\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (global_params_set) {
+		fprintf(stderr, "%s line %d: LARc already set\n",
+			infname, lineno);
+		exit(1);
+	}
+	set_speech_params(0);
+	global_params_set = 1;
+}
+
+static void
+handle_lpc()
+{
+	if (!is_efr) {
+		fprintf(stderr, "%s line %d: LPC not valid for FR\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (nfields != 6) {
+		fprintf(stderr,
+			"%s line %d: wrong number of arguments for LPC\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (global_params_set) {
+		fprintf(stderr, "%s line %d: LPC already set\n",
+			infname, lineno);
+		exit(1);
+	}
+	set_speech_params(0);
+	global_params_set = 1;
+}
+
+static void
+handle_sf()
+{
+	if (is_efr) {
+		if (nfields != 14) {
+			fprintf(stderr,
+			"%s line %d: wrong number of arguments for EFR sf\n",
+				infname, lineno);
+			exit(1);
+		}
+	} else {
+		if (nfields != 18) {
+			fprintf(stderr,
+			"%s line %d: wrong number of arguments for FR sf\n",
+				infname, lineno);
+			exit(1);
+		}
+	}
+	if (subframe_count >= 4) {
+		fprintf(stderr, "%s line %d: too many subframes\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (is_efr)
+		set_speech_params(5 + subframe_count * 13);
+	else
+		set_speech_params(8 + subframe_count * 17);
+	subframe_count++;
+}
+
+static void
+handle_bfi()
+{
+	if (nfields != 2) {
+		fprintf(stderr, "%s line %d: BFI takes one argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (bfi_set) {
+		fprintf(stderr, "%s line %d: BFI already set\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (fields[1][0] < '0' || fields[1][0] > '1' || fields[1][1]) {
+		fprintf(stderr,
+		"%s line %d: invalid BFI argument \"%s\" (must be 0 or 1)\n",
+			infname, lineno, fields[1]);
+		exit(1);
+	}
+	bfi = fields[1][0] - '0';
+	bfi_set = 1;
+}
+
+static void
+handle_sid()
+{
+	if (nfields != 2) {
+		fprintf(stderr, "%s line %d: SID takes one argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (sid_set) {
+		fprintf(stderr, "%s line %d: SID already set\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (fields[1][0] < '0' || fields[1][0] > '2' || fields[1][1]) {
+		fprintf(stderr,
+		"%s line %d: invalid SID argument \"%s\" (must be 0, 1 or 2)\n",
+			infname, lineno, fields[1]);
+		exit(1);
+	}
+	sid = fields[1][0] - '0';
+	sid_set = 1;
+}
+
+static void
+handle_crc_inv()
+{
+	unsigned nf;
+
+	if (!is_efr) {
+		fprintf(stderr, "%s line %d: crc-inv not valid for FR\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (nfields < 2) {
+		fprintf(stderr,
+			"%s line %d: crc-inv requires at least 1 argument\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (crc_inv_set) {
+		fprintf(stderr, "%s line %d: crc-inv already set\n",
+			infname, lineno);
+		exit(1);
+	}
+	for (nf = 1; nf < nfields; nf++) {
+		if (!strcasecmp(fields[nf], "all"))
+			crc_inv = 0xF8;
+		else if (fields[nf][0] >= '0' && fields[nf][0] <= '4' &&
+			 !fields[nf][1])
+			crc_inv |= 0x80 >> (fields[nf][0] - '0');
+		else {
+			fprintf(stderr,
+		"%s line %d: \"%s\" is not a valid argument to crc-inv\n",
+				infname, lineno, fields[nf]);
+			exit(1);
+		}
+	}
+	crc_inv_set = 1;
+}
+
+static void
+process_frame_interior()
+{
+	int rc;
+
+	for (;;) {
+		rc = get_line_nonempty();
+		if (rc) {
+			fprintf(stderr, "bad input: EOF inside frame block\n");
+			exit(1);
+		}
+		if (!strcasecmp(fields[0], "larc"))
+			handle_larc();
+		else if (!strcasecmp(fields[0], "lpc"))
+			handle_lpc();
+		else if (!strcasecmp(fields[0], "sf"))
+			handle_sf();
+		else if (!strcasecmp(fields[0], "bfi"))
+			handle_bfi();
+		else if (!strcasecmp(fields[0], "sid"))
+			handle_sid();
+		else if (!strcasecmp(fields[0], "crc-inv"))
+			handle_crc_inv();
+		else if (!strcmp(fields[0], "}")) {
+			if (nfields != 1) {
+				fprintf(stderr,
+				"%s line %d: stuff after } not permitted\n",
+					infname, lineno);
+				exit(1);
+			}
+			return;
+		} else {
+			fprintf(stderr,
+				"%s line %d: non-understood keyword \"%s\"\n",
+				infname, lineno, fields[0]);
+			exit(1);
+		}
+	}
+}
+
+static void
+finish_frame()
+{
+	uint8_t bin[34];
+
+	if (!global_params_set) {
+		fprintf(stderr, "%s line %d: LARc/LPC parameters not set\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (subframe_count != 4) {
+		fprintf(stderr, "%s line %d: subframe parameters not set\n",
+			infname, lineno);
+		exit(1);
+	}
+	if (is_efr) {
+		EFR_params2frame(speech_params, bin);
+		if (!sid_set)
+			sid = EFR_sid_classify(bin);
+		bin[31] = crc_inv;
+		bin[32] = 0;
+	} else {
+		gsmfr_pack_from_array(speech_params, bin);
+		if (!sid_set)
+			sid = gsmfr_preproc_sid_classify(bin);
+	}
+	bin[33] = (bfi << 7) | sid;
+	fwrite(bin, 1, 34, outf);
+}
+
+main(argc, argv)
+	char **argv;
+{
+	int rc;
+
+	if (argc != 3) {
+		fprintf(stderr, "usage: %s input.tsrc output.tul\n", argv[0]);
+		exit(1);
+	}
+	infname = argv[1];
+	outfname = argv[2];
+
+	inf = fopen(infname, "r");
+	if (!inf) {
+		perror(infname);
+		exit(1);
+	}
+	outf = fopen(outfname, "w");
+	if (!outf) {
+		perror(outfname);
+		exit(1);
+	}
+
+	for (;;) {
+		rc = get_line_nonempty();
+		if (rc)
+			break;
+		if (!strcasecmp(fields[0], "frame_fr")) {
+			is_efr = 0;
+			start_new_frame();
+		} else if (!strcasecmp(fields[0], "frame_efr")) {
+			is_efr = 1;
+			start_new_frame();
+		} else {
+			fprintf(stderr,
+		"%s line %d: expected frame opening line, got something else\n",
+				infname, lineno);
+			exit(1);
+		}
+		process_frame_interior();
+		finish_frame();
+	}
+	exit(0);
+}