diff tchtools/fc-tch2fr.c @ 902:8ddb16a37273

tree org: move TCH and VM utils from miscutil to tchtools
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 28 Dec 2022 07:52:30 +0000
parents miscutil/fc-tch2fr.c@d57f68d0568d
children a7ad6b39e01b
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tchtools/fc-tch2fr.c	Wed Dec 28 07:52:30 2022 +0000
@@ -0,0 +1,94 @@
+/*
+ * Our experimental Calypso firmware enables us to capture the output of
+ * the GSM 05.03 channel decoder in the DSP, i.e., the bits leaving the
+ * channel decoder and going into the speech decoder.  Our fc-shell utility
+ * allows saving this capture to a file; the captured booty includes not only
+ * the expected 260 bits per frame, but also some DSP status words which are
+ * not fully understood, but which are believed to contain indications as to
+ * whether the decoded speech frame is good or bad.
+ *
+ * My first naive thought was to save the captured speech frames in libgsm
+ * format so I could then play them with the 'play' command (SoX package)
+ * under Linux, but the problem with this naive approach is that the bad frames
+ * indication is lost, and some of the saved "speech" frames will contain
+ * utter garbage, resulting in very unkind-on-ears noises if that file is
+ * then played.  I don't know what the proper solution should be; I don't know
+ * what the commercial cellphone implementations of the GSM 06.10 speech decoder
+ * (buried in black box DSPs) do when they get bad frames from the channel
+ * decoder.
+ *
+ * The present utility reproduces the naive behaviour of my previous
+ * implementation of fc-shell's tch record command: it takes hex files written
+ * by the current implementation of tch record in fc-shell, DISREGARDS the
+ * DSP status words, and blindly converts each 260-bit frame (good or bad)
+ * into libgsm format.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static
+decode_hex_digit(ch)
+{
+	if (isdigit(ch))
+		return(ch - '0');
+	else if (isupper(ch))
+		return(ch - 'A' + 10);
+	else
+		return(ch - 'a' + 10);
+}
+
+main(argc, argv)
+	char **argv;
+{
+	FILE *inf, *outf;
+	char linebuf[128];
+	int lineno;
+	char *cp;
+	int i, j;
+	u_char tidsp_bytes[33], libgsm_bytes[33];
+
+	if (argc != 3) {
+		fprintf(stderr, "usage: %s infile outfile\n", argv[0]);
+		exit(1);
+	}
+	inf = fopen(argv[1], "r");
+	if (!inf) {
+		perror(argv[1]);
+		exit(1);
+	}
+	outf = fopen(argv[2], "w");
+	if (!outf) {
+		perror(argv[2]);
+		exit(1);
+	}
+	for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) {
+		/* skip DSP status words */
+		cp = linebuf;
+		for (i = 0; i < 3; i++) {
+			for (j = 0; j < 4; j++) {
+				if (!isxdigit(*cp++)) {
+invalid:				fprintf(stderr,
+				    "error: %s is not in the expected format\n",
+						argv[1]);
+					exit(1);
+				}
+			}
+			if (*cp++ != ' ')
+				goto invalid;
+		}
+		/* read the frame bits */
+		for (i = 0; i < 33; i++) {
+			if (!isxdigit(cp[0]) || !isxdigit(cp[1]))
+				goto invalid;
+			tidsp_bytes[i] = (decode_hex_digit(cp[0]) << 4) |
+					  decode_hex_digit(cp[1]);
+			cp += 2;
+		}
+		gsm0610_tidsp_to_libgsm(tidsp_bytes, libgsm_bytes);
+		fwrite(libgsm_bytes, 1, 33, outf);
+	}
+	exit(0);
+}