Mercurial > hg > aim92
view tools/merge.c @ 0:5242703e91d3 tip
Initial checkin for AIM92 aimR8.2 (last updated May 1997).
author | tomwalters |
---|---|
date | Fri, 20 May 2011 15:19:45 +0100 |
parents | |
children |
line wrap: on
line source
/* merge.c Merge N streams onto stdout using given operator. ------- Usage: merge [options] file1 file2 ... fileN For each vector of items (p1,p2,...,pN) read from file1, file2,...,fileN respectively write the result of a merging operation on the stdout. An input item is a number depending upon the type option. The output item has the same type as that selected for input. Internal processing is in floating point. A scale factor is included to avoid overflow when casting output data. If 16-bit over or under-flow occurs a warning is printed on the stderr. The `range' option sets the start and duration of the process. Its arguments are of the form: range=a-b (where start=a and duration=b-a+1) or: range=a (where start=a and duration=1 ) The arguments can be in time units (ms, s) or samples (no units), and both "min" (start of file) and "max" (end of file) are recognised. Samples in a file are numbered 0,1,2,...,max. All files are interpreted as functions sampled with origin at the point in the file given by the first argument of the `range' option. The functions are assumed to be zero for all samples beyond those specified in the files. The `phase' option shifts the origin to introduce a phase difference between files. The `phase' option takes as argument a comma-separated list of arguments which must be the same length as the number of file arguments. Each argument can be in time units (ms, s) or samples (no units). A +ve phase advances the origin into the file. A -ve phase retards the origin. If a negative phase in combination with the start of the file as set by the `range' option results in a new origin outside the specified file, then the difference is padded with zeroes. The weights option takes as argument a comma-separated list of real numbers which must be the same length as the number of file arguments. These number are applied as weights to each item prior to the merging operation. */ #include <stdio.h> #include <math.h> #include "options.h" #include "strmatch.h" #include "units.h" char applic[] = "Merge N streams onto stdout using given operator." ; char usage[] = "merge [options] file1 file2 ... fileN" ; static char *helpstr, *debugstr, *sampstr, *opstr ; static char *phstr, *rangestr, *scalestr, *typestr ; static char *wtstr ; static Options option[] = { { "help" , "off" , &helpstr , "help" , DEBUG }, { "debug" , "off" , &debugstr , "debugging switch" , DEBUG }, { "samplerate", "20kHz" , &sampstr , "samplerate " , VAL }, { "operator" , "mean" , &opstr , "operator for merging" , VAL }, { "phase" , "off" , &phstr , "phase shift (phi1,...,phiN)" , VAL }, { "weights" , "off" , &wtstr , "weight coefficients (w1,...,wN)" , VAL }, { "range" , "0-max" , &rangestr , "inclusive time range for all files" , VAL }, { "scale" , "1.0" , &scalestr , "scale factor for output" , VAL }, { "type" , "short" , &typestr , "datatype" , VAL }, ( char * ) 0 } ; char *operator[] = { "cat" , "add" , "subtract" , "multiply" , "divide" , "abs" , "max" , "min" , "mean" , "norm" , ( char * ) 0 } ; #define Cat 0 /* Functions (index of operator list) */ #define Add 1 #define Subtract 2 #define Multiply 3 #define Divide 4 #define Abs 5 #define Max 6 #define Min 7 #define Mean 8 #define Norm 9 #define sq(p) ((p)*(p)) int samplerate ; int bytes ; int type ; /* datatype index */ int op ; /* operator index */ float scale ; main(argc, argv) int argc; char **argv; { FILE **fp ; float *vec, *weight ; int *origin ; char **list ; int i, j, n, morehelp() ; int a, b ; float writevec(), f, newscale = 1. ; if ( ( i = getopts( option, argc, argv ) ) == 0 || !isoff( helpstr ) ) helpopts2( helpstr, argv[0], applic, usage, option, morehelp ) ; samplerate = to_Hz( sampstr, 0 ) ; scale = atof( scalestr ) ; op = opindex( opstr ) ; if ( ( type = typeindex( typestr ) ) < 0 ) { fprintf( stderr, "merge: bad type [%s]\n", typestr ) ; exit( 1 ) ; } bytes = typebytes( type ) ; if ( range( rangestr, &a, &b, samplerate ) == 0 ) { fprintf(stderr,"merge: bad range [%s]\n", rangestr ) ; exit( 1 ) ; } fp = (FILE **)malloc( i * sizeof( FILE *) ) ; vec = (float *)malloc( i * sizeof( float ) ) ; origin = (int *)malloc( i * sizeof( int ) ) ; if ( isoff( wtstr ) ) weight = (float *)0 ; else { list = (char **)malloc( i * sizeof( char *) ) ; weight = (float *)malloc( i * sizeof( float ) ) ; if ( ( n = tokens( wtstr, list, i, ',' ) ) != i ) { fprintf( stderr,"merge: incorrect number of weights\n" ) ; exit( 1 ) ; } for ( j = 0 ; j < n ; j++ ) weight[j] = atof( list[j] ) ; } if ( isoff( phstr ) ) for ( j = 0 ; j < i ; j++ ) origin[j] = a ; else { list = (char **)malloc( i * sizeof( char *) ) ; if ( ( n = tokens( phstr, list, i, ',' ) ) != i ) { fprintf( stderr,"merge: incorrect number of phases\n" ) ; exit( 1 ) ; } for ( j = 0 ; j < n ; j++ ) origin[j] = a + to_p( list[j], samplerate ) ; } for ( n = 0 ; i > 0 ; i--, n++ ) { if ( ( fp[n] = fropen( argv[argc-i] ) ) == (FILE *)0 ) { fprintf( stderr,"merge: can't open %s\n", argv[argc-i] ) ; exit( 1 ) ; } } for ( i = 0 ; i < n ; i++ ) if ( origin[i] > 0 ) if ( seekstart( origin[i], bytes, fp[i] ) < origin[i] ) { fprintf( stderr, "insufficient data in file%d\n", i+1 ) ; exit( 1 ) ; } for ( i = a ; ( i <= b || b == (-1) ) && readvec( vec, n, fp, type, origin ) ; i++ ) { if ( weight != (float *)0 ) do_weights( vec, weight, n ) ; j = do_operation( vec, n, op ) ; if ( ( f = writevec( vec, j, type, scale ) ) < newscale ) newscale = f ; } if ( newscale < 1. ) fprintf( stderr, "Warning: 16-bit overflow during merge. Try scale<%.4f\n", newscale ) ; } /* Return the operator index (to the operator list) of the given operator string. */ int opindex( opstr ) char *opstr ; { int i ; if ( ( i = listindex( operator, opstr ) ) < 0 ) { if ( i == (-1) ) fprintf(stderr,"merge: unknown operator [%s]\n", opstr ) ; if ( i == (-2) ) fprintf(stderr,"merge: ambiguous operator [%s]\n", opstr ) ; exit( 1 ) ; } return i ; } /* Assign the given n-vector of floats using one item of given type (an index to the datatype list in options.h) read from each of the n streams given in the fp array. Return 0 if eof on any stream, otherwise return 1. If the stream origin < 0 read a value of 0, increment the origin, and return 1 (successful read). */ readvec( vec, n, fp, type, origin ) float *vec ; int n ; FILE **fp ; int type ; int *origin ; { int i ; for ( i = 0 ; i < n ; i++ ) { if ( origin[i] < 0 ) { vec[i] = 0 ; origin[i]++ ; } else if ( readitem( &vec[i], type, 1, fp[i] ) == 0 ) return 0 ; } return 1 ; } /* Write n elements from the given vector on the stdout in the given type (an index to the datatype list in options.h) Multiply each element by the given scale factor (prior to type conversion). If any element will over or underflow when scaled and cast into type then return a more appropriate scale factor. Return scale factor of 1 if no over or underflow. */ float writevec( vec, n, type, scale ) float *vec ; int n ; int type ; float scale; { float newscale ; int i ; for ( i = 0 ; i < n ; i++ ) { newscale = check_overflow( vec[i], scale, type ) ; vec[i] *= scale ; writeitem( &vec[i], type, 1, stdout ) ; } return ( newscale ) ; } /* Perform the given operation (op is an index to the operations list) on the given n-vector, storing the results in the vector. Return the size of the result (the number of elements of vec it occupies). */ do_operation( vec, n, op ) float *vec ; int n ; int op ; { int i ; switch ( op ) { case Cat : return n ; case Add : for ( i = 1 ; i < n ; i++ ) vec[0] += vec[i] ; return 1 ; case Subtract : for ( i = 1 ; i < n ; i++ ) vec[0] -= vec[i] ; return 1 ; case Abs : for ( i = 1 ; i < n ; i++ ) vec[0] = fabs(vec[0]-vec[i]) ; return 1 ; case Multiply : for ( i = 1 ; i < n ; i++ ) vec[0] *= vec[i] ; return 1 ; case Divide : for ( i = 1 ; i < n ; i++ ) vec[0] /= vec[i] ; return 1 ; case Max : for ( i = 1 ; i < n ; i++ ) if ( vec[i] > vec[0] ) vec[0] = vec[i] ; return 1 ; case Min : for ( i = 1 ; i < n ; i++ ) if ( vec[i] < vec[0] ) vec[0] = vec[i] ; return 1 ; case Mean : for ( i = 1 ; i < n ; i++ ) vec[0] += vec[i] ; vec[0] /= n ; return 1 ; case Norm: vec[0] = sq(vec[0]) ; for ( i = 1 ; i < n ; i++ ) vec[0] += sq(vec[i]) ; vec[0] = sqrt(vec[0]) ; return 1 ; } } do_weights( vec, weight, n ) float *vec ; float *weight ; int n ; { int i ; for ( i = 0 ; i < n ; i++ ) vec[i] *= weight[i] ; } morehelp() { fprintf(stderr,"\noperators: \n"); fprintf(stderr," cat concatenate p1,p2,p3,... \n"); fprintf(stderr," add p1+p2+p3+... \n"); fprintf(stderr," subtract p1-p2-p3-... \n"); fprintf(stderr," abs ||p1-p2|-p3|-... \n"); fprintf(stderr," multiply p1*p2*p3*... \n"); fprintf(stderr," divide p1/p2/p3/... \n"); fprintf(stderr," max max(p1,p2,p3,...) \n"); fprintf(stderr," min min(p1,p2,p3,...) \n"); fprintf(stderr," mean mean(p1,p2,p3,...) \n"); fprintf(stderr," norm sqrt( p1*p1+p2*p2+p3*p3+... ) \n"); exit( 1 ) ; }