annotate 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
rev   line source
tomwalters@0 1 /*
tomwalters@0 2 merge.c Merge N streams onto stdout using given operator.
tomwalters@0 3 -------
tomwalters@0 4
tomwalters@0 5 Usage: merge [options] file1 file2 ... fileN
tomwalters@0 6
tomwalters@0 7 For each vector of items (p1,p2,...,pN) read from file1, file2,...,fileN
tomwalters@0 8 respectively write the result of a merging operation on the stdout.
tomwalters@0 9
tomwalters@0 10 An input item is a number depending upon the type option.
tomwalters@0 11 The output item has the same type as that selected for input.
tomwalters@0 12
tomwalters@0 13 Internal processing is in floating point. A scale factor is included to
tomwalters@0 14 avoid overflow when casting output data.
tomwalters@0 15 If 16-bit over or under-flow occurs a warning is printed on the stderr.
tomwalters@0 16
tomwalters@0 17 The `range' option sets the start and duration of the process.
tomwalters@0 18 Its arguments are of the form: range=a-b (where start=a and duration=b-a+1)
tomwalters@0 19 or: range=a (where start=a and duration=1 )
tomwalters@0 20 The arguments can be in time units (ms, s) or samples (no units), and both
tomwalters@0 21 "min" (start of file) and "max" (end of file) are recognised.
tomwalters@0 22 Samples in a file are numbered 0,1,2,...,max.
tomwalters@0 23
tomwalters@0 24 All files are interpreted as functions sampled with origin at the point in
tomwalters@0 25 the file given by the first argument of the `range' option.
tomwalters@0 26 The functions are assumed to be zero for all samples beyond those specified
tomwalters@0 27 in the files.
tomwalters@0 28
tomwalters@0 29 The `phase' option shifts the origin to introduce a phase difference between
tomwalters@0 30 files. The `phase' option takes as argument a comma-separated list of
tomwalters@0 31 arguments which must be the same length as the number of file arguments.
tomwalters@0 32 Each argument can be in time units (ms, s) or samples (no units).
tomwalters@0 33 A +ve phase advances the origin into the file.
tomwalters@0 34 A -ve phase retards the origin. If a negative phase in combination with
tomwalters@0 35 the start of the file as set by the `range' option results in a new origin
tomwalters@0 36 outside the specified file, then the difference is padded with zeroes.
tomwalters@0 37
tomwalters@0 38 The weights option takes as argument a comma-separated list of real numbers
tomwalters@0 39 which must be the same length as the number of file arguments.
tomwalters@0 40 These number are applied as weights to each item prior to the merging
tomwalters@0 41 operation.
tomwalters@0 42
tomwalters@0 43 */
tomwalters@0 44
tomwalters@0 45 #include <stdio.h>
tomwalters@0 46 #include <math.h>
tomwalters@0 47 #include "options.h"
tomwalters@0 48 #include "strmatch.h"
tomwalters@0 49 #include "units.h"
tomwalters@0 50
tomwalters@0 51 char applic[] = "Merge N streams onto stdout using given operator." ;
tomwalters@0 52 char usage[] = "merge [options] file1 file2 ... fileN" ;
tomwalters@0 53
tomwalters@0 54 static char *helpstr, *debugstr, *sampstr, *opstr ;
tomwalters@0 55 static char *phstr, *rangestr, *scalestr, *typestr ;
tomwalters@0 56 static char *wtstr ;
tomwalters@0 57
tomwalters@0 58 static Options option[] = {
tomwalters@0 59 { "help" , "off" , &helpstr , "help" , DEBUG },
tomwalters@0 60 { "debug" , "off" , &debugstr , "debugging switch" , DEBUG },
tomwalters@0 61 { "samplerate", "20kHz" , &sampstr , "samplerate " , VAL },
tomwalters@0 62 { "operator" , "mean" , &opstr , "operator for merging" , VAL },
tomwalters@0 63 { "phase" , "off" , &phstr , "phase shift (phi1,...,phiN)" , VAL },
tomwalters@0 64 { "weights" , "off" , &wtstr , "weight coefficients (w1,...,wN)" , VAL },
tomwalters@0 65 { "range" , "0-max" , &rangestr , "inclusive time range for all files" , VAL },
tomwalters@0 66 { "scale" , "1.0" , &scalestr , "scale factor for output" , VAL },
tomwalters@0 67 { "type" , "short" , &typestr , "datatype" , VAL },
tomwalters@0 68 ( char * ) 0 } ;
tomwalters@0 69
tomwalters@0 70 char *operator[] = {
tomwalters@0 71 "cat" ,
tomwalters@0 72 "add" ,
tomwalters@0 73 "subtract" ,
tomwalters@0 74 "multiply" ,
tomwalters@0 75 "divide" ,
tomwalters@0 76 "abs" ,
tomwalters@0 77 "max" ,
tomwalters@0 78 "min" ,
tomwalters@0 79 "mean" ,
tomwalters@0 80 "norm" ,
tomwalters@0 81 ( char * ) 0 } ;
tomwalters@0 82
tomwalters@0 83
tomwalters@0 84 #define Cat 0 /* Functions (index of operator list) */
tomwalters@0 85 #define Add 1
tomwalters@0 86 #define Subtract 2
tomwalters@0 87 #define Multiply 3
tomwalters@0 88 #define Divide 4
tomwalters@0 89 #define Abs 5
tomwalters@0 90 #define Max 6
tomwalters@0 91 #define Min 7
tomwalters@0 92 #define Mean 8
tomwalters@0 93 #define Norm 9
tomwalters@0 94
tomwalters@0 95 #define sq(p) ((p)*(p))
tomwalters@0 96
tomwalters@0 97 int samplerate ;
tomwalters@0 98 int bytes ;
tomwalters@0 99 int type ; /* datatype index */
tomwalters@0 100 int op ; /* operator index */
tomwalters@0 101 float scale ;
tomwalters@0 102
tomwalters@0 103
tomwalters@0 104 main(argc, argv)
tomwalters@0 105 int argc;
tomwalters@0 106 char **argv;
tomwalters@0 107 {
tomwalters@0 108 FILE **fp ;
tomwalters@0 109 float *vec, *weight ;
tomwalters@0 110 int *origin ;
tomwalters@0 111 char **list ;
tomwalters@0 112 int i, j, n, morehelp() ;
tomwalters@0 113 int a, b ;
tomwalters@0 114 float writevec(), f, newscale = 1. ;
tomwalters@0 115
tomwalters@0 116 if ( ( i = getopts( option, argc, argv ) ) == 0 || !isoff( helpstr ) )
tomwalters@0 117 helpopts2( helpstr, argv[0], applic, usage, option, morehelp ) ;
tomwalters@0 118
tomwalters@0 119 samplerate = to_Hz( sampstr, 0 ) ;
tomwalters@0 120 scale = atof( scalestr ) ;
tomwalters@0 121 op = opindex( opstr ) ;
tomwalters@0 122
tomwalters@0 123 if ( ( type = typeindex( typestr ) ) < 0 ) {
tomwalters@0 124 fprintf( stderr, "merge: bad type [%s]\n", typestr ) ;
tomwalters@0 125 exit( 1 ) ;
tomwalters@0 126 }
tomwalters@0 127 bytes = typebytes( type ) ;
tomwalters@0 128
tomwalters@0 129 if ( range( rangestr, &a, &b, samplerate ) == 0 ) {
tomwalters@0 130 fprintf(stderr,"merge: bad range [%s]\n", rangestr ) ;
tomwalters@0 131 exit( 1 ) ;
tomwalters@0 132 }
tomwalters@0 133
tomwalters@0 134
tomwalters@0 135 fp = (FILE **)malloc( i * sizeof( FILE *) ) ;
tomwalters@0 136 vec = (float *)malloc( i * sizeof( float ) ) ;
tomwalters@0 137 origin = (int *)malloc( i * sizeof( int ) ) ;
tomwalters@0 138
tomwalters@0 139
tomwalters@0 140 if ( isoff( wtstr ) ) weight = (float *)0 ;
tomwalters@0 141 else {
tomwalters@0 142 list = (char **)malloc( i * sizeof( char *) ) ;
tomwalters@0 143 weight = (float *)malloc( i * sizeof( float ) ) ;
tomwalters@0 144 if ( ( n = tokens( wtstr, list, i, ',' ) ) != i ) {
tomwalters@0 145 fprintf( stderr,"merge: incorrect number of weights\n" ) ;
tomwalters@0 146 exit( 1 ) ;
tomwalters@0 147 }
tomwalters@0 148 for ( j = 0 ; j < n ; j++ )
tomwalters@0 149 weight[j] = atof( list[j] ) ;
tomwalters@0 150 }
tomwalters@0 151
tomwalters@0 152 if ( isoff( phstr ) )
tomwalters@0 153 for ( j = 0 ; j < i ; j++ )
tomwalters@0 154 origin[j] = a ;
tomwalters@0 155 else {
tomwalters@0 156 list = (char **)malloc( i * sizeof( char *) ) ;
tomwalters@0 157 if ( ( n = tokens( phstr, list, i, ',' ) ) != i ) {
tomwalters@0 158 fprintf( stderr,"merge: incorrect number of phases\n" ) ;
tomwalters@0 159 exit( 1 ) ;
tomwalters@0 160 }
tomwalters@0 161 for ( j = 0 ; j < n ; j++ )
tomwalters@0 162 origin[j] = a + to_p( list[j], samplerate ) ;
tomwalters@0 163 }
tomwalters@0 164
tomwalters@0 165
tomwalters@0 166
tomwalters@0 167 for ( n = 0 ; i > 0 ; i--, n++ ) {
tomwalters@0 168 if ( ( fp[n] = fropen( argv[argc-i] ) ) == (FILE *)0 ) {
tomwalters@0 169 fprintf( stderr,"merge: can't open %s\n", argv[argc-i] ) ;
tomwalters@0 170 exit( 1 ) ;
tomwalters@0 171 }
tomwalters@0 172 }
tomwalters@0 173
tomwalters@0 174
tomwalters@0 175 for ( i = 0 ; i < n ; i++ )
tomwalters@0 176 if ( origin[i] > 0 )
tomwalters@0 177 if ( seekstart( origin[i], bytes, fp[i] ) < origin[i] ) {
tomwalters@0 178 fprintf( stderr, "insufficient data in file%d\n", i+1 ) ;
tomwalters@0 179 exit( 1 ) ;
tomwalters@0 180 }
tomwalters@0 181
tomwalters@0 182
tomwalters@0 183 for ( i = a ; ( i <= b || b == (-1) ) && readvec( vec, n, fp, type, origin ) ; i++ ) {
tomwalters@0 184
tomwalters@0 185 if ( weight != (float *)0 )
tomwalters@0 186 do_weights( vec, weight, n ) ;
tomwalters@0 187
tomwalters@0 188 j = do_operation( vec, n, op ) ;
tomwalters@0 189 if ( ( f = writevec( vec, j, type, scale ) ) < newscale )
tomwalters@0 190 newscale = f ;
tomwalters@0 191 }
tomwalters@0 192
tomwalters@0 193 if ( newscale < 1. )
tomwalters@0 194 fprintf( stderr, "Warning: 16-bit overflow during merge. Try scale<%.4f\n", newscale ) ;
tomwalters@0 195
tomwalters@0 196 }
tomwalters@0 197
tomwalters@0 198
tomwalters@0 199 /*
tomwalters@0 200 Return the operator index (to the operator list) of the given operator string.
tomwalters@0 201 */
tomwalters@0 202
tomwalters@0 203 int opindex( opstr )
tomwalters@0 204 char *opstr ;
tomwalters@0 205 {
tomwalters@0 206 int i ;
tomwalters@0 207
tomwalters@0 208 if ( ( i = listindex( operator, opstr ) ) < 0 ) {
tomwalters@0 209 if ( i == (-1) )
tomwalters@0 210 fprintf(stderr,"merge: unknown operator [%s]\n", opstr ) ;
tomwalters@0 211 if ( i == (-2) )
tomwalters@0 212 fprintf(stderr,"merge: ambiguous operator [%s]\n", opstr ) ;
tomwalters@0 213 exit( 1 ) ;
tomwalters@0 214 }
tomwalters@0 215 return i ;
tomwalters@0 216 }
tomwalters@0 217
tomwalters@0 218
tomwalters@0 219
tomwalters@0 220 /*
tomwalters@0 221 Assign the given n-vector of floats using one item of given type (an index
tomwalters@0 222 to the datatype list in options.h) read from each of the n streams given in
tomwalters@0 223 the fp array. Return 0 if eof on any stream, otherwise return 1.
tomwalters@0 224 If the stream origin < 0 read a value of 0, increment the origin, and return
tomwalters@0 225 1 (successful read).
tomwalters@0 226 */
tomwalters@0 227
tomwalters@0 228 readvec( vec, n, fp, type, origin )
tomwalters@0 229 float *vec ;
tomwalters@0 230 int n ;
tomwalters@0 231 FILE **fp ;
tomwalters@0 232 int type ;
tomwalters@0 233 int *origin ;
tomwalters@0 234 {
tomwalters@0 235 int i ;
tomwalters@0 236
tomwalters@0 237 for ( i = 0 ; i < n ; i++ ) {
tomwalters@0 238
tomwalters@0 239 if ( origin[i] < 0 ) {
tomwalters@0 240 vec[i] = 0 ;
tomwalters@0 241 origin[i]++ ;
tomwalters@0 242 }
tomwalters@0 243
tomwalters@0 244 else if ( readitem( &vec[i], type, 1, fp[i] ) == 0 )
tomwalters@0 245 return 0 ;
tomwalters@0 246
tomwalters@0 247 }
tomwalters@0 248 return 1 ;
tomwalters@0 249 }
tomwalters@0 250
tomwalters@0 251
tomwalters@0 252 /*
tomwalters@0 253 Write n elements from the given vector on the stdout in the given type
tomwalters@0 254 (an index to the datatype list in options.h)
tomwalters@0 255 Multiply each element by the given scale factor (prior to type conversion).
tomwalters@0 256 If any element will over or underflow when scaled and cast into type
tomwalters@0 257 then return a more appropriate scale factor.
tomwalters@0 258 Return scale factor of 1 if no over or underflow.
tomwalters@0 259 */
tomwalters@0 260
tomwalters@0 261 float writevec( vec, n, type, scale )
tomwalters@0 262 float *vec ;
tomwalters@0 263 int n ;
tomwalters@0 264 int type ;
tomwalters@0 265 float scale;
tomwalters@0 266 {
tomwalters@0 267 float newscale ;
tomwalters@0 268 int i ;
tomwalters@0 269
tomwalters@0 270
tomwalters@0 271 for ( i = 0 ; i < n ; i++ ) {
tomwalters@0 272
tomwalters@0 273 newscale = check_overflow( vec[i], scale, type ) ;
tomwalters@0 274
tomwalters@0 275 vec[i] *= scale ;
tomwalters@0 276 writeitem( &vec[i], type, 1, stdout ) ;
tomwalters@0 277 }
tomwalters@0 278
tomwalters@0 279 return ( newscale ) ;
tomwalters@0 280 }
tomwalters@0 281
tomwalters@0 282
tomwalters@0 283
tomwalters@0 284 /*
tomwalters@0 285 Perform the given operation (op is an index to the operations list) on the
tomwalters@0 286 given n-vector, storing the results in the vector.
tomwalters@0 287 Return the size of the result (the number of elements of vec it occupies).
tomwalters@0 288 */
tomwalters@0 289
tomwalters@0 290 do_operation( vec, n, op )
tomwalters@0 291 float *vec ;
tomwalters@0 292 int n ;
tomwalters@0 293 int op ;
tomwalters@0 294 {
tomwalters@0 295 int i ;
tomwalters@0 296
tomwalters@0 297 switch ( op ) {
tomwalters@0 298
tomwalters@0 299 case Cat : return n ;
tomwalters@0 300 case Add : for ( i = 1 ; i < n ; i++ )
tomwalters@0 301 vec[0] += vec[i] ;
tomwalters@0 302 return 1 ;
tomwalters@0 303 case Subtract : for ( i = 1 ; i < n ; i++ )
tomwalters@0 304 vec[0] -= vec[i] ;
tomwalters@0 305 return 1 ;
tomwalters@0 306 case Abs : for ( i = 1 ; i < n ; i++ )
tomwalters@0 307 vec[0] = fabs(vec[0]-vec[i]) ;
tomwalters@0 308 return 1 ;
tomwalters@0 309 case Multiply : for ( i = 1 ; i < n ; i++ )
tomwalters@0 310 vec[0] *= vec[i] ;
tomwalters@0 311 return 1 ;
tomwalters@0 312 case Divide : for ( i = 1 ; i < n ; i++ )
tomwalters@0 313 vec[0] /= vec[i] ;
tomwalters@0 314 return 1 ;
tomwalters@0 315 case Max : for ( i = 1 ; i < n ; i++ )
tomwalters@0 316 if ( vec[i] > vec[0] ) vec[0] = vec[i] ;
tomwalters@0 317 return 1 ;
tomwalters@0 318 case Min : for ( i = 1 ; i < n ; i++ )
tomwalters@0 319 if ( vec[i] < vec[0] ) vec[0] = vec[i] ;
tomwalters@0 320 return 1 ;
tomwalters@0 321 case Mean : for ( i = 1 ; i < n ; i++ )
tomwalters@0 322 vec[0] += vec[i] ;
tomwalters@0 323 vec[0] /= n ;
tomwalters@0 324 return 1 ;
tomwalters@0 325 case Norm: vec[0] = sq(vec[0]) ;
tomwalters@0 326 for ( i = 1 ; i < n ; i++ )
tomwalters@0 327 vec[0] += sq(vec[i]) ;
tomwalters@0 328 vec[0] = sqrt(vec[0]) ;
tomwalters@0 329 return 1 ;
tomwalters@0 330 }
tomwalters@0 331 }
tomwalters@0 332
tomwalters@0 333
tomwalters@0 334 do_weights( vec, weight, n )
tomwalters@0 335 float *vec ;
tomwalters@0 336 float *weight ;
tomwalters@0 337 int n ;
tomwalters@0 338 {
tomwalters@0 339 int i ;
tomwalters@0 340
tomwalters@0 341 for ( i = 0 ; i < n ; i++ )
tomwalters@0 342 vec[i] *= weight[i] ;
tomwalters@0 343 }
tomwalters@0 344
tomwalters@0 345
tomwalters@0 346 morehelp()
tomwalters@0 347 {
tomwalters@0 348 fprintf(stderr,"\noperators: \n");
tomwalters@0 349 fprintf(stderr," cat concatenate p1,p2,p3,... \n");
tomwalters@0 350 fprintf(stderr," add p1+p2+p3+... \n");
tomwalters@0 351 fprintf(stderr," subtract p1-p2-p3-... \n");
tomwalters@0 352 fprintf(stderr," abs ||p1-p2|-p3|-... \n");
tomwalters@0 353 fprintf(stderr," multiply p1*p2*p3*... \n");
tomwalters@0 354 fprintf(stderr," divide p1/p2/p3/... \n");
tomwalters@0 355 fprintf(stderr," max max(p1,p2,p3,...) \n");
tomwalters@0 356 fprintf(stderr," min min(p1,p2,p3,...) \n");
tomwalters@0 357 fprintf(stderr," mean mean(p1,p2,p3,...) \n");
tomwalters@0 358 fprintf(stderr," norm sqrt( p1*p1+p2*p2+p3*p3+... ) \n");
tomwalters@0 359 exit( 1 ) ;
tomwalters@0 360 }
tomwalters@0 361
tomwalters@0 362