view efrtest/etsi-dec.c @ 140:5efc377326da

gsmefr-dlcap-gsmx: EFR counterpart to gsmfr-cvt-dlcap
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 13 Dec 2022 07:14:41 +0000
parents e5ee684c6d29
children 8ed838709897
line wrap: on
line source

/*
 * gsmefr-etsi-dec is a test program for our EFR decoder: it reads ETSI's
 * .dec format as input and writes raw 16-bit PCM (same as ETSI's *.out)
 * as output, allowing our decoder to be tested with ETSI's official test
 * sequences.
 *
 * ETSI input and output files are read and written in LE byte order,
 * matching the official test sequences in ts_100725v050200p0.zip.
 */

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "../libgsmefr/gsm_efr.h"

#define	ETSI_DEC_NWORDS	247

static int
read_input(inf, bitvec, filename_for_errs)
	FILE *inf;
	uint8_t *bitvec;
	char *filename_for_errs;
{
	uint8_t file_bytes[ETSI_DEC_NWORDS * 2], *sp;
	int cc;
	unsigned n;

	cc = fread(file_bytes, 2, ETSI_DEC_NWORDS, inf);
	if (cc == 0)
		return 0;
	if (cc != ETSI_DEC_NWORDS) {
		fprintf(stderr, "error: short read from %s\n",
			filename_for_errs);
		exit(1);
	}
	sp = file_bytes;
	for (n = 0; n < ETSI_DEC_NWORDS; n++) {
		if (sp[1]) {
			fprintf(stderr,
		"error in %s: non-zero in what should be LE upper byte\n",
				filename_for_errs);
			exit(1);
		}
		bitvec[n] = sp[0];
		sp += 2;
	}
	return 1;
}

static void
bits2frame(input_bits, frame, filename_for_errs, frame_no)
	uint8_t *input_bits, *frame;
	char *filename_for_errs;
	unsigned frame_no;
{
	uint8_t bits[248], *sp, *dp;
	unsigned nb, byte, mask;

	bits[0] = 1;
	bits[1] = 1;
	bits[2] = 0;
	bits[3] = 0;
	bcopy(input_bits, bits + 4, 244);
	sp = bits;
	dp = frame;
	for (nb = 0; nb < EFR_RTP_FRAME_LEN; nb++) {
		byte = 0;
		for (mask = 0x80; mask; mask >>= 1) {
			if (*sp > 1) {
				fprintf(stderr,
					"error in %s frame #%u: data bit > 1\n",
					filename_for_errs, frame_no);
				exit(1);
			}
			if (*sp)
				byte |= mask;
			sp++;
		}
		*dp++ = byte;
	}
}

static void
write_pcm_le(outf, pcm)
	FILE *outf;
	int16_t *pcm;
{
	uint8_t bytes[320], *dp;
	int16_t samp;
	unsigned n;

	dp = bytes;
	for (n = 0; n < 160; n++) {
		samp = pcm[n];
		*dp++ = samp & 0xFF;
		*dp++ = (samp >> 8) & 0xFF;
	}
	fwrite(bytes, 2, 160, outf);
}

main(argc, argv)
	char **argv;
{
	FILE *inf, *outf;
	struct EFR_decoder_state *state;
	unsigned frame_no;
	uint8_t input_bits[ETSI_DEC_NWORDS], frame[EFR_RTP_FRAME_LEN];
	int16_t pcm[160];
	int rc;

	if (argc != 3) {
		fprintf(stderr, "usage: %s input.dec output.out\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);
	}
	state = EFR_decoder_create();
	if (!state) {
		perror("EFR_decoder_create()");
		exit(1);
	}
	for (frame_no = 0; ; frame_no++) {
		rc = read_input(inf, input_bits, argv[1]);
		if (!rc)
			break;
		if (input_bits[0] > 1) {
			fprintf(stderr, "error in %s frame #%u: BFI > 1\n",
				argv[1], frame_no);
			exit(1);
		}
		bits2frame(input_bits + 1, frame, argv[1], frame_no);
		if (input_bits[245] > 2) {
			fprintf(stderr, "error in %s frame #%u: SID > 2\n",
				argv[1], frame_no);
			exit(1);
		}
		if (input_bits[246] > 1) {
			fprintf(stderr, "error in %s frame #%u: TAF > 1\n",
				argv[1], frame_no);
			exit(1);
		}
		rc = EFR_sid_classify(frame);
		if (input_bits[245] != rc) {
			fprintf(stderr,
"warning: frame #%u has mismatching SID (file says %u, analysis yields %d)\n",
				frame_no, input_bits[245], rc);
		}
		EFR_decode_frame(state, frame, input_bits[0], input_bits[246],
				 pcm);
		write_pcm_le(outf, pcm);
	}
	fclose(outf);
	exit(0);
}