changeset 216:9d59df9b0e4e

amrconv: new program amr-ietf2cod
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 21 Apr 2023 21:28:02 +0000
parents 4c4649a5fec3
children 1a7d659a952f
files .hgignore amrconv/Makefile amrconv/ietf2cod.c
diffstat 3 files changed, 127 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Fri Apr 21 06:30:29 2023 +0000
+++ b/.hgignore	Fri Apr 21 21:28:02 2023 +0000
@@ -5,6 +5,7 @@
 ^amrconv/amr-cod-parse$
 ^amrconv/amr-cod2ietf$
 ^amrconv/amr-ietf-parse$
+^amrconv/amr-ietf2cod$
 ^amrconv/gsm-amr2efr$
 ^amrconv/gsm-efr2amr$
 
--- a/amrconv/Makefile	Fri Apr 21 06:30:29 2023 +0000
+++ b/amrconv/Makefile	Fri Apr 21 21:28:02 2023 +0000
@@ -1,6 +1,7 @@
 CC=	gcc
 CFLAGS=	-O2
-PROGS=	amr-cod-parse amr-cod2ietf amr-ietf-parse gsm-amr2efr gsm-efr2amr
+PROGS=	amr-cod-parse amr-cod2ietf amr-ietf-parse amr-ietf2cod gsm-amr2efr \
+	gsm-efr2amr
 LIBTEST=../libtest/libtest.a
 INSTBIN=/opt/freecalypso/bin
 
@@ -13,6 +14,8 @@
 
 COD2IETF_OBJS=	amr122bits.o amr_bits.o amr_common_tbl.o bitmanip.o cod-read.o \
 		cod2ietf.o ietf_common.o if1_pack.o
+IETF2COD_OBJS=	amr122bits.o amr_bits.o amr_common_tbl.o bitmanip.o ietf2cod.o \
+		ietf_common.o if1_unpack.o
 
 all:	${PROGS}
 
@@ -25,6 +28,9 @@
 amr-ietf-parse:	${IETF_PARSE_OBJS}
 	${CC} ${CFLAGS} -o $@ ${IETF_PARSE_OBJS}
 
+amr-ietf2cod:	${IETF2COD_OBJS}
+	${CC} ${CFLAGS} -o $@ ${IETF2COD_OBJS}
+
 gsm-amr2efr:	${AMR2EFR_OBJS}
 	${CC} ${CFLAGS} -o $@ ${AMR2EFR_OBJS}
 
--- /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);
+}