diff amrconv/ietf2cod.c @ 216:9d59df9b0e4e

amrconv: new program amr-ietf2cod
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 21 Apr 2023 21:28:02 +0000
parents amrconv/cod2ietf.c@4c4649a5fec3
children 1a7d659a952f
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/amrconv/ietf2cod.c	Fri Apr 21 21:28:02 2023 +0000
@@ -0,0 +1,119 @@
+/*
+ * 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++;
+	while (n < MAX_SERIAL_SIZE)
+		*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);
+}