📄 shorten.c
字号:
/******************************************************************************* ** Copyright (C) 1992-1996 Tony Robinson and SoftSound Limited ** ** See the file LICENSE for conditions on distribution and usage ** *******************************************************************************/# include <math.h># include <stdio.h># include <stdlib.h># include <string.h>#ifdef MSDOS# include <io.h># include <fcntl.h>#else# include <unistd.h>#endif# include <setjmp.h># include "shorten.h"#ifndef MSDOSchar *readmode = "r";char *writemode = "w";# define FILESUFFIX ".shn"#elsechar *readmode = "rb";char *writemode = "wb";#endifchar *argv0 = "shorten";int getc_exit_val;char *filenameo = NULL;FILE *fileo = NULL;# define V2LPCQOFFSET (1 << LPCQUANT);# define UINT_PUT(val, nbit, file) \ if(version == 0) uvar_put((unsigned long) val, nbit, file); \ else ulong_put((unsigned long) val, file)# define UINT_GET(nbit, file) \ ((version == 0) ? uvar_get(nbit, file) : ulong_get(file))# define VAR_PUT(val, nbit, file) \ if(version == 0) var_put((unsigned long) val, nbit - 1, file); \ else var_put((unsigned long) val, nbit, file)void init_offset(offset, nchan, nblock, ftype) long **offset; int nchan, nblock, ftype; { long mean = 0; int chan, i; /* initialise offset */ switch(ftype) { case TYPE_AU1: case TYPE_S8: case TYPE_S16HL: case TYPE_S16LH: case TYPE_ULAW: case TYPE_AU2: case TYPE_AU3: case TYPE_ALAW: mean = 0; break; case TYPE_U8: mean = 0x80; break; case TYPE_U16HL: case TYPE_U16LH: mean = 0x8000; break; default: update_exit(1, "unknown file type: %d\n", ftype); } for(chan = 0; chan < nchan; chan++) for(i = 0; i < nblock; i++) offset[chan][i] = mean;}float Satof(string) char *string; { int i, rval = 1; /* this should have tighter checking */ for(i = 0; i < (int) strlen(string) && rval == 1; i++) if(string[i] != '.' && (string[i] < '0' || string[i] > '9')) usage_exit(1, "non-parseable float: %s\n", string); return((float) atof(string));}float* parseList(maxresnstr, nchan) char *maxresnstr; int nchan; { int nval; char *str, *floatstr; float *floatval; /* copy maxresnstr to temporary space, str */ str = malloc(strlen(maxresnstr) + 1); strcpy(str, maxresnstr); /* grab space for the floating point parses */ floatval = pmalloc((ulong) (nchan * sizeof(*floatval))); /* loop for all floats in the arguement */ floatstr = strtok(str, ","); floatval[0] = Satof(floatstr); for(nval = 1; (floatstr = strtok(NULL, ",")) != NULL && nval < nchan;nval++) floatval[nval] = Satof(floatstr); for(; nval < nchan; nval++) floatval[nval] = floatval[nval - 1]; free(str); return(floatval);}int shorten(stdi, stdo, argc, argv) FILE *stdi, *stdo; int argc; char **argv; { long **buffer, *buffer1, **offset; long lpcqoffset = 0; int version = FORMAT_VERSION, extract = 0, lastbitshift = 0, bitshift = 0; int hiloint = 1, hilo = !(*((char*) &hiloint)); int ftype = hilo ? TYPE_S16HL : TYPE_S16LH; char *magic = MAGIC, *filenamei = NULL; char *tmpfilename = NULL; char *maxresnstr = DEFAULT_MAXRESNSTR; FILE *filei; int blocksize = DEFAULT_BLOCK_SIZE, nchan = DEFAULT_NCHAN; int i, chan, nwrap, nskip = DEFAULT_NSKIP, ndiscard = DEFAULT_NDISCARD; int *qlpc = NULL, maxnlpc = DEFAULT_MAXNLPC, nmean = UNDEFINED_UINT; int quanterror = DEFAULT_QUANTERROR, minsnr = DEFAULT_MINSNR, nfilename; int ulawZeroMerge = 0; char *minusstr = "-"; extern char *hs_optarg; extern int hs_optind; /* this block just processes the command line arguments */ { int c; hs_resetopt(); while((c = hs_getopt(argc, argv, "a:b:c:d:hlm:n:p:q:r:t:uv:x")) != -1) switch(c) { case 'a': if((nskip = atoi(hs_optarg)) < 0) usage_exit(1, "number of bytes to copy must be positive\n"); break; case 'b': if((blocksize = atoi(hs_optarg)) <= 0) usage_exit(1, "block size must be greater than zero\n"); break; case 'c': if((nchan = atoi(hs_optarg)) <= 0) usage_exit(1, "number of channels must be greater than zero\n"); break; case 'd': if((ndiscard = atoi(hs_optarg)) < 0) usage_exit(1, "number of bytes to discard must be positive\n"); break; case 'h':#ifndef _WINDOWS printf("%s: version %d.%s: (c) 1992-1996 Tony Robinson and SoftSound Ltd\n", argv0, FORMAT_VERSION, BUGFIX_RELEASE);#ifdef OLDHELP printf("usage: %s [-hx] [-a #byte] [-b #sample] [-c #channel] [-d #discard]\n\t[-m #block] [-p #delay] [-q #bit] [-r #bit] [-t filetype]\n\t[input file] [output file]\n", argv0);#endif printf("%s: usage: %s {options} [input file] [output file]\n", argv0, argv0); printf(" -a %-5dbytes to copy verbatim to align file\n", DEFAULT_NSKIP); printf(" -b %-5dblock size\n", DEFAULT_BLOCK_SIZE); printf(" -c %-5dnumber of channels\n", DEFAULT_NCHAN); printf(" -d %-5dtbytes to discard before compression or decompression\n", DEFAULT_NDISCARD); printf(" -h help (this message)\n"); printf(" -l print the license giving the distribution and usage conditions\n"); printf(" -m %-5dnumber of past block for mean estimation\n", (FORMAT_VERSION < 2) ? DEFAULT_V0NMEAN : DEFAULT_V2NMEAN); printf(" -n %-5dminimum signal to noise ratio in dB (%d == lossless coding)\n", DEFAULT_MINSNR, DEFAULT_MINSNR); printf(" -p %-5dmaximum LPC predictor order (0 == fast polynomial predictor)\n", DEFAULT_MAXNLPC); printf(" -q %-5dacceptable quantisation error in bits\n", DEFAULT_QUANTERROR); printf(" -r %-5smaximum number of bits per sample (%s == lossless coding)\n", DEFAULT_MAXRESNSTR, DEFAULT_MAXRESNSTR); printf(" -t s16 filetype {ulaw,alaw,s8,u8,s16,u16,s16x,u16x,s16hl,u16hl,s16lh,u16lh}\n"); printf(" -u merge the two zero codes in ulaw files\n"); printf(" -v %-5dformat version number\n", FORMAT_VERSION); printf(" -x extract (all other options except -a and -d are ignored)\n"); basic_exit(0);#else /* _WINDOWS */ error_exit("%s: usage: %s {options} [input file] [output file]\n", argv0, argv0);#endif break; case 'l': license(); basic_exit(0); break; case 'm': if((nmean = atoi(hs_optarg)) < 0) usage_exit(1, "number of blocks for mean estimation must be positive\n"); break; case 'n': if((minsnr = atoi(hs_optarg)) < 0) usage_exit(1, "Useful signal to noise ratios are positive\n"); break; case 'p': maxnlpc = atoi(hs_optarg); if(maxnlpc < 0 || maxnlpc > MAX_LPC_ORDER) usage_exit(1, "linear prediction order must be in the range 0 ... %d\n", MAX_LPC_ORDER); break; case 'q': if((quanterror = atoi(hs_optarg)) < 0) usage_exit(1, "quantisation level must be positive\n"); break; case 'r': maxresnstr = hs_optarg; break; case 't': if (!strcmp(hs_optarg, "au")) ftype = TYPE_GENERIC_ULAW; else if(!strcmp(hs_optarg, "ulaw")) ftype = TYPE_GENERIC_ULAW; else if(!strcmp(hs_optarg, "alaw")) ftype = TYPE_GENERIC_ALAW; else if(!strcmp(hs_optarg, "s8")) ftype = TYPE_S8; else if(!strcmp(hs_optarg, "u8")) ftype = TYPE_U8; else if(!strcmp(hs_optarg, "s16")) ftype = hilo?TYPE_S16HL:TYPE_S16LH; else if(!strcmp(hs_optarg, "u16")) ftype = hilo?TYPE_U16HL:TYPE_U16LH; else if(!strcmp(hs_optarg, "s16x")) ftype = hilo?TYPE_S16LH:TYPE_S16HL; else if(!strcmp(hs_optarg, "u16x")) ftype = hilo?TYPE_U16LH:TYPE_U16HL; else if(!strcmp(hs_optarg, "s16hl"))ftype = TYPE_S16HL; else if(!strcmp(hs_optarg, "u16hl"))ftype = TYPE_U16HL; else if(!strcmp(hs_optarg, "s16lh"))ftype = TYPE_S16LH; else if(!strcmp(hs_optarg, "u16lh"))ftype = TYPE_U16LH; else usage_exit(1, "unknown file type: %s\n", hs_optarg); break; case 'u': ulawZeroMerge = 1; break; case 'v': version = atoi(hs_optarg); if(version < 0 || version > MAX_SUPPORTED_VERSION) usage_exit(1, "currently supported versions are in the range %d ... %d\n", MIN_SUPPORTED_VERSION, MAX_SUPPORTED_VERSION); break; case 'x': extract = 1; break; default:#ifdef _WINDOWS usage_exit(1, "apparently too many file names"); /* mrhmod */#else usage_exit(1, NULL);#endif break; } } if(nmean == UNDEFINED_UINT) nmean = (version < 2) ? DEFAULT_V0NMEAN : DEFAULT_V2NMEAN; /* a few sanity checks */ if(blocksize <= NWRAP) usage_exit(1, "blocksize must be greater than %d\n", NWRAP); if(maxnlpc >= blocksize) usage_exit(1, "the predictor order must be less than the block size\n"); if(ulawZeroMerge == 1 && ftype != TYPE_GENERIC_ULAW) usage_exit(1, "the -u flag is only applicable to ulaw coding\n"); { int linearLossy = (Satof(maxresnstr) != Satof(DEFAULT_MAXRESNSTR) || quanterror != DEFAULT_QUANTERROR); /* sort out which ulaw type we are going to use */ if(ftype == TYPE_GENERIC_ULAW) { if(linearLossy) ftype = TYPE_ULAW; else if(version < 2 || ulawZeroMerge == 1) ftype = TYPE_AU1; else ftype = TYPE_AU2; } /* sort out which alaw type we are going to use */ if(ftype == TYPE_GENERIC_ALAW) { if(linearLossy) ftype = TYPE_ALAW; else ftype = TYPE_AU3; } } /* mean compensation is not supported for TYPE_AU1 or TYPE_AU2 */ /* (the bit shift compensation can't cope with the lag vector) */ if(ftype == TYPE_AU1 || ftype == TYPE_AU2) nmean = 0; /* this chunk just sets up the input and output files */ nfilename = argc - hs_optind; switch(nfilename) { case 0: filenamei = minusstr; filenameo = minusstr; break; case 1: {#ifndef MSDOS int oldfilelen, suffixlen, maxlen; filenamei = argv[argc - 1]; oldfilelen = strlen(filenamei); suffixlen = strlen(FILESUFFIX); maxlen = oldfilelen + suffixlen; tmpfilename = pmalloc((ulong) (maxlen + 1)); strcpy(tmpfilename, filenamei); if(extract) { int newfilelen = oldfilelen - suffixlen; if(strcmp(filenamei + newfilelen, FILESUFFIX)) usage_exit(1,"file name does not end in %s: %s\n", FILESUFFIX, filenamei); tmpfilename[newfilelen] = '\0'; } else strcat(tmpfilename, FILESUFFIX); filenameo = tmpfilename;#else usage_exit(1, "must specify both input and output file when running under DOS\n");#endif break; } case 2: filenamei = argv[argc - 2]; filenameo = argv[argc - 1]; break; default: usage_exit(1, NULL); } if(strcmp(filenamei, minusstr)) { if((filei = fopen(filenamei, readmode)) == NULL) perror_exit("fopen(\"%s\", \"%s\")", filenamei, readmode); } else { filei = stdi;#ifdef MSDOS setmode(fileno(filei), O_BINARY);#endif } if(strcmp(filenameo, minusstr)) { if((fileo = fopen(filenameo, writemode)) == NULL) perror_exit("fopen(\"%s\", \"%s\")", filenameo, writemode); } else { fileo = stdo;#ifdef MSDOS setmode(fileno(fileo), O_BINARY);#endif } /* discard header on input file - can't rely on fseek() here */ if(ndiscard != 0) { char discardbuf[BUFSIZ]; for(i = 0; i < ndiscard / BUFSIZ; i++) if(fread(discardbuf, BUFSIZ, 1, filei) != 1) usage_exit(1, "EOF on input when discarding header\n"); if(ndiscard % BUFSIZ != 0) if(fread(discardbuf, ndiscard % BUFSIZ, 1, filei) != 1) usage_exit(1, "EOF on input when discarding header\n"); } if(!extract) { float *maxresn; int nread, nscan = 0, vbyte = MAX_VERSION + 1; nwrap = MAX(NWRAP, maxnlpc); /* grab some space for the input buffers */ buffer = long2d((ulong) nchan, (ulong) (blocksize + nwrap)); buffer1 = pmalloc((ulong) (blocksize * sizeof(*buffer1))); offset = long2d((ulong) nchan, (ulong) MAX(1, nmean)); maxresn = parseList(maxresnstr, nchan); for(chan = 0; chan < nchan; chan++) if(maxresn[chan] < MINBITRATE) usage_exit(1,"channel %d: expected bit rate must be >= %3.1f: %3.1f\n", MINBITRATE, chan, maxresn[chan]); else maxresn[chan] -= 3.0; for(chan = 0; chan < nchan; chan++) { for(i = 0; i < nwrap; i++) buffer[chan][i] = 0; buffer[chan] += nwrap; } if(maxnlpc > 0) qlpc = (int*) pmalloc((ulong) (maxnlpc * sizeof(*qlpc))); init_offset(offset, nchan, MAX(1, nmean), ftype); /* verbatim copy of skip bytes from input to output checking for the existence of magic number in header, and defaulting to internal storage if that happens */ if(version >= 2) { while(nskip - nscan > 0 && vbyte > MAX_VERSION) { int byte = getc_exit(filei); if(magic[nscan] != '\0' && byte == magic[nscan]) nscan++; else if(magic[nscan] == '\0' && byte <= MAX_VERSION) vbyte = byte; else { for(i = 0; i < nscan; i++) putc_exit(magic[i], fileo); if(byte == magic[0]) { nskip -= nscan; nscan = 1; } else { putc_exit(byte, fileo); nskip -= nscan + 1; nscan = 0; } } } if(vbyte > MAX_VERSION) { for(i = 0; i < nscan; i++) putc_exit(magic[i], fileo); nskip -= nscan; nscan = 0; } } /* write magic number */ if(fwrite(magic, strlen(magic), 1, fileo) != 1) usage_exit(1, "could not write the magic number\n"); /* write version number */ putc_exit(version, fileo); /* initialise the fixed length file read for the uncompressed stream */ fread_type_init(); /* initialise the variable length file write for the compressed stream */ var_put_init(); /* put file type and number of channels */ UINT_PUT(ftype, TYPESIZE, fileo); UINT_PUT(nchan, CHANSIZE, fileo); /* put blocksize if version > 0 */ if(version == 0) { if(blocksize != DEFAULT_BLOCK_SIZE) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -