FreeCalypso > hg > freecalypso-tools
diff tchtools/fc-vm2gsmx.c @ 905:546bf873ccc8
tchtools: new program fc-vm2gsmx
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Wed, 28 Dec 2022 09:08:50 +0000 |
parents | tchtools/fc-vm2hex.c@5041bcb8140f |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tchtools/fc-vm2gsmx.c Wed Dec 28 09:08:50 2022 +0000 @@ -0,0 +1,103 @@ +/* + * This utility converts old-fashioned (non-AMR) TCS211 voice memo files + * read out of FFS into Themyscira Wireless gsmx (extended-libgsm) format, + * allowing further decoding into playable speech with gsmfr-decode. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> + +static char *infname; +static FILE *inf, *outf; +static u_long file_offset; + +static const u_char bfi_marker[2] = {0xBF, 0x00}; + +static unsigned +get_word() +{ + u_char b[2]; + int i, c; + + for (i = 0; i < 2; i++) { + c = getc(inf); + if (c < 0) { + fprintf(stderr, "error: premature EOF in %s\n", + infname); + exit(1); + } + b[i] = c; + file_offset++; + } + return((b[1] << 8) | b[0]); +} + +static void +read_dsp_bytes(bytes) + u_char *bytes; +{ + int i, dp; + unsigned word; + + dp = 0; + for (i = 0; i < 17; i++) { + word = get_word(); + bytes[dp++] = word >> 8; + bytes[dp++] = word; + } +} + +static void +convert_speech_sample() +{ + u_char tidsp_bytes[34], libgsm_bytes[33]; + + read_dsp_bytes(tidsp_bytes); + gsm0610_tidsp_to_libgsm(tidsp_bytes, libgsm_bytes); + fwrite(libgsm_bytes, 1, 33, outf); +} + +main(argc, argv) + char **argv; +{ + unsigned first_word; + + if (argc != 3) { + fprintf(stderr, "usage: %s infile outfile\n", argv[0]); + exit(1); + } + infname = argv[1]; + inf = fopen(infname, "r"); + if (!inf) { + perror(infname); + exit(1); + } + outf = fopen(argv[2], "w"); + if (!outf) { + perror(argv[2]); + exit(1); + } + for (;;) { + first_word = get_word(); + if (first_word == 0xFBFF) /* SC_VM_END_MASK */ + break; + if ((first_word & 0xB7FF) == 0x8400) { + /* skip dummy header words 1 and 2 */ + get_word(); + get_word(); + /* process the actual speech or SID frame */ + convert_speech_sample(); + } else if (first_word == 0x0400) { + /* it's a skipped frame, aka BFI */ + fwrite(bfi_marker, 1, 2, outf); + } else { + fprintf(stderr, + "error in %s at offset 0x%lx: invalid frame header word 0x%04X\n", + infname, file_offset, first_word); + exit(1); + } + } + fclose(outf); + exit(0); +}