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