view trau-decode/parse-new8.c @ 114:4ff5c798c75d

trau-decode: new program trau-parse-n8
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 22 Dec 2025 08:28:44 +0000
parents trau-decode/amr8-readbin.c@028307356ba9
children
line wrap: on
line source

/*
 * This program reads a 64 kbit/s timeslot recording file, examines one
 * of the eight 8 kbit/s subslots (selected), looks for all possible sync
 * patterns (classic HR and TRAU-AMR-8k), and decodes whatever it finds.
 */

#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

static uint8_t *filebuf;
static unsigned total_size;

static void
read_ts_file(filename, subslot_arg)
	char *filename, *subslot_arg;
{
	FILE *inf;
	struct stat st;
	int subslot, right_shift;
	unsigned n;
	uint8_t *dp;
	int b;

	inf = fopen(filename, "r");
	if (!inf) {
		perror(filename);
		exit(1);
	}
	fstat(fileno(inf), &st);
	if (!S_ISREG(st.st_mode)) {
		fprintf(stderr, "error: %s is not a regular file\n", filename);
		exit(1);
	}
	total_size = st.st_size;
	if (total_size < 160) {
		fprintf(stderr, "error: %s is too short\n", filename);
		exit(1);
	}
	filebuf = malloc(total_size);
	if (!filebuf) {
		perror("malloc of file size");
		exit(1);
	}
	subslot = atoi(subslot_arg);
	if (subslot < 0 || subslot > 7) {
		fprintf(stderr, "error: invalid subslot argument\n");
		exit(1);
	}
	right_shift = 7 - subslot;
	dp = filebuf;
	for (n = 0; n < total_size; n++) {
		b = getc(inf);
		if (b < 0) {
			fprintf(stderr,
			"error: getc() returned EOF contrary to st_size\n");
			exit(1);
		}
		*dp++ = (b >> right_shift) & 1;
	}
	fclose(inf);
}

static int
is_classic_hr(cand)
	uint8_t *cand;
{
	unsigned n;

	for (n = 0; n < 8; n++) {
		if (cand[n])
			return 0;
	}
	if (!cand[8])
		return 0;
	if (cand[16])
		return 0;
	if (!cand[17])
		return 0;
	for (n = 3; n < 20; n++) {
		if (!cand[n * 8])
			return 0;
	}
	return 1;
}

static int
check_sync(pos, cont)
	unsigned pos;
{
	uint8_t *cand = filebuf + pos;

	if (is_classic_hr(cand))
		return 1;
	if (is_amr_low(cand))
		return 1;
	if (!cont)
		return 0;
	if (is_amr_67(cand))
		return 1;
	if (is_amr_74(cand))
		return 1;
	return 0;
}

static void
dump_raw_nibbles(bits, num_bits)
	uint8_t *bits;
	unsigned num_bits;
{
	uint8_t *sp = bits;
	unsigned remain = num_bits;

	if (remain >= 4) {
		while (remain >= 4) {
			printf("%x", (sp[0] << 3) | (sp[1] << 2) |
				(sp[2] << 1) | sp[3]);
			sp += 4;
			remain -= 4;
		}
		putchar('\n');
	}
	if (remain) {
		fputs("dribble ", stdout);
		while (remain) {
			printf("%u", *sp++);
			remain--;
		}
		putchar('\n');
	}
}

static int
process_frame(pos)
	unsigned pos;
{
	uint8_t *frame = filebuf + pos;

	printf("Frame at 0x%x:\n", pos);
	dump_raw_nibbles(frame, 160);
	if (is_classic_hr(frame))
		return print_gsmhr_frame(frame);
	else
		return print_amr8_frame(frame);
}

static void
process_filebuf()
{
	unsigned p, nf_pos = 0, nf_accum = 0;
	int match, num_t_bits;
	int in_sync = 0;

	for (p = 0; p < total_size; ) {
		if ((total_size - p) >= 160)
			match = check_sync(p, in_sync);
		else
			match = 0;
		if (match) {
			if (nf_accum) {
				printf("Non-frame at 0x%x:\n", nf_pos);
				dump_raw_nibbles(filebuf + nf_pos, nf_accum);
			}
			num_t_bits = process_frame(p);
			if (num_t_bits == 2 && !filebuf[p+158] &&
			    !filebuf[p+159]) {
				puts("advance of 250 us");
				p += 158;
			} else if (num_t_bits == 2 && filebuf[p+158] &&
				   !filebuf[p+159]) {
				puts("advance of 125 us");
				p += 159;
			} else if (num_t_bits == 1 && !filebuf[p+159]) {
				puts("advance of 125 us");
				p += 159;
			} else
				p += 160;
			nf_pos = p;
			nf_accum = 0;
			in_sync = 1;
		} else {
			p++;
			nf_accum++;
			if (nf_accum >= 320) {
				printf("Non-frame at 0x%x:\n", nf_pos);
				dump_raw_nibbles(filebuf + nf_pos, nf_accum);
				nf_pos = p;
				nf_accum = 0;
			}
			in_sync = 0;
		}
	}
	if (nf_accum) {
		printf("Non-frame at 0x%x:\n", nf_pos);
		dump_raw_nibbles(filebuf + nf_pos, nf_accum);
	}
}

main(argc, argv)
	char **argv;
{
	if (argc != 3) {
		fprintf(stderr, "usage: %s binfile subslot\n", argv[0]);
		exit(1);
	}
	read_ts_file(argv[1], argv[2]);
	process_filebuf();
	exit(0);
}