changeset 589:e414d138c607

amrconv: new program amr-ietf2hexoa
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 06 Nov 2025 21:18:59 +0000
parents 4d6ccca0c687
children 6b2900fe20f4
files .hgignore amrconv/Makefile amrconv/ietf2hex.c
diffstat 3 files changed, 82 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Nov 06 20:12:15 2025 +0000
+++ b/.hgignore	Thu Nov 06 21:18:59 2025 +0000
@@ -8,6 +8,7 @@
 ^amrconv/amr-hexoa2ietf$
 ^amrconv/amr-ietf-parse$
 ^amrconv/amr-ietf2cod$
+^amrconv/amr-ietf2hexoa$
 ^amrconv/gsm-amr2efr$
 ^amrconv/gsm-efr2amr$
 
--- a/amrconv/Makefile	Thu Nov 06 20:12:15 2025 +0000
+++ b/amrconv/Makefile	Thu Nov 06 21:18:59 2025 +0000
@@ -1,5 +1,5 @@
 PROGS=	amr-cod-parse amr-cod2ietf amr-hexoa2ietf amr-ietf-parse amr-ietf2cod \
-	gsm-amr2efr gsm-efr2amr
+	amr-ietf2hexoa gsm-amr2efr gsm-efr2amr
 LIBTEST=../libtest/libtest.a
 
 include ../config.defs
@@ -17,6 +17,7 @@
 		ietf_common.o if1_unpack.o
 
 HEX2IETF_OBJS=	hex2ietf.o ietf_common.o
+IETF2HEX_OBJS=	ietf2hex.o ietf_common.o
 
 all:	${PROGS}
 
@@ -35,6 +36,9 @@
 amr-ietf2cod:	${IETF2COD_OBJS}
 	${CC} ${CFLAGS} -o $@ ${IETF2COD_OBJS}
 
+amr-ietf2hexoa:	${IETF2HEX_OBJS} ${LIBTEST}
+	${CC} ${CFLAGS} -o $@ ${IETF2HEX_OBJS} ${LIBTEST}
+
 gsm-amr2efr:	${AMR2EFR_OBJS}
 	${CC} ${CFLAGS} -o $@ ${AMR2EFR_OBJS}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/amrconv/ietf2hex.c	Thu Nov 06 21:18:59 2025 +0000
@@ -0,0 +1,76 @@
+/*
+ * This program reads an AMR speech recording in RFC 4867 binary storage format,
+ * converts each frame to an octet-aligned RTP payload (adds CMR octet), and
+ * writes out these payloads as a TW-TS-005 Annex C hex file.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "../libtest/tw5writer.h"
+#include "amr_defs.h"
+
+extern const char amr_file_hdr[IETF_HDR_LEN];
+extern const uint8_t extra_bytes_per_ft[9];
+
+main(argc, argv)
+	char **argv;
+{
+	FILE *inf, *outf;
+	uint8_t frame[MAX_IF1_BYTES + 2];
+	unsigned frame_no, ft, frame_len;
+	int rc;
+
+	if (argc != 3) {
+		fprintf(stderr, "usage: %s input.amr output.hex\n", argv[0]);
+		exit(1);
+	}
+	inf = fopen(argv[1], "r");
+	if (!inf) {
+		perror(argv[1]);
+		exit(1);
+	}
+	if (fread(frame, 1, IETF_HDR_LEN, inf) != IETF_HDR_LEN ||
+	    bcmp(frame, amr_file_hdr, IETF_HDR_LEN)) {
+		fprintf(stderr, "error: %s is not in IETF AMR format\n",
+			argv[1]);
+		exit(1);
+	}
+	if (strcmp(argv[2], "-")) {
+		outf = fopen(argv[2], "w");
+		if (!outf) {
+			perror(argv[2]);
+			exit(1);
+		}
+	} else
+		outf = stdout;
+	frame[0] = 0xF0;
+	for (frame_no = 0; ; frame_no++) {
+		rc = getc(inf);
+		if (rc < 0)
+			break;
+		frame[1] = rc & 0x7C;
+		ft = frame[1] >> 3;
+		frame_len = 2;
+		if (ft != MODE_NO_DATA) {
+			if (ft > MRDTX) {
+				fprintf(stderr,
+					"error in frame #%u: invalid FT=%u\n",
+					frame_no, ft);
+				exit(1);
+			}
+			rc = fread(frame + 2, 1, extra_bytes_per_ft[ft], inf);
+			if (rc != extra_bytes_per_ft[ft]) {
+				fprintf(stderr,
+				"error: short read from %s on frame #%u\n",
+					argv[1], frame_no);
+				exit(1);
+			}
+			frame_len += extra_bytes_per_ft[ft];
+		}
+		emit_hex_frame(outf, frame, frame_len);
+	}
+	exit(0);
+}