Mercurial > hg > audiostuff
view intercom/g726/vbr-g726.c @ 6:22a74b01a099 default tip
implement more meaningful test program
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 16:14:50 +0200 |
parents | 13be24d74cd2 |
children |
line wrap: on
line source
/* 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() ............................. */