view amrconv/ietf2cod.c @ 478:936a08cc73ce

doc/AMR-library-API: describe the decoder
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 19 May 2024 21:32:31 +0000
parents 1a7d659a952f
children
line wrap: on
line source

/*
 * This program converts an AMR-encoded speech recording from the common
 * IETF RFC 4867 .amr format into the 3GPP test sequence .cod format.
 */

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "amr_defs.h"

extern unsigned amr_bit_lengths[9];
extern const char amr_file_hdr[IETF_HDR_LEN];
extern const uint8_t extra_bytes_per_ft[9];

static void
bits2words(ser_bits, cod_words, nbits)
	uint8_t *ser_bits;
	uint16_t *cod_words;
	unsigned nbits;
{
	uint8_t *sp = ser_bits;
	uint16_t *dp = cod_words;
	unsigned n;

	for (n = 0; n < nbits; n++)
		*dp++ = *sp++;
	for (; n < MAX_SERIAL_SIZE; n++)
		*dp++ = 0;
}

main(argc, argv)
	char **argv;
{
	char *infname, *outfname;
	FILE *inf, *outf;
	uint8_t frm_in[MAX_IF1_BYTES];
	unsigned frame_no, mode, qbit, sti, sid_mode;
	uint8_t ser_bits[MAX_SERIAL_SIZE];
	uint16_t cod_words[COD_FORMAT_NWORDS];
	int rc;

	if (argc != 3) {
		fprintf(stderr, "usage: %s input.amr output.cod\n", argv[0]);
		exit(1);
	}
	infname = argv[1];
	outfname = argv[2];
	inf = fopen(infname, "r");
	if (!inf) {
		perror(infname);
		exit(1);
	}
	if (fread(frm_in, 1, IETF_HDR_LEN, inf) != IETF_HDR_LEN ||
	    bcmp(frm_in, amr_file_hdr, IETF_HDR_LEN)) {
		fprintf(stderr, "error: %s is not in IETF AMR format\n",
			infname);
		exit(1);
	}
	outf = fopen(outfname, "w");
	if (!outf) {
		perror(outfname);
		exit(1);
	}
	/* padding words which will never be filled */
	bzero(cod_words + MAX_SERIAL_SIZE + 2, sizeof(uint16_t) * 4);
	for (frame_no = 0; ; frame_no++) {
		rc = getc(inf);
		if (rc < 0)
			break;
		mode = (rc & 0x78) >> 3;
		qbit = (rc & 4) >> 2;
		if (mode == MODE_NO_DATA) {
			cod_words[0] = TX_NO_DATA;
			bzero(cod_words+1, sizeof(uint16_t) * MAX_SERIAL_SIZE);
			cod_words[245] = 0xFFFF;
			goto output;
		}
		if (mode > MRDTX) {
			fprintf(stderr, "error in frame #%u: invalid FT=%u\n",
				frame_no, mode);
			exit(1);
		}
		rc = fread(frm_in, 1, extra_bytes_per_ft[mode], inf);
		if (rc != extra_bytes_per_ft[mode]) {
			fprintf(stderr,
				"error: short read from %s on frame #%u\n",
				infname, frame_no);
			exit(1);
		}
		amr_if1_unpack(frm_in, ser_bits, mode);
		if (mode == MRDTX) {
			sti = (frm_in[4] & 0x10) >> 4;
			sid_mode = 0;
			if (frm_in[4] & 0x08)
				sid_mode |= 1;
			if (frm_in[4] & 0x04)
				sid_mode |= 2;
			if (frm_in[4] & 0x02)
				sid_mode |= 4;
		}
		bits2words(ser_bits, cod_words + 1, amr_bit_lengths[mode]);
		if (mode == MRDTX) {
			if (qbit)
				cod_words[0] = sti ? TX_SID_UPDATE
						   : TX_SID_FIRST;
			else
				cod_words[0] = TX_SID_BAD;
			cod_words[245] = sid_mode;
		} else {
			cod_words[0] = qbit ? TX_SPEECH_GOOD : TX_SPEECH_BAD;
			cod_words[245] = mode;
		}
output:		fwrite(cod_words, 2, COD_FORMAT_NWORDS, outf);
	}
	fclose(outf);
	exit(0);
}