FreeCalypso > hg > gsm-net-reveng
diff trau-ul-compile/trau-ul-compile.c @ 24:8e9bbb83bd16
trau-ul-compile program written
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 24 Jun 2024 01:01:17 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trau-ul-compile/trau-ul-compile.c Mon Jun 24 01:01:17 2024 +0000 @@ -0,0 +1,397 @@ +/* + * This program compile *.tsrc source format into *.tul binary format, + * see ../doc/TRAU-UL-testing article. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <tw_gsmfr.h> +#include <gsm_efr.h> + +#define MAX_FIELDS 18 + +static char *infname, *outfname; +static FILE *inf, *outf; + +static int lineno; +static char linebuf[256]; +static char *fields[MAX_FIELDS]; +static unsigned nfields; + +static int is_efr; +static int16_t speech_params[GSMFR_NUM_PARAMS]; +static int global_params_set, subframe_count; +static int bfi, bfi_set, sid, sid_set; +static uint8_t crc_inv, crc_inv_set; + +static int +get_line() +{ + char *cp; + + if (!fgets(linebuf, sizeof linebuf, inf)) + return 1; + lineno++; + if (!index(linebuf, '\n')) { + fprintf(stderr, "%s line %d: too long or missing newline\n", + infname, lineno); + exit(1); + } + nfields = 0; + for (cp = linebuf; ; ) { + while (isspace(*cp)) + cp++; + if (*cp == '\0' || *cp == '#') + break; + if (nfields >= MAX_FIELDS) { + fprintf(stderr, "%s line %d: too many fields\n", + infname, lineno); + exit(1); + } + fields[nfields++] = cp; + while (*cp && !isspace(*cp)) + cp++; + if (*cp) + *cp++ = '\0'; + } + return 0; +} + +static int +get_line_nonempty() +{ + int rc; + + for (;;) { + rc = get_line(); + if (rc) + return rc; + if (nfields) + return 0; + } +} + +static void +start_new_frame() +{ + if (nfields != 2 || strcmp(fields[1], "{")) { + fprintf(stderr, "%s line %d: invalid frame opening line\n", + infname, lineno); + exit(1); + } + global_params_set = 0; + subframe_count = 0; + bfi = 0; + bfi_set = 0; + sid_set = 0; + crc_inv = 0; + crc_inv_set = 0; +} + +static void +set_speech_params(start_param) + unsigned start_param; +{ + unsigned ni, no; + u_long val; + char *cp; + + no = start_param; + for (ni = 1; ni < nfields; ni++) { + if (!isdigit(fields[ni][0])) { +inv_number: fprintf(stderr, + "%s line %d: field \"%s\" is not a valid number\n", + infname, lineno, fields[ni]); + exit(1); + } + val = strtoul(fields[ni], &cp, 0); + if (*cp) + goto inv_number; + if (val > 0x1FF) { + fprintf(stderr, + "%s line %d: number \"%s\" is too large for a speech parameter\n", + infname, lineno, fields[ni]); + exit(1); + } + speech_params[no++] = val; + } +} + +static void +handle_larc() +{ + if (is_efr) { + fprintf(stderr, "%s line %d: LARc not valid for EFR\n", + infname, lineno); + exit(1); + } + if (nfields != 9) { + fprintf(stderr, + "%s line %d: wrong number of arguments for LARc\n", + infname, lineno); + exit(1); + } + if (global_params_set) { + fprintf(stderr, "%s line %d: LARc already set\n", + infname, lineno); + exit(1); + } + set_speech_params(0); + global_params_set = 1; +} + +static void +handle_lpc() +{ + if (!is_efr) { + fprintf(stderr, "%s line %d: LPC not valid for FR\n", + infname, lineno); + exit(1); + } + if (nfields != 6) { + fprintf(stderr, + "%s line %d: wrong number of arguments for LPC\n", + infname, lineno); + exit(1); + } + if (global_params_set) { + fprintf(stderr, "%s line %d: LPC already set\n", + infname, lineno); + exit(1); + } + set_speech_params(0); + global_params_set = 1; +} + +static void +handle_sf() +{ + if (is_efr) { + if (nfields != 14) { + fprintf(stderr, + "%s line %d: wrong number of arguments for EFR sf\n", + infname, lineno); + exit(1); + } + } else { + if (nfields != 18) { + fprintf(stderr, + "%s line %d: wrong number of arguments for FR sf\n", + infname, lineno); + exit(1); + } + } + if (subframe_count >= 4) { + fprintf(stderr, "%s line %d: too many subframes\n", + infname, lineno); + exit(1); + } + if (is_efr) + set_speech_params(5 + subframe_count * 13); + else + set_speech_params(8 + subframe_count * 17); + subframe_count++; +} + +static void +handle_bfi() +{ + if (nfields != 2) { + fprintf(stderr, "%s line %d: BFI takes one argument\n", + infname, lineno); + exit(1); + } + if (bfi_set) { + fprintf(stderr, "%s line %d: BFI already set\n", + infname, lineno); + exit(1); + } + if (fields[1][0] < '0' || fields[1][0] > '1' || fields[1][1]) { + fprintf(stderr, + "%s line %d: invalid BFI argument \"%s\" (must be 0 or 1)\n", + infname, lineno, fields[1]); + exit(1); + } + bfi = fields[1][0] - '0'; + bfi_set = 1; +} + +static void +handle_sid() +{ + if (nfields != 2) { + fprintf(stderr, "%s line %d: SID takes one argument\n", + infname, lineno); + exit(1); + } + if (sid_set) { + fprintf(stderr, "%s line %d: SID already set\n", + infname, lineno); + exit(1); + } + if (fields[1][0] < '0' || fields[1][0] > '2' || fields[1][1]) { + fprintf(stderr, + "%s line %d: invalid SID argument \"%s\" (must be 0, 1 or 2)\n", + infname, lineno, fields[1]); + exit(1); + } + sid = fields[1][0] - '0'; + sid_set = 1; +} + +static void +handle_crc_inv() +{ + unsigned nf; + + if (!is_efr) { + fprintf(stderr, "%s line %d: crc-inv not valid for FR\n", + infname, lineno); + exit(1); + } + if (nfields < 2) { + fprintf(stderr, + "%s line %d: crc-inv requires at least 1 argument\n", + infname, lineno); + exit(1); + } + if (crc_inv_set) { + fprintf(stderr, "%s line %d: crc-inv already set\n", + infname, lineno); + exit(1); + } + for (nf = 1; nf < nfields; nf++) { + if (!strcasecmp(fields[nf], "all")) + crc_inv = 0xF8; + else if (fields[nf][0] >= '0' && fields[nf][0] <= '4' && + !fields[nf][1]) + crc_inv |= 0x80 >> (fields[nf][0] - '0'); + else { + fprintf(stderr, + "%s line %d: \"%s\" is not a valid argument to crc-inv\n", + infname, lineno, fields[nf]); + exit(1); + } + } + crc_inv_set = 1; +} + +static void +process_frame_interior() +{ + int rc; + + for (;;) { + rc = get_line_nonempty(); + if (rc) { + fprintf(stderr, "bad input: EOF inside frame block\n"); + exit(1); + } + if (!strcasecmp(fields[0], "larc")) + handle_larc(); + else if (!strcasecmp(fields[0], "lpc")) + handle_lpc(); + else if (!strcasecmp(fields[0], "sf")) + handle_sf(); + else if (!strcasecmp(fields[0], "bfi")) + handle_bfi(); + else if (!strcasecmp(fields[0], "sid")) + handle_sid(); + else if (!strcasecmp(fields[0], "crc-inv")) + handle_crc_inv(); + else if (!strcmp(fields[0], "}")) { + if (nfields != 1) { + fprintf(stderr, + "%s line %d: stuff after } not permitted\n", + infname, lineno); + exit(1); + } + return; + } else { + fprintf(stderr, + "%s line %d: non-understood keyword \"%s\"\n", + infname, lineno, fields[0]); + exit(1); + } + } +} + +static void +finish_frame() +{ + uint8_t bin[34]; + + if (!global_params_set) { + fprintf(stderr, "%s line %d: LARc/LPC parameters not set\n", + infname, lineno); + exit(1); + } + if (subframe_count != 4) { + fprintf(stderr, "%s line %d: subframe parameters not set\n", + infname, lineno); + exit(1); + } + if (is_efr) { + EFR_params2frame(speech_params, bin); + if (!sid_set) + sid = EFR_sid_classify(bin); + bin[31] = crc_inv; + bin[32] = 0; + } else { + gsmfr_pack_from_array(speech_params, bin); + if (!sid_set) + sid = gsmfr_preproc_sid_classify(bin); + } + bin[33] = (bfi << 7) | sid; + fwrite(bin, 1, 34, outf); +} + +main(argc, argv) + char **argv; +{ + int rc; + + if (argc != 3) { + fprintf(stderr, "usage: %s input.tsrc output.tul\n", argv[0]); + exit(1); + } + infname = argv[1]; + outfname = argv[2]; + + inf = fopen(infname, "r"); + if (!inf) { + perror(infname); + exit(1); + } + outf = fopen(outfname, "w"); + if (!outf) { + perror(outfname); + exit(1); + } + + for (;;) { + rc = get_line_nonempty(); + if (rc) + break; + if (!strcasecmp(fields[0], "frame_fr")) { + is_efr = 0; + start_new_frame(); + } else if (!strcasecmp(fields[0], "frame_efr")) { + is_efr = 1; + start_new_frame(); + } else { + fprintf(stderr, + "%s line %d: expected frame opening line, got something else\n", + infname, lineno); + exit(1); + } + process_frame_interior(); + finish_frame(); + } + exit(0); +}