view miscutil/fc-tch2fr.c @ 834:c458e33060bf

ffstools/tiaud: prep for adding support for new AEC
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 30 Jul 2021 00:10:13 +0000
parents d57f68d0568d
children
line wrap: on
line source

/*
 * 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);
}