Mercurial > hg > aim92
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 |