view hrutil/dec-craft.c @ 552:6ab066180ec2

doc: new article FR1-Rx-DTX-detail
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 07 Oct 2024 00:25:50 +0000
parents 6f8abfe253a4
children
line wrap: on
line source

/*
 * This program facilitates hand-crafting HRv1 decoder input files (*.dec).
 * It reads a line-based ASCII source and compiles it into binary *.dec format.
 */

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "../libgsmhr1/tw_gsmhr.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 int16_t dec_frame[GSMHR_NUM_PARAMS_DEC];
static unsigned taf_count;

static void
set_all_0()
{
	bzero(dec_frame, sizeof(int16_t) * GSMHR_NUM_PARAMS);
}

static void
set_dhf()
{
	bcopy(gsmhr_dhf_params, dec_frame, sizeof(int16_t) * GSMHR_NUM_PARAMS);
}

static void
set_sid_cw()
{
	/* Int_LPC and Mode */
	dec_frame[4] = 1;
	dec_frame[5] = 3;
	/* subframe 1 */
	dec_frame[6] = 0xFF;
	dec_frame[7] = 0x1FF;
	dec_frame[8] = 0x1F;
	/* subframe 2 */
	dec_frame[9] = 0xF;
	dec_frame[10] = 0x1FF;
	dec_frame[11] = 0x1F;
	/* subframe 3 */
	dec_frame[12] = 0xF;
	dec_frame[13] = 0x1FF;
	dec_frame[14] = 0x1F;
	/* subframe 4 */
	dec_frame[15] = 0xF;
	dec_frame[16] = 0x1FF;
	dec_frame[17] = 0x1F;
}

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
set_speech_params(start_param, start_arg)
	unsigned start_param, start_arg;
{
	unsigned ni, no;
	u_long val;
	char *cp;

	no = start_param;
	for (ni = start_arg; ni < nfields; ni++) {
		if (!isxdigit(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, 16);
		if (*cp)
			goto inv_number;
		if (val > 0x7FF) {
			fprintf(stderr,
	"%s line %d: number \"%s\" is too large for a speech parameter\n",
				infname, lineno, fields[ni]);
			exit(1);
		}
		dec_frame[no++] = val;
	}
}

static void
handle_r0()
{
	if (nfields != 2) {
		fprintf(stderr, "%s line %d: R0 takes one argument\n",
			infname, lineno);
		exit(1);
	}
	set_speech_params(0, 1);
}

static void
handle_lpc()
{
	if (nfields != 5) {
		fprintf(stderr, "%s line %d: LPC takes 4 arguments\n",
			infname, lineno);
		exit(1);
	}
	set_speech_params(1, 1);
}

static void
handle_mode()
{
	if (nfields != 2) {
		fprintf(stderr, "%s line %d: Mode takes one argument\n",
			infname, lineno);
		exit(1);
	}
	set_speech_params(5, 1);
}

static void
handle_sf()
{
	unsigned sf_0_based;

	if (nfields != 5) {
		fprintf(stderr, "%s line %d: sf takes 4 arguments\n",
			infname, lineno);
		exit(1);
	}
	if (fields[1][0] < '1' || fields[1][0] > '4' || fields[1][1]) {
		fprintf(stderr,
		"%s line %d: first argument to sf must be in range [1,4]\n",
			infname, lineno);
		exit(1);
	}
	sf_0_based = fields[1][0] - '1';
	set_speech_params(6 + sf_0_based * 3, 2);
}

static void
handle_bfi()
{
	if (nfields != 2) {
		fprintf(stderr, "%s line %d: BFI takes one argument\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);
	}
	dec_frame[18] = fields[1][0] - '0';
}

static void
handle_ufi()
{
	if (nfields != 2) {
		fprintf(stderr, "%s line %d: UFI takes one argument\n",
			infname, lineno);
		exit(1);
	}
	if (fields[1][0] < '0' || fields[1][0] > '1' || fields[1][1]) {
		fprintf(stderr,
		"%s line %d: invalid UFI argument \"%s\" (must be 0 or 1)\n",
			infname, lineno, fields[1]);
		exit(1);
	}
	dec_frame[19] = fields[1][0] - '0';
}

static void
handle_sid()
{
	if (nfields != 2) {
		fprintf(stderr, "%s line %d: SID takes one argument\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);
	}
	dec_frame[20] = fields[1][0] - '0';
}

static void
set_taf_count()
{
	if (nfields != 2) {
		fprintf(stderr, "%s line %d: taf-count takes one argument\n",
			infname, lineno);
		exit(1);
	}
	taf_count = atoi(fields[1]);
	if (taf_count > 11) {
		fprintf(stderr,
			"%s line %d: taf-count argument \"%s\" is invalid\n",
			infname, lineno, fields[1]);
		exit(1);
	}
}

static void
emit_frame()
{
	if (gsmhr_check_common_params(dec_frame) < 0) {
		fprintf(stderr,
	"%s line %d: one of the preceding speech parameters is out of range\n",
			infname, lineno);
		exit(1);
	}
	dec_frame[21] = (taf_count == 11);
	fwrite(dec_frame, 2, GSMHR_NUM_PARAMS_DEC, outf);
	taf_count++;
	if (taf_count >= 12)
		taf_count = 0;
}

main(argc, argv)
	char **argv;
{
	int rc;

	if (argc != 3) {
		fprintf(stderr, "usage: %s input.src output.dec\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], "all-0"))
			set_all_0();
		else if (!strcasecmp(fields[0], "dhf"))
			set_dhf();
		else if (!strcasecmp(fields[0], "r0"))
			handle_r0();
		else if (!strcasecmp(fields[0], "lpc"))
			handle_lpc();
		else if (!strcasecmp(fields[0], "mode"))
			handle_mode();
		else if (!strcasecmp(fields[0], "sf"))
			handle_sf();
		else if (!strcasecmp(fields[0], "bfi"))
			handle_bfi();
		else if (!strcasecmp(fields[0], "ufi"))
			handle_ufi();
		else if (!strcasecmp(fields[0], "sid"))
			handle_sid();
		else if (!strcasecmp(fields[0], "sid-cw"))
			set_sid_cw();
		else if (!strcasecmp(fields[0], "taf-count"))
			set_taf_count();
		else if (!strcasecmp(fields[0], "emit-frame"))
			emit_frame();
		else {
			fprintf(stderr,
				"%s line %d: non-understood keyword \"%s\"\n",
				infname, lineno, fields[0]);
			exit(1);
		}
	}
	exit(0);
}