Mercurial > hg > aim92
comparison tools/audim.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 audim.c auditory images | |
3 --------- | |
4 | |
5 This program provides methods of constructing time-varying auditory | |
6 images from the output of the cochlear model which are alternatives to | |
7 the gensai (stabilized auditory image) program. Correlograms (ie. row- | |
8 wise autocorrelation) and row-wise Fourier transform are provided. The | |
9 program reads an AIM header and the output from the genbmm (basilar mem- | |
10 brane motion) or gennap (neural activity pattern) programs. This is | |
11 divided into contiguous time frames and written on the stdout with an | |
12 appropriate header as if output from the gensai program. This enables | |
13 genbmm or gennap output to be divided into time frames and replayed as a | |
14 cartoon by gensai using the "useprevious" option. Additional processing | |
15 to each frame is optionally available to compute alternative forms of | |
16 auditory image according to the "image" option. | |
17 | |
18 | |
19 The options "start" and "length" specify the size of the input. The | |
20 options "width" and "frstep" specify the frames which are output. The | |
21 input is divided into frames according to the width option and the | |
22 frstep option. | |
23 | |
24 Special option values are: | |
25 | |
26 length=max Read all the input from the given start to its end. | |
27 width=max Output framewidth is set equal to the given input | |
28 length, and if this is also "max", then the | |
29 framewidth is the remainder of the input. | |
30 frames=1-max Select the 1st to the last frame inclusively. | |
31 frame=4 Select the 4th frame only. | |
32 | |
33 image=off Divide the input into frames for replay as a cartoon. | |
34 image=acgram Compute correlogram of each frame. | |
35 image=ftgram Compute power spectrum of each channel of each frame. | |
36 image=phgram Compute phase spectrum of each channel of each frame. | |
37 | |
38 Most options in the input header are copied to the output header. This | |
39 enables options which are needed for the eventual display to pass | |
40 straight through. Some options are set so that they can override the | |
41 input header. For example, the display option is set on to enable | |
42 display even when input has display=off. The animate option can be set | |
43 on even when the input has animate=off. Parts of the header are changed | |
44 for the new sai format: (frames, frameshift, framewidth, frameheight, | |
45 framebytes). | |
46 | |
47 Padding: | |
48 The input nap is divided into frames according to the width option (called | |
49 framewidth internally) and the frstep option (called frameshift internally). | |
50 The framewidth is used as the basis for output image frame width: | |
51 the output width is actually the next power-of-2 above twice the framewidth. | |
52 This is because: | |
53 a. fft and acf output is always half the given frame size, due to symmetry, | |
54 so the input must be padded to twice its width. | |
55 b. To use fft, the input must also be a power of two. | |
56 So, each input row is padded out to the next power of two above twice its | |
57 width. | |
58 | |
59 Certain display parameters have different default values for different | |
60 applications. The gensai display parameters should be set to the | |
61 appropriate values, in order to plot the cartoon on the same scale. For | |
62 example: when the source application is gennap, set gensai top=1000, | |
63 when the source application is genbmm, set gensai bottom=-100. | |
64 | |
65 | |
66 Examples: | |
67 | |
68 1. An animated normalized autocorrelogram from a nap: | |
69 | |
70 gennap len=64ms output=stdout display=off file | audim norm=on anim=on > file.sai | |
71 gensai useprev=on top=1000 cegc -(for landscape plot) | |
72 genspl useprev=on top=1000 pensize=2 cegc -(for spiral plot) | |
73 | |
74 | |
75 2. To convert a nap to multiple animated frames: | |
76 | |
77 gennap len=16ms display=off output=stdout file | audim image=off width=8ms frstep=0.2ms anim=on > file.sai | |
78 gensai useprev=on top=1000 cegc -(for landscape plot) | |
79 genspl useprev=on top=1000 pensize=2 cegc -(for spiral plot) | |
80 | |
81 (Note: spirals look better in a square box, so you might use options: | |
82 dencf=1 width=500 height=500 ) | |
83 | |
84 3. To view the basilar membrane from a cross section, animating the waves on it. | |
85 | |
86 genbmm mincf=220 maxcf=660 len=8ms output=stdout display=off file | audim image=off width=1p frstep=1p display=on anim=on | edframe Tran=on > foo.sai | |
87 gensai bott=-100 useprev=on mag=.2 foo | |
88 | |
89 or: | |
90 | |
91 genbmm mincf=220 maxcf=660 len=32ms output=stdout display=off file | \ | |
92 audim image=off width=1p frstep=1p display=on anim=on | \ | |
93 edframe Tran=on Header=off > foo | |
94 | |
95 x11play -n75 -a500 foo | |
96 | |
97 */ | |
98 | |
99 | |
100 #include <stdio.h> | |
101 #include <math.h> | |
102 #include "header.h" | |
103 #include "options.h" | |
104 #include "units.h" | |
105 #include "strmatch.h" | |
106 #include "sigproc.h" | |
107 #include "freqs.c" | |
108 | |
109 char applic[] = "Auditory images of neural activity patterns (NAP). " ; | |
110 | |
111 static char *helpstr, *debugstr, *dispstr, *anistr, *startstr, *imstr ; | |
112 static char *lengthstr, *widthstr, *shiftstr, *headerstr, *cfstr, *framestr ; | |
113 static char *normstr, *wstr, *sacfstr, *smagstr, *sphstr ; | |
114 static char *blstr, *erbstr ; | |
115 | |
116 static Options option[] = { | |
117 { "help" , "off" , &helpstr , "help" , DEBUG }, | |
118 { "debug" , "off" , &debugstr , "debugging switch" , DEBUG }, | |
119 { "display" , "on" , &dispstr , "Display output image." , SETFLAG }, | |
120 { "animate" , "off" , &anistr , "Animate cartoon." , SETFLAG }, | |
121 { "frames" , "1-max" , &framestr , "Select frames inclusively" , VAL }, | |
122 { "image" , "acgram" , &imstr , "Form of auditory image." , VAL }, | |
123 { "header" , "on" , &headerstr , "Header (for gensai useprevious=on)." , VAL }, | |
124 { "start" , "0" , &startstr , "Start point in i/p NAP" , VAL }, | |
125 { "length" , "max" , &lengthstr , "Length of i/p NAP to process." , VAL }, | |
126 { "frstep" , "16ms" , &shiftstr , "Step between frames of the auditory image." , VAL }, | |
127 { "width" , "32ms" , &widthstr , "Width of auditory image." , VAL }, | |
128 { "normalize" , "off" , &normstr , "Normalization" , SETFLAG }, | |
129 { "window" , "off" , &wstr , "Hamming window" , SETFLAG }, | |
130 { "bandlimit" , "off" , &blstr , "Zero outside bandwidth." , SETFLAG }, | |
131 { "erbs" , "2" , &erbstr , "Width (in ERBS) of band either side of cf." , SVAL }, | |
132 { "align_cf" , "off" , &cfstr , "Align on centre frequency." , SETFLAG }, | |
133 { "scale_acf" , "0.025" , &sacfstr , "Scale factor for acf output" , SVAL }, | |
134 { "scale_fft" , "0.08" , &smagstr , "Scale factor for fft magnitude output" , SVAL }, | |
135 { "scale_phs" , "100" , &sphstr , "Scale factor for fft phase output" , SVAL }, | |
136 ( char * ) 0 } ; | |
137 | |
138 | |
139 int frameheight ; /* Nap parameters read from header */ | |
140 int frames, samplerate ; | |
141 int framewidth ; /* width option */ | |
142 | |
143 int start, length ; | |
144 | |
145 int Newframeheight, Newframewidth ; /* Sai parameters to write */ | |
146 int Newframes ; | |
147 int Newframeshift ; | |
148 int Newframebytes ; | |
149 | |
150 | |
151 char *limitstr ; /* Sai parameters used to get centre-frequencies */ | |
152 char *qualstr ; | |
153 char *minstr ; | |
154 char *maxstr ; | |
155 char *denstr ; | |
156 char *chansstr ; | |
157 double *frequencies ; | |
158 int nerbs ; /* bandwidth defined as number of erbs either side of cf */ | |
159 int bandlimit ; /* flag for zeroing outside bandwidth around centre-freqs */ | |
160 int align ; /* flag for aligning centre-freqs */ | |
161 | |
162 #define NONE 0 /* forms of auditory image */ | |
163 #define ACGRAM 1 | |
164 #define FTGRAM 2 | |
165 #define PHGRAM 3 | |
166 int image ; | |
167 | |
168 float *buf ; /* fft working space */ | |
169 int zeroes ; /* padding */ | |
170 float *W ; /* Hamming window for fft */ | |
171 short window ; /* flag for window */ | |
172 | |
173 short debug ; /* flag for debug printf's */ | |
174 | |
175 main(argc, argv) | |
176 int argc ; | |
177 char *argv[] ; | |
178 { | |
179 FILE *fp ; | |
180 int i, framebytes, startbytes, frameshift, framebyteshift; | |
181 char *header, *SaiHeader(); | |
182 short *nap, *frame, *endframe; | |
183 int a, b ; | |
184 char *val1, *val2 ; | |
185 | |
186 fp = openopts( option,argc,argv ) ; | |
187 if ( !isoff( helpstr ) ) | |
188 helpopts( helpstr, argv[0], applic, option ) ; | |
189 | |
190 window = ison( wstr ) ; | |
191 nerbs = atoi( erbstr ) ; | |
192 debug = ison( debugstr ) ; | |
193 | |
194 /**** Form of image ****/ | |
195 | |
196 if ( iststr( imstr, "acgram" ) ) { | |
197 image = ACGRAM ; | |
198 } | |
199 else if ( iststr( imstr, "ftgram" ) ) { | |
200 image = FTGRAM ; | |
201 } | |
202 else if ( iststr( imstr, "phgram" ) ) { | |
203 image = PHGRAM ; | |
204 } | |
205 else if ( isoff( imstr ) ) { | |
206 image = NONE ; | |
207 } | |
208 else { | |
209 fprintf(stderr, "audim: unknown form of auditory image [%s]\n", imstr ) ; | |
210 exit( 1 ) ; | |
211 } | |
212 | |
213 align = ison( cfstr ) ; | |
214 bandlimit = ison( blstr ) ; | |
215 | |
216 | |
217 /**** parse bounds on number of frames ****/ | |
218 | |
219 if ( getvals( framestr, &val1, &val2, "-" ) == BADVAL ) { | |
220 fprintf(stderr,"audim: bad frame selector [%s]\n", framestr ) ; | |
221 exit( 1 ) ; | |
222 } | |
223 a = atoi( val1 ) ; | |
224 if ( isempty( val2 ) ) b = a ; | |
225 else if ( ismax( val2 ) ) b = 0 ; | |
226 else b = atoi( val2 ) ; | |
227 | |
228 if (b<a && b>0) fprintf(stderr,"audim warning: bad frame specifiers\n"); | |
229 | |
230 | |
231 /**** Read header and options to find dimensions of auditory image ****/ | |
232 | |
233 if ( (header = ReadHeader(fp)) == (char *) 0 ) { | |
234 fprintf(stderr,"audim: header not found\n"); | |
235 exit(1); | |
236 } | |
237 | |
238 frameheight = HeaderInt( header, "frameheight" ); | |
239 frames = HeaderInt( header, "frames" ); | |
240 samplerate = HeaderSamplerate( header ); | |
241 start = to_p( startstr, samplerate ); | |
242 frameshift = to_p( shiftstr, samplerate ) ; | |
243 | |
244 if ( ismax( lengthstr ) ) /* Special case for remainder of input */ | |
245 length = frames - start ; | |
246 else | |
247 length = to_p( lengthstr, samplerate ); | |
248 | |
249 if ( start + length > frames ) { | |
250 fprintf(stderr,"audim: nap too small (%d ms) for requested start and length \n", to_ms( frames, samplerate ) ); | |
251 exit(1); | |
252 } | |
253 | |
254 framebytes = frameheight * length * sizeof(short) ; | |
255 startbytes = frameheight * start * sizeof(short) ; | |
256 | |
257 if ( ismax( widthstr ) ) /* Special case for single frame of max width */ | |
258 framewidth = length ; | |
259 else | |
260 framewidth = to_p( widthstr, samplerate ) ; | |
261 | |
262 frames = ( length - framewidth ) / frameshift ; | |
263 zeroes = getpower( framewidth << 1 ) - framewidth ; | |
264 | |
265 | |
266 /**** Get centre-frequencies information using info given in header ****/ | |
267 | |
268 limitstr = HeaderStringOnly( header, "bwmin_afb" ); | |
269 qualstr = HeaderStringOnly( header, "quality_afb" ); | |
270 minstr = HeaderStringOnly( header, "mincf_afb" ); | |
271 maxstr = HeaderStringOnly( header, "maxcf_afb" ); | |
272 denstr = HeaderStringOnly( header, "dencf_afb" ); | |
273 chansstr = HeaderStringOnly( header, "channels_afb" ); | |
274 | |
275 SetErbParameters( to_Hz( limitstr ), atof( qualstr ) ) ; | |
276 if( OptionInt( chansstr ) == 0 ) | |
277 frequencies = GenerateCenterFrequencies( to_Hz( minstr ), to_Hz( maxstr ), atof( denstr ) ) ; | |
278 else | |
279 frequencies = NumberedCenterFrequencies( to_Hz( minstr ), to_Hz( maxstr ), OptionInt( chansstr ) ) ; | |
280 | |
281 | |
282 /**** Output frame dimensions (to write into new header) ****/ | |
283 | |
284 Newframeheight = frameheight ; | |
285 | |
286 if ( !align ) { | |
287 if ( image == NONE ) | |
288 Newframewidth = framewidth ; | |
289 else | |
290 Newframewidth = ( framewidth + zeroes ) >> 1 ; /* spectral bins */ | |
291 } | |
292 else { /* number of bins corresponding to the filter bandwidth */ | |
293 switch ( image ) { | |
294 case NONE : Newframewidth = framewidth ; | |
295 break ; | |
296 case ACGRAM : Newframewidth = maxlagwidth( to_Hz( minstr ), nerbs ) ; | |
297 break ; | |
298 case FTGRAM : Newframewidth = maxbandwidth( to_Hz( maxstr ), nerbs, (framewidth+zeroes)>>1 ) ; | |
299 break ; | |
300 } | |
301 } | |
302 Newframeshift = frameshift ; | |
303 Newframebytes = Newframeheight * Newframewidth * sizeof(short) ; | |
304 | |
305 if ( frameshift > 0 ) { | |
306 if ( b == 0 ) | |
307 Newframes = frames - (a-1) ; | |
308 else | |
309 Newframes = b - (a-1) ; | |
310 } | |
311 else { | |
312 fprintf(stderr,"audim: non-positive frstep [%d]\n", frameshift); | |
313 exit(1); | |
314 } | |
315 | |
316 | |
317 /**** Check limits etc.. ****/ | |
318 | |
319 if ( b > frames ) { | |
320 fprintf(stderr,"audim: can't select frame %d out of %d frames\n", b, frames ) ; | |
321 exit(1); | |
322 } | |
323 | |
324 if ( length < framewidth ) { | |
325 fprintf(stderr,"audim: nap too small (%d ms) for requested width\n", to_ms( length, samplerate ) ); | |
326 exit(1); | |
327 } | |
328 | |
329 if (frames<=0) { | |
330 if (frames==0) fprintf(stderr,"audim: zero frames input\n"); | |
331 if (frames<0) fprintf(stderr,"audim: garbled number of frames, (start set too big?)\n"); | |
332 exit(1); | |
333 } | |
334 | |
335 if (a>frames || b>frames) | |
336 fprintf(stderr,"audim warning: bad frame selectors\n"); | |
337 | |
338 | |
339 | |
340 if ( debug ) { | |
341 fprintf(stderr, "Header: frames=%d frameheight=%d\n", frames, frameheight ) ; | |
342 fprintf(stderr, "Options: a=%d b=%d start=%d length=%d frameshift=%d framewidth=%d\n", a, b, start, length, frameshift, framewidth ) ; | |
343 fprintf(stderr, "Output: zeroes=%d Newframewidth=%d Newframes=%d \n", zeroes, Newframewidth, Newframes ) ; | |
344 } | |
345 | |
346 | |
347 /**** Write new sai header ****/ | |
348 | |
349 if ( ison( headerstr ) ) | |
350 WriteHeader( SaiHeader(header), stdout ); | |
351 | |
352 | |
353 /**** Allocate space for framebytes of nap data ****/ | |
354 | |
355 if ( (nap = (short *)malloc( framebytes )) == NULL ) { | |
356 fprintf(stderr,"audim: malloc out of space\n"); | |
357 exit(1); | |
358 } | |
359 | |
360 | |
361 /**** Allocate and assign window coeffs ****/ | |
362 | |
363 if ( window ) | |
364 W = hamming( framewidth ) ; | |
365 | |
366 | |
367 /**** Allocate fft working space ****/ | |
368 | |
369 buf = (float *)malloc( ( framewidth + zeroes ) * sizeof(float) ); | |
370 | |
371 | |
372 /**** Seek to start in blocks of framebytes ****/ | |
373 | |
374 for (i=framebytes ; i < startbytes ; i += framebytes) | |
375 if ( fread( nap, framebytes, 1, fp ) == NULL ) { | |
376 fprintf(stderr,"audim: missing data after header\n"); | |
377 exit(1); | |
378 } | |
379 if ( (startbytes -= (i - framebytes)) > 0 ) | |
380 if ( fread( nap, startbytes, 1, fp ) == NULL ) { | |
381 fprintf(stderr,"audim: missing data after header\n"); | |
382 exit(1); | |
383 } | |
384 | |
385 /**** Read framebytes of i/p nap data ****/ | |
386 | |
387 if ( fread( nap, framebytes, 1, fp ) == NULL ) { | |
388 fprintf(stderr,"audim: missing data after header\n"); | |
389 exit(1); | |
390 } | |
391 | |
392 framebyteshift = frameshift * frameheight ; | |
393 nap = nap + (a-1) * framebyteshift ; | |
394 endframe = nap + Newframes * framebyteshift ; | |
395 | |
396 switch ( image ) { | |
397 case NONE : fprintf(stderr,"Output framewidth = %dp \n", Newframewidth ) ; break ; | |
398 case ACGRAM : fprintf(stderr,"Output framewidth = %dp Lag range = 0-%dms\n", Newframewidth, (Newframewidth*1000)/samplerate ) ; break ; | |
399 case FTGRAM : fprintf(stderr,"Output framewidth = %dp Frequency range = 0-%dkHz\n", Newframewidth, samplerate/2000 ) ; break ; | |
400 case PHGRAM : break ; | |
401 } | |
402 | |
403 for ( frame = nap ; frame < endframe ; frame += framebyteshift ) { | |
404 | |
405 fprintf(stderr,"audim: %d / %d\n", a++, frames ); | |
406 switch ( image ) { | |
407 | |
408 case NONE : writeframe( frame ) ; break ; | |
409 case ACGRAM : acgram( frame ) ; break ; | |
410 case FTGRAM : ftgram( frame ) ; break ; | |
411 case PHGRAM : phgram( frame ) ; break ; | |
412 | |
413 } | |
414 } | |
415 fprintf(stderr,"audim: done\n" ); | |
416 } | |
417 | |
418 | |
419 | |
420 | |
421 | |
422 int OptionInt( str ) | |
423 char *str ; | |
424 { | |
425 if( strcmp( str, "on" ) == 0 ) | |
426 return( 1 ) ; | |
427 else if( strcmp( str, "Not_used" ) == 0 ) | |
428 return( 0 ) ; | |
429 else | |
430 return( atoi( str ) ) ; | |
431 } | |
432 | |
433 | |
434 /*********************** Read header and build new header *****************/ | |
435 | |
436 /* | |
437 Copy the original nap header to a new sai header, changing in order: | |
438 frames | |
439 frameshift | |
440 framewidth | |
441 frameheight | |
442 framebytes | |
443 animate | |
444 display | |
445 Finally, update the new header_bytes, and return the new header. | |
446 */ | |
447 | |
448 char *SaiHeader( napheader ) | |
449 char *napheader ; | |
450 { | |
451 char *saiheader; | |
452 char *p0, *p1, *p2, *s, str[64]; | |
453 | |
454 saiheader = (char *)malloc( strlen(napheader) + 256 ) ; | |
455 | |
456 p0 = saiheader ; | |
457 p1 = napheader ; | |
458 | |
459 /* copy to first item after the header_bytes */ | |
460 | |
461 p2 = HeaderString( napheader , "header_bytes" ) ; | |
462 while( p1 < p2 ) | |
463 *p0++ = *p1++ ; | |
464 while (*p1 != '\n') | |
465 *p0++ = *p1++ ; | |
466 *p0++ = *p1++; | |
467 | |
468 /* insert frstep_aid at top of new header */ | |
469 | |
470 sprintf( str,"frstep_aid=%s\n", shiftstr ) ; | |
471 for (s = str ; *s != '\n' ; ) | |
472 *p0++ = *s++; | |
473 *p0++ = *s; | |
474 | |
475 /** copy up to frames **/ | |
476 | |
477 p2 = HeaderString( napheader , "frames" ) ; | |
478 while( p1 < p2 ) | |
479 *p0++ = *p1++ ; | |
480 | |
481 sprintf(str,"%d\n", Newframes); | |
482 for (s = str ; *s != '\n' ; ) | |
483 *p0++ = *s++; | |
484 *p0++ = *s; | |
485 while (*p1 != '\n') | |
486 *p1++; | |
487 *p1++; | |
488 | |
489 | |
490 /** copy up to frameshift **/ | |
491 | |
492 p2 = HeaderString( napheader , "frameshift" ) ; | |
493 while ( p1 < p2 ) | |
494 *p0++ = *p1++ ; | |
495 | |
496 sprintf(str,"%d\n", Newframeshift); | |
497 for (s = str ; *s != '\n' ; ) | |
498 *p0++ = *s++; | |
499 *p0++ = *s; | |
500 while (*p1 != '\n') | |
501 *p1++; | |
502 *p1++; | |
503 | |
504 | |
505 /** copy up to framewidth **/ | |
506 | |
507 p2 = HeaderString( napheader , "framewidth" ) ; | |
508 while ( p1 < p2 ) | |
509 *p0++ = *p1++ ; | |
510 | |
511 sprintf(str,"%d\n", Newframewidth); | |
512 for (s = str ; *s != '\n' ; ) | |
513 *p0++ = *s++; | |
514 *p0++ = *s; | |
515 while (*p1 != '\n') | |
516 *p1++; | |
517 *p1++; | |
518 | |
519 | |
520 /** copy up to frameheight **/ | |
521 | |
522 p2 = HeaderString( napheader , "frameheight" ) ; | |
523 while ( p1 < p2 ) | |
524 *p0++ = *p1++ ; | |
525 | |
526 sprintf(str,"%d\n", Newframeheight); | |
527 for (s = str ; *s != '\n' ; ) | |
528 *p0++ = *s++; | |
529 *p0++ = *s; | |
530 while (*p1 != '\n') | |
531 *p1++; | |
532 *p1++; | |
533 | |
534 | |
535 /** copy up to framebytes **/ | |
536 | |
537 p2 = HeaderString( napheader , "framebytes" ) ; | |
538 while ( p1 < p2 ) | |
539 *p0++ = *p1++ ; | |
540 | |
541 sprintf(str,"%d\n", Newframebytes); | |
542 for (s = str ; *s != '\n' ; ) | |
543 *p0++ = *s++; | |
544 *p0++ = *s; | |
545 while (*p1 != '\n') | |
546 *p1++; | |
547 *p1++; | |
548 | |
549 | |
550 /** copy up to animate_ctn **/ | |
551 | |
552 p2 = HeaderString( napheader , "animate_ctn" ) ; | |
553 while ( p1 < p2 ) | |
554 *p0++ = *p1++ ; | |
555 | |
556 sprintf(str,"%s\n", anistr ); | |
557 for (s = str ; *s != '\n' ; ) | |
558 *p0++ = *s++; | |
559 *p0++ = *s; | |
560 while (*p1 != '\n') | |
561 *p1++; | |
562 *p1++; | |
563 | |
564 | |
565 /** copy up to display **/ | |
566 | |
567 p2 = HeaderString( napheader , "display" ) ; | |
568 while ( p1 < p2 ) | |
569 *p0++ = *p1++ ; | |
570 | |
571 sprintf(str,"%s\n", dispstr ); | |
572 for (s = str ; *s != '\n' ; ) | |
573 *p0++ = *s++; | |
574 *p0++ = *s; | |
575 while (*p1 != '\n') | |
576 *p1++; | |
577 *p1++; | |
578 | |
579 | |
580 /** copy rest of header **/ | |
581 | |
582 p2 = HeaderString( napheader , "Version" ) ; | |
583 while ( p1 < p2 ) | |
584 *p0++ = *p1++ ; | |
585 | |
586 if ( ( p2 = ApplicString( napheader ) ) == (char *)0 ) { | |
587 fprintf(stderr,"audim: application name not found in header\n"); | |
588 exit( 1 ) ; | |
589 } | |
590 while ( p1 < p2 ) | |
591 *p0++ = *p1++ ; | |
592 | |
593 *p0++ = 's' ; *p0++ = 'a' ; *p0++ = 'i' ; /* copy sai into applic name */ | |
594 p1 += 3 ; | |
595 | |
596 while (*p1 != '\n') | |
597 *p0++ = *p1++ ; | |
598 *p0++ = *p1++ ; | |
599 | |
600 | |
601 /** update header_bytes **/ | |
602 | |
603 sprintf(str, "%0*d", 7, p0-saiheader); | |
604 p0 = HeaderString( saiheader , "header_bytes" ) ; | |
605 s = str; | |
606 while(*p0 != '\n') | |
607 *p0++ = *s++ ; | |
608 | |
609 | |
610 return saiheader; | |
611 } | |
612 | |
613 | |
614 /************************** Autocorrelation function ***********************/ | |
615 | |
616 /* Call acf for each row in auditory image */ | |
617 | |
618 acgram( frame ) | |
619 short *frame ; | |
620 { | |
621 static float scale ; | |
622 static int normalize ; | |
623 static int first = 1 ; | |
624 register int i, j, row, col ; | |
625 short p ; | |
626 | |
627 if (first) { | |
628 normalize = ison( normstr ) ; | |
629 scale = 1./(double)( framewidth + zeroes ) * atof( sacfstr ) ; | |
630 first=0; | |
631 } | |
632 | |
633 for ( row=0 ; row < frameheight ; row++ ) { | |
634 for ( col=0 , i=row ; col < framewidth ; col++, i+=frameheight ) | |
635 buf[col] = frame[i] ; | |
636 for ( j=0 ; j<zeroes ; j++ ) /* padding */ | |
637 buf[col++] = 0 ; | |
638 | |
639 acf( buf, framewidth+zeroes ) ; | |
640 | |
641 if ( align || bandlimit ) | |
642 writelags( buf, row, (framewidth+zeroes)>>1, Newframewidth, scale ) ; | |
643 else { | |
644 if ( normalize == 0 ) | |
645 writebuf( buf, Newframewidth, scale ) ; | |
646 else | |
647 writebuf( buf, Newframewidth, 5000./buf[0] ) ; | |
648 } | |
649 } | |
650 } | |
651 | |
652 | |
653 /********************************** FFT ************************************/ | |
654 | |
655 /* Call fft and magnitude spectrum for each row in auditory image */ | |
656 | |
657 ftgram( frame ) | |
658 short *frame ; | |
659 { | |
660 static float scale ; | |
661 static int first = 1 ; | |
662 register int i, j, row, col ; | |
663 | |
664 if (first) { | |
665 scale = atof( smagstr ) ; | |
666 first=0; | |
667 } | |
668 | |
669 for ( row=0 ; row < frameheight ; row++ ) { | |
670 if ( window ) | |
671 for ( col=0 , i=row ; col < framewidth ; col++, i+=frameheight ) | |
672 buf[col] = frame[i] * W[col] ; | |
673 else | |
674 for ( col=0 , i=row ; col < framewidth ; col++, i+=frameheight ) | |
675 buf[col] = frame[i] ; | |
676 | |
677 for ( j=0 ; j<zeroes ; j++ ) /* padding */ | |
678 buf[col++] = 0 ; | |
679 | |
680 fft( buf, framewidth+zeroes, 1 ) ; | |
681 mag( buf, framewidth+zeroes ) ; | |
682 | |
683 if ( align || bandlimit ) | |
684 writebins( buf, row, (framewidth+zeroes)>>1, Newframewidth, scale ) ; | |
685 else | |
686 writebuf( buf, Newframewidth, scale ) ; | |
687 } | |
688 } | |
689 | |
690 | |
691 /********************************** Phase **********************************/ | |
692 | |
693 /* Call fft and phase spectrum for each row in auditory image */ | |
694 | |
695 phgram( frame ) | |
696 short *frame ; | |
697 { | |
698 static float scale ; | |
699 static int first = 1 ; | |
700 register int i, j, row, col ; | |
701 | |
702 if (first) { | |
703 scale = atof( sphstr ) ; | |
704 first=0; | |
705 } | |
706 | |
707 for ( row=0 ; row < frameheight ; row++ ) { | |
708 for ( col=0 , i=row ; col < framewidth ; col++, i+=frameheight ) | |
709 buf[col] = frame[i] ; | |
710 for ( j=0 ; j<zeroes ; j++ ) /* padding */ | |
711 buf[col++] = 0 ; | |
712 | |
713 fft( buf, framewidth+zeroes, 1 ) ; | |
714 phase( buf, framewidth+zeroes ) ; | |
715 | |
716 writebuf( buf, Newframewidth, scale ) ; | |
717 } | |
718 } | |
719 | |
720 | |
721 /**** Write o/p routines ****/ | |
722 | |
723 writebuf( buf, n, scale ) /* write buffer as scaled shorts */ | |
724 float *buf ; | |
725 int n ; | |
726 float scale ; | |
727 { | |
728 register int i ; | |
729 short p ; | |
730 | |
731 for (i=0 ; i < n ; i++) { | |
732 p = (short)( buf[i] * scale ) ; | |
733 fwrite( &p, sizeof(short), 1, stdout ) ; | |
734 } | |
735 } | |
736 | |
737 | |
738 | |
739 | |
740 writeframe( frame ) /* Write a nap frame in sai format */ | |
741 short *frame ; | |
742 { | |
743 int i, row, col; | |
744 | |
745 for (row=0 ; row < frameheight ; row++) | |
746 for (col=0 , i=row ; col < framewidth ; col++, i+=frameheight) | |
747 fwrite( &frame[i], sizeof(short), 1, stdout ); | |
748 } | |
749 | |
750 | |
751 /* | |
752 Write a band of spectral bins around the centre-freq of the given channel. | |
753 | |
754 The o/p spectrum is 0 to samplerate/2 Hz, resolved into spectral bins: | |
755 bins = (framewidth + zeroes) / 2 | |
756 | |
757 For the i'th channel, the centre-frequency cf = frequencies[i]. | |
758 Filters are symmetrical bandpass, so considering a bandwidth of 4 ERB | |
759 the side-frequencies at the band limits are: | |
760 | |
761 side1 = cf - 2*ERB [Hz] | |
762 side2 = cf + 2*ERB [Hz] | |
763 | |
764 Note: side1 < side2 | |
765 | |
766 Convert frequency to bin number as follows: | |
767 Let centre-frequency cf have bin number j, so that ratios: | |
768 cf/(samplerate/2) = j/bins | |
769 and so: | |
770 j = ( cf*bins ) / ( samplerate/2 ) | |
771 | |
772 (Similarly for each of the side-frequencies at the 2-ERB band limits). | |
773 | |
774 */ | |
775 | |
776 writebins( buf, chan, bins, maxwidth, scale ) | |
777 float *buf ; | |
778 int chan ; | |
779 int bins ; /* number of spectral bins */ | |
780 int maxwidth ; | |
781 float scale ; | |
782 { | |
783 double ERB, cf, side1, side2, max ; | |
784 register int i, j, s1, s2 ; | |
785 short p ; | |
786 | |
787 ERB = frequencies[chan]/9.26449 + 24.7 ; | |
788 cf = frequencies[chan] ; | |
789 side1 = frequencies[chan] - nerbs*ERB ; | |
790 side2 = frequencies[chan] + nerbs*ERB ; | |
791 | |
792 j = (int)( ( cf * bins ) / ( samplerate >> 1 ) + 0.5 ) ; /* rounding */ | |
793 s1 = (int)( ( side1 * bins ) / ( samplerate >> 1 ) + 0.5 ) ; | |
794 s2 = (int)( ( side2 * bins ) / ( samplerate >> 1 ) + 0.5 ) ; | |
795 | |
796 if ( debug ) | |
797 fprintf(stderr,"chan=%d bins=%d maxwidth=%d j=%d side1=%d side2=%d\n",chan,bins,maxwidth,j,s1,s2); | |
798 | |
799 /* Plot the given bandwidth, zeroing elsewhere: */ | |
800 | |
801 if ( bandlimit && !align ) { | |
802 | |
803 for ( i=0, p=0 ; i < s1 ; i++ ) | |
804 fwrite( &p, sizeof(short), 1, stdout ) ; | |
805 | |
806 for ( ; i < s2 && i < bins ; i++ ) { | |
807 p = (short)( buf[i] * scale ) ; | |
808 fwrite( &p, sizeof(short), 1, stdout ) ; | |
809 } | |
810 | |
811 for ( p=0 ; i < bins ; i++ ) | |
812 fwrite( &p, sizeof(short), 1, stdout ) ; | |
813 } | |
814 | |
815 /* Plot the given bandwidth, shifting it to the centre */ | |
816 | |
817 if ( align ) { | |
818 | |
819 /* align on max bin in band | |
820 max = 0 ; | |
821 for ( i=s1 ; i<s2 ; i++ ) | |
822 if ( buf[i] >= max ) { | |
823 max = buf[i] ; | |
824 j = i ; | |
825 } | |
826 for ( i=0, p=0 ; i < s1+(maxwidth/2-j) ; i++ ) | |
827 fwrite( &p, sizeof(short), 1, stdout ) ; | |
828 for ( j = s1 ; j < s2 && i < maxwidth ; i++, j++ ) { | |
829 p = (short)( buf[j] * scale ) ; | |
830 fwrite( &p, sizeof(short), 1, stdout ) ; | |
831 } | |
832 for ( p=0 ; i < maxwidth ; i++ ) | |
833 fwrite( &p, sizeof(short), 1, stdout ) ; | |
834 */ | |
835 | |
836 j = (maxwidth+s1-s2)/2 ; | |
837 for ( i=0, p=0 ; i < j ; i++ ) | |
838 fwrite( &p, sizeof(short), 1, stdout ) ; | |
839 | |
840 for ( j = s1 ; j < s2 ; i++, j++ ) { | |
841 p = (short)( buf[j] * scale ) ; | |
842 fwrite( &p, sizeof(short), 1, stdout ) ; | |
843 } | |
844 for ( p=0 ; i < maxwidth ; i++ ) | |
845 fwrite( &p, sizeof(short), 1, stdout ) ; | |
846 | |
847 } | |
848 } | |
849 | |
850 | |
851 | |
852 /* | |
853 Write a band of acf lags around the centre-period of the given channel. | |
854 | |
855 For the i'th channel, the centre-frequency | |
856 Centre-frequency cf = frequencies[i] [Hz] | |
857 Bandwidth ERB = cf/9.26449 + 24.7 [Hz] | |
858 Centre-period cp = samplerate / cf [samples] | |
859 | |
860 Filters are symmetrical bandpass, so considering a bandwidth of 4 ERB | |
861 | |
862 side1 = samplerate / ( cf - 2*ERB ) [samples] | |
863 side2 = samplerate / ( cf + 2*ERB ) [samples] | |
864 | |
865 Note: side2 < side1 since periods | |
866 | |
867 Also, successive bins ARE successive lags (in samples). | |
868 */ | |
869 | |
870 | |
871 | |
872 writelags( buf, chan, lags, maxwidth, scale ) | |
873 float *buf ; | |
874 int chan ; | |
875 int lags ; /* number of acf lags */ | |
876 int maxwidth ; | |
877 float scale ; | |
878 { | |
879 double ERB, cp, side1, side2 ; | |
880 register int i, j, s1, s2 ; | |
881 short p ; | |
882 | |
883 ERB = frequencies[chan]/9.26449 + 24.7 ; | |
884 cp = (double)samplerate / frequencies[chan] ; | |
885 side1 = (double)samplerate / ( frequencies[chan] - nerbs*ERB ) ; | |
886 side2 = (double)samplerate / ( frequencies[chan] + nerbs*ERB ) ; | |
887 | |
888 j = (int)( cp + 0.5 ) ; /* rounding */ | |
889 s1 = (int)( side1 + 0.5 ) ; | |
890 s2 = (int)( side2 + 0.5 ) ; | |
891 | |
892 if ( debug ) | |
893 fprintf(stderr,"chan=%d lags=%d side1=%d side2=%d\n",chan,lags,s1,s2); | |
894 | |
895 /* Plot the given bandwidth, zeroing elsewhere: */ | |
896 | |
897 if ( bandlimit && !align ) { | |
898 | |
899 for ( i=0, p=0 ; i < s2 ; i++ ) | |
900 fwrite( &p, sizeof(short), 1, stdout ) ; | |
901 | |
902 for ( ; i < s1 && i < lags ; i++ ) { | |
903 p = (short)( buf[i] * scale ) ; | |
904 fwrite( &p, sizeof(short), 1, stdout ) ; | |
905 } | |
906 | |
907 for ( p=0 ; i < lags ; i++ ) | |
908 fwrite( &p, sizeof(short), 1, stdout ) ; | |
909 } | |
910 | |
911 /* Plot the given bandwidth, shifting it to the centre */ | |
912 | |
913 if ( align ) { | |
914 | |
915 j = (maxwidth+s2-s1)/2 ; | |
916 for ( i=0, p=0 ; i < j ; i++ ) | |
917 fwrite( &p, sizeof(short), 1, stdout ) ; | |
918 | |
919 for ( j = s2 ; j < s1 ; i++, j++ ) { | |
920 p = (short)( buf[j] * scale ) ; | |
921 fwrite( &p, sizeof(short), 1, stdout ) ; | |
922 } | |
923 for ( p=0 ; i < maxwidth ; i++ ) | |
924 fwrite( &p, sizeof(short), 1, stdout ) ; | |
925 } | |
926 } | |
927 | |
928 | |
929 /* | |
930 Return the number of lags corresponding to a bandwidth of nerbs ERBS either | |
931 side of a given mincf. This will be the max required framewidth. | |
932 */ | |
933 | |
934 maxlagwidth( mincf, nerbs ) | |
935 double mincf ; | |
936 int nerbs ; | |
937 { | |
938 double ERB, side1, side2 ; | |
939 | |
940 ERB = mincf/9.26449 + 24.7 ; | |
941 side1 = (double)samplerate / ( mincf - nerbs*ERB ) ; | |
942 side2 = (double)samplerate / ( mincf + nerbs*ERB ) ; | |
943 | |
944 return (int)( side1 - side2 ) ; | |
945 } | |
946 | |
947 | |
948 /* | |
949 Return the number of bins corresponding to a bandwidth of nerbs ERBS either | |
950 side of a given maxcf. This will be the max required framewidth. | |
951 */ | |
952 | |
953 maxbandwidth( maxcf, nerbs, bins ) | |
954 double maxcf ; | |
955 int nerbs ; | |
956 int bins ; | |
957 { | |
958 double ERB, side1, side2 ; | |
959 int s1, s2 ; | |
960 | |
961 ERB = maxcf/9.26449 + 24.7 ; | |
962 side1 = maxcf - nerbs*ERB ; | |
963 side2 = maxcf + nerbs*ERB ; | |
964 | |
965 /* convert frequencies to bin numbers */ | |
966 | |
967 s1 = (int)( ( side1 * bins ) / ( samplerate >> 1 ) + 0.5 ) ; | |
968 s2 = (int)( ( side2 * bins ) / ( samplerate >> 1 ) + 0.5 ) ; | |
969 | |
970 return (int)( s2 - s1 ) ; | |
971 } | |
972 | |
973 |