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 ) ;
+}
+
+