Mercurial > hg > audiostuff
diff intercom/g726/vbr-g726.c @ 2:13be24d74cd2
import intercom-0.4.1
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 09:57:52 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/intercom/g726/vbr-g726.c Fri Jun 25 09:57:52 2010 +0200 @@ -0,0 +1,602 @@ +/* 21.Mar.2000 V1.3 + ============================================================================ + + VBR-G726.C + ~~~~~~~~~~ + + Description: + ~~~~~~~~~~~~ + + Demonstration program for UGST/ITU-T G.726 module using the variable + bit rate feature. This version accepts either linear or G.711 A/u-law + input. Since this implementation of the G.726 requires G.711 compressed + samples, linear samples are converted to G.711 format before being + processed. Therefore, the same ammount of quantization distortion should + be expect either way. + + The modules called have been originally written in Fortran, and were + translated into C by the converter f2c, version of October 15, 1990 + at 19:58:17. + + Input data is supposed to be aligned at word boundaries, i.e., + organized in 16-bit words, following the operating system normal + organization (low-byte first for VMS and DOS; high byte first for most + Unix systems). Linear samples are supposed to be 16-bit right-adjusted. + G711 compressed data is supposed to be in the 8 LEAST + significant bits of the word and the ADPCM data is in the LEAST 5 + bits. Both are without sign extension. + + Output data will be generated in the same format as decribed above for + the input data. + + Usage: + ~~~~~~ + $ VBR-G726 [-options] InpFile OutFile + [FrameSize [1stBlock [NoOfBlocks [Reset]]]] + where: + InpFile is the name of the file to be processed; + OutFile is the name with the processed data; + FrameSize is the frame size, in number of samples; the bitrate + will only change in the boundaries of a frame + [default: 16 samples] + 1stBlock is the number of the first block of the input file + to be processed [default: 1st block] + NoOfBlocks is the number of blocks to be processed, starting on + block "1stBlock" [default: all blocks] + + Options: + -law # the letters A or a for G.711 A-law, letter u for + G.711 u-law, or letter l for linear. If linear is + chosen, A-law is used to compress/expand samples to/from + the G.726 routines. Default is A-law. + -rate # is the bit-rate (in kbit/s): 40, 32, 24 or 16 (in kbit/s); + or a combination of them using dashes (e.g. 32-24 or + 16-24-32). Default is 32 kbit/s. + -frame # Number of samples per frame for switching bit rates. + Default is 16 samples (or 2ms) + -enc run only the G.726 encoder on the samples + [default: run encoder and decoder] + -dec run only the G.726 decoder on the samples + [default: run encoder and decoder] + -noreset don't apply reset to the encoder/decoder + -?/-help print help message + + Example: + $ vbr-G726 -law u -enc -rate 32 voice.ref voice.adp 256 3 45 + + The command above takes the samples in file "voice.ref", already + in mu law format, processes the data through the G726 encoder + only at a rate of 32 bkit/s, saving them into the file + "voice.rel". The processing starts at block 3 for 45 blocks, + each block being 256 samples wide. + + Variables: + ~~~~~~~~~~ + law law to use (either A or u) + conv desired processing + rate desired rate + inpfil input file name; + outfil output file name; + N block size; + N1 first block to process; + N2 no. of blocks to process; + + Exit values: + ~~~~~~~~~~~~ + 0 success (all but VMS); + 1 success (only in VMS); + 2 error opening input file; + 3 error creating output file; + 4 error moving pointer to desired start of conversion; + 5 error reading input file; + 6 error writing to file; + 7 invalid law + 8 invalid conversion + 9 invalid rate + + Original author: + ~~~~~~~~~~~~~~~~ + Simao Ferraz de Campos Neto + Comsat Laboratories Tel: +1-301-428-4516 + 22300 Comsat Drive Fax: +1-301-428-9287 + Clarksburg MD 20871 - USA E-mail: simao@ctd.comsat.com + + History: + ~~~~~~~~ + 10/Mar/1995 v1.0 Created based on vbr-g726.c + 22/Feb/1996 v1.1 Removed compilation warnings, included headers as + suggested by Kirchherr (FI/DBP Telekom) to run under + OpenVMS/AXP <simao@ctd.comsat.com> + 22/Jul/1997 v1.2 Changed static allocation for data arrays to allow longer + frame sizes. Fix based on modifications by R. Kirchherr + <kirchherr@tzd.telekom.de> + 21.Mar.2000 v1.3 Corrected bug when the bitrate is not specified by + the user. Corrected bug that made incorrect + calculation on total number of blocks to process + when the block size is not a multiple of the file + size. <simao.campos@labs.comsat.com> + ============================================================================ +*/ + +/* ..... General definitions for UGST demo programs ..... */ +#include "ugstdemo.h" + +/* ..... General include ..... */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <ctype.h> + +#if defined(VMS) +#include <unixio.h> +#include <stat.h> +#else /* Unix/DOS */ +#include <sys/stat.h> +#endif + +/* ..... G.726 module as include functions ..... */ +#include "g726.h" +#include "g711.h" + +/* + ------------------------------------------------------------------------- + void parse_rate(char *str, short *rate); + ~~~~~~~~~~~~~~~ + Parses string str with a list of bitrates for the operation of the G726 + algorithm and return a list of them in rate, and the number of rates read. + + Parameters: + ~~~~~~~~~~~ + str ..... string pointing to a list of dash-separated bitrates to be used. + Valid examples are: 16 (single rate), 32-24 (duo-rate), etc. + rate .... string of short numbers with each of the specified rates. + + Return: + ~~~~~~~ + Returns the number of bitrates for the ADPCM operation, 0 if str is + empty or improper, and -1 if there are too many rates requested. + + History: + ~~~~~~~~ + 10.Mar.95 v1.0 Created <simao@ctd.comsat.com> + ------------------------------------------------------------------------- +*/ +int parse_rate(str, rate) +char *str; +short **rate; +{ + char *s = str; + int count = 1, i; + + if (str == NULL) + return 0; + + while ((s = strchr(s, '-')) != NULL) { + s++; + count++; + } + + /* Allocates memory for the necessary number of rates */ + *rate = (short *) calloc(sizeof(short), count); + if (*rate == NULL) + return (-1); + + /* Save rates in the array */ + for (s = strtok(str, "-"), i = 0; i < count; i++) { + /* Convert to short & save */ + (*rate)[i] = atoi(s); + + /* Classification of rate - return 0 if invalid rate was specified */ + if ((*rate)[i] > 5) { + if ((*rate)[i] == 40) + (*rate)[i] = 5; + else if ((*rate)[i] == 32) + (*rate)[i] = 4; + else if ((*rate)[i] == 24) + (*rate)[i] = 3; + else if ((*rate)[i] == 16) + (*rate)[i] = 2; + else + return (0); + } + + /* Update s to the next valid rate number */ + s = strtok(NULL, "-"); + } + + /* Return the number of rates */ + return (count); +} + +/* .................... End of parse_rate() ........................... */ + + +/* + ------------------------------------------------------------------------- + void display_usage(void); + ~~~~~~~~~~~~~~~~~~ + Display proper usage for the demo program. Generated automatically from + program documentation. + + History: + ~~~~~~~~ + 10.Mar.95 v1.0 Created <simao>. + ------------------------------------------------------------------------- +*/ +#define P(x) printf x +void display_usage() +{ + P(("Version 1.3 of 21/Mar/2000 \n\n")); + + P((" VBR-G726.C \n")); + P((" Demonstration program for UGST/ITU-T G.726 module using the variable\n")); + P((" bit rate feature. This version accepts either linear or G.711 A/u-law\n")); + P((" input. Since this implementation of the G.726 requires G.711 compressed\n")); + P((" samples, linear samples are converted to G.711 format before being\n")); + P((" processed. Therefore, the same ammount of quantization distortion should\n")); + P((" be expect either way.\n")); + P((" Input data is supposed to be aligned at word boundaries, i.e.,\n")); + P((" organized in 16-bit words, following the operating system normal\n")); + P((" organization (low-byte first for VMS and DOS; high byte first for most\n")); + P((" Unix systems). Linear samples are supposed to be 16-bit right-adjusted. \n")); + P((" G711 compressed data is supposed to be in the 8 LEAST\n")); + P((" significant bits of the word and the ADPCM data is in the LEAST 5\n")); + P((" bits. Both are without sign extension.\n")); + P((" \n")); + P((" Output data will be generated in the same format as decribed above for\n")); + P((" the input data.\n")); + P((" \n")); + P((" Usage:\n")); + P((" VBR-G726 [-options] InpFile OutFile \n")); + P((" [FrameSize [1stBlock [NoOfBlocks [Reset]]]]\n")); + P((" where:\n")); + P((" InpFile is the name of the file to be processed;\n")); + P((" OutFile is the name with the processed data;\n")); + P((" FrameSize is the frame size, in number of samples; the bitrate \n")); + P((" will only change in the boundaries of a frame \n")); + P((" [default: 16 samples]\n")); + P((" 1stBlock is the number of the first block of the input file\n")); + P((" to be processed [default: 1st block]\n")); + P((" NoOfBlocks is the number of blocks to be processed, starting on\n")); + P((" block \"1stBlock\" [default: all blocks]\n")); + P(("\n")); + P((" Options:\n")); + P((" -law # the letters A or a for G.711 A-law, letter u for \n")); + P((" G.711 u-law, or letter l for linear. If linear is\n")); + P((" chosen, A-law is used to compress/expand samples to/from\n")); + P((" the G.726 routines. Default is A-law.\n")); + P((" -rate # is the bit-rate (in kbit/s): 40, 32, 24 or 16 (in kbit/s); \n")); + P((" or a combination of them using dashes (e.g. 32-24 or\n")); + P((" 16-24-32). Default is 32 kbit/s.\n")); + P((" -frame # Number of samples per frame for switching bit rates.\n")); + P((" Default is 16 samples (or 2ms) \n")); + P((" -enc run only the G.726 encoder on the samples \n")); + P((" [default: run encoder and decoder]\n")); + P((" -dec run only the G.726 decoder on the samples \n")); + P((" [default: run encoder and decoder]\n")); + P((" -noreset don't apply reset to the encoder/decoder\n")); + P((" -?/-help print help message\n")); + P(("\n")); + + /* Quit program */ + exit(-128); +} + +#undef P +/* .................... End of display_usage() ........................... */ + + +void G726_initEncode(G726_state *encoder_state) +{ + memset(encoder_state, 0, sizeof(G726_state)); +} + +void G726_initDecode(G726_state *decoder_state) +{ + memset(decoder_state, 0, sizeof(G726_state)); +} + +void g726pack(Byte *packed, short *in, int cnt) +{ + int i; + for (i = 0; i <= cnt; i += 2, ++packed, ++in) { + *packed = (*in & 0xF); + ++in; + *packed += (*in & 0xF) * 16; + } +} + +void g726unpack(short *out, Byte *packed, int cnt) +{ + int i; + for (i = 0; i <= cnt; i += 2, ++packed, ++out) { + *out = (*packed & 0xF); + ++out; + *out = (*packed & 0xF0) / 16; + } +} + +/* + ************************************************************************** + *** *** + *** Demo-Program for testing the correct implementation *** + *** and to show how to use the programs *** + *** *** + ************************************************************************** +*/ +int main(argc, argv) +int argc; +char *argv[]; +{ + G726_state encoder_state, decoder_state; + long N = 16, N1 = 1, N2 = 0, cur_blk, smpno; + short *tmp_buf, *inp_buf, *out_buf, reset = 1; + Byte tmpb_buf[N], outb_buf[N]; + short inp_type, out_type, *rate = 0; + char encode = 1, decode = 1, law[4] = "A", def_rate[] = "32"; + int rateno = 1, rate_idx; + + /* General-purpose, progress indication */ + static char quiet = 0, funny[9] = "|/-\\|/-\\"; + +/* File variables */ + char FileIn[80], FileOut[80]; + FILE *Fi, *Fo; + int inp, out; + long start_byte; +#ifdef VMS + char mrs[15]; +#endif + +/* + * ......... PARAMETERS FOR PROCESSING ......... + */ + + /* GETTING OPTIONS */ + + if (argc < 2) + display_usage(); + else { + while (argc > 1 && argv[1][0] == '-') + if (strcmp(argv[1], "-noreset") == 0) { + /* No reset */ + reset = 0; + + /* Update argc/argv to next valid option/argument */ + argv++; + argc--; + } else if (strcmp(argv[1], "-enc") == 0) { + /* Encoder-only operation */ + encode = 1; + decode = 0; + + /* Move argv over the option to the next argument */ + argv++; + argc--; + } else if (strcmp(argv[1], "-dec") == 0) { + /*Decoder-only operation */ + encode = 0; + decode = 1; + + /* Move argv over the option to the next argument */ + argv++; + argc--; + } else if (strcmp(argv[1], "-law") == 0) { + /* Define law for operation: A, u, or linear */ + switch (toupper(argv[2][0])) { + case 'A': + law[0] = '1'; + break; + case 'U': + law[0] = '0'; + break; + case 'L': + law[0] = '2'; + break; + default: + HARAKIRI(" Invalid law (A or u)! Aborted...\n", 7); + } + + /* Move argv over the option to the next argument */ + argv += 2; + argc -= 2; + } else if (strcmp(argv[1], "-frame") == 0) { + /* Define Frame size for rate change during operation */ + N = atoi(argv[2]); + + /* Move argv over the option to the next argument */ + argv += 2; + argc -= 2; + } else if (strcmp(argv[1], "-rate") == 0) { + /*Define rate(s) for operation */ + rateno = parse_rate(argv[2], &rate); + if (rateno == 0) { + fprintf(stderr, "Invalid bitrate list: %s\n", argv[2]); + exit(9); + } + /* Move argv over the option to the next argument */ + argv += 2; + argc -= 2; + } else if (strcmp(argv[1], "-q") == 0) { + /* Don't print progress indicator */ + quiet = 1; + + /* Move argv over the option to the next argument */ + argv++; + argc--; + } else if (strcmp(argv[1], "-?") == 0 + || strcmp(argv[1], "-help") == 0) { + /* Print help */ + display_usage(); + } else { + fprintf(stderr, + "ERROR! Invalid option \"%s\" in command line\n\n", argv[1]); + display_usage(); + } + } + + /* Now get regular parameters */ + GET_PAR_S(1, "_Input File: .................. ", FileIn); + GET_PAR_S(2, "_Output File: ................. ", FileOut); + FIND_PAR_L(3, "_Block Size: .................. ", N, N); + FIND_PAR_L(4, "_Starting Block: .............. ", N1, N1); + FIND_PAR_L(5, "_No. of Blocks: ............... ", N2, N2); + + /* Uses default rate if none is given */ + if (rate == 0) + rateno = parse_rate(def_rate, &rate); + + /* Inform user of the compading law used: 0->u, 1->A, 2->linear */ + fprintf(stderr, "Using %s\n", + law[0] == '1' ? "A-law" : (law[0] == '0' ? "u-law" : "linear PCM")); + + /* Find starting byte in file */ + start_byte = sizeof(short) * (long) (--N1) * (long) N; + + /* Check if is to process the whole file */ + if (N2 == 0) { + struct stat st; + + /* ... find the input file size ... */ + stat(FileIn, &st); + N2 = ceil((st.st_size - start_byte) / (double) (N * sizeof(short))); + } + + /* Define correct data I/O types */ + if (encode && decode) { + inp_type = out_type = (law[0] == '2' ? IS_LIN : IS_LOG); + } else if (encode) { + inp_type = law[0] == '2' ? IS_LIN : IS_LOG; + out_type = IS_ADPCM; + } else { + inp_type = IS_ADPCM; + out_type = law[0] == '2' ? IS_LIN : IS_LOG; + } + + /* Force law to be used *by the ADPCM* to A-law, if input is linear */ + if (law[0] == '2') + law[0] = '1'; + +/* + * ...... MEMORY ALLOCATION ......... + */ + + if ((inp_buf = (short *) calloc(N, sizeof(short))) == NULL) + HARAKIRI("Error in memory allocation!\n", 1); + if ((out_buf = (short *) calloc(N, sizeof(short))) == NULL) + HARAKIRI("Error in memory allocation!\n", 1); + if ((tmp_buf = (short *) calloc(N, sizeof(short))) == NULL) + HARAKIRI("Error in memory allocation!\n", 1); + +/* + * ......... FILE PREPARATION ......... + */ + + /* Opening input file; abort if there's any problem */ + if ((Fi = fopen(FileIn, "rb")) == NULL) + KILL(FileIn, 2); + inp = fileno(Fi); + + /* Creates output file */ +#ifdef VMS + sprintf(mrs, "mrs=%d", 512); +#endif + if ((Fo = fopen(FileOut, WB)) == NULL) + KILL(FileOut, 3); + out = fileno(Fo); + + /* Move pointer to 1st block of interest */ + if (fseek(Fi, start_byte, 0) < 0l) + KILL(FileIn, 4); + +/* + * ......... PROCESSING ACCORDING TO ITU-T G.726 ......... + */ + /* Reset VBR counters */ + rate_idx = 0; + + for (cur_blk = 0; cur_blk < N2; cur_blk++) { + /* Set the proper rate index */ + rate_idx = cur_blk % rateno; + + /* Print progress flag */ + if (!quiet) +#ifdef DISPLAY_CURRENT_RATE + fprintf(stderr, "%d-", 8 * rate[rate_idx]); +#else + fprintf(stderr, "%c\r", funny[cur_blk % 8]); +#endif + + /* Read a block of samples */ + if ((smpno = fread(inp_buf, sizeof(short), N, Fi)) < 0) + KILL(FileIn, 5); + + /* Compress linear input samples */ + if (inp_type == IS_LIN) { + /* Compress using A-law */ + alaw_compress(smpno, inp_buf, tmpb_buf); + + /* copy temporary buffer over input buffer */ + // memcpy(inp_buf, tmp_buf, sizeof(short) * smpno); + } + + /* Check if reset is needed */ + reset = (reset == 1 && cur_blk == 0) ? 1 : 0; + + /* Carry out the desired operation */ + if (encode && !decode) + G726_encode(tmpb_buf, out_buf, smpno, law, + rate[rate_idx], reset, &encoder_state); + else if (decode && !encode) + G726_decode(inp_buf, outb_buf, smpno, law, + rate[rate_idx], reset, &decoder_state); + else if (encode && decode) { + Byte g726_buf[N/2]; + + G726_encode(tmpb_buf, tmp_buf, smpno, law, + rate[rate_idx], reset, &encoder_state); + // printf ("rate[rate_idx] = %d\n", rate[rate_idx]); + g726pack(g726_buf, tmp_buf, smpno); + + g726unpack(tmp_buf, g726_buf, smpno); + + G726_decode(tmp_buf, outb_buf, smpno, law, + rate[rate_idx], reset, &decoder_state); + } + + /* Expand linear input samples */ + if (out_type == IS_LIN) { + /* Compress using A-law */ + alaw_expand(smpno, outb_buf, tmp_buf); + + /* copy temporary buffer over input buffer */ + memcpy(out_buf, tmp_buf, sizeof(short) * smpno); + } + + /* Write ADPCM output word */ + if ((smpno = fwrite(out_buf, sizeof(short), smpno, Fo)) < 0) + KILL(FileOut, 6); + } + +/* + * ......... FINALIZATIONS ......... + */ + + /* Free allocated memory */ + free(tmp_buf); + free(out_buf); + free(inp_buf); + free(rate); + + /* Close input and output files */ + fclose(Fi); + fclose(Fo); + + /* Exit with success for non-vms systems */ +#ifndef VMS + return (0); +#endif +} + +/* ............................. end of main() ............................. */