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