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