Mercurial > hg > aim92
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/merge.c Fri May 20 15:19:45 2011 +0100 @@ -0,0 +1,362 @@ +/* + 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 ) ; +} + +