Mercurial > hg > aim92
comparison tools/acf.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 Autocorrelation function using FFT routines adapted from routines given in | |
3 Numerical Recipes. | |
4 The routine acf() uses an fft to compute the array of lagged products | |
5 which is the autocovariance function. An optional normalization (dividing | |
6 each coefficient by the zeroth coefficient) produces the autocorrelation | |
7 function, (and this is then scaled up to the range [0-1000]). | |
8 | |
9 The output framewidth is the given maximum acf lag, which must not be | |
10 greater than the input framewidth. | |
11 | |
12 Padding with zeroes is recommended to counter end-effects (See NR, p416). | |
13 It is also necessary since: | |
14 1) framesize + padding must be a power of two (sample points at given rate). | |
15 2) max possible acf lag = ( framesize + padding ) / 2 | |
16 | |
17 Each input frame is padded with zeroes so that it is at least twice the | |
18 required max acf lag, and is also a power of 2. | |
19 This is because the fft method is "radix-2", and because the output acf is | |
20 symmetrical so that just half the points are unique. | |
21 Therefore each input frame is padded with zeroes to the next power of 2 | |
22 larger than either the input framewidth, or twice the required max acf lag, | |
23 (whichever is the larger). | |
24 | |
25 If necessary, extra padding can be enforced using the padding option to | |
26 add extra zeroes, padding to a larger power of 2. | |
27 The amount of extra padding is "exponential", expanding the basic size to: | |
28 ( framesize + padding ) * 2**n | |
29 where the padding option is n. | |
30 (n=0 by default, so that no extra padding is added. When n=1 then padding is | |
31 added to double the size, and when n=2 the size is quadrupled, etc.). | |
32 | |
33 Frames are selected from the input stream using the "frames" option, | |
34 which has syntax: [[-]frame=a[-b]]. Input frames are numbered 1,2,... | |
35 For example: | |
36 frame=a Select just the a'th frame. | |
37 frame=a-b Select frames from the a'th to b'th inclusive. | |
38 The strings "min" and "max" can be used as specifiers, meaning eg: | |
39 frame=min Select the first frame. | |
40 frame=max Select the last frame. | |
41 frame=a-max Select frames from the a'th to the last inclusive. | |
42 frame=min-b Select frames from the first to the b'th inclusive. | |
43 The default selects all frames, (ie frame=min-max). | |
44 | |
45 Other options (set using <option>=on): | |
46 size Print the input and output frame sizes in sample points. | |
47 echo Echo buffered input without processing. | |
48 negative Write negative half of acf (ie. with zeroth lag on right). | |
49 | |
50 | |
51 Examples: | |
52 | |
53 1. To print the input and output frame sizes in sample points, eg for a | |
54 subsequent plotting program, use the size option: | |
55 | |
56 acf ... size=on | |
57 | |
58 2. An acf of a waveform sampled at 10kHz, computed to a max lag of 12.8ms | |
59 within a frame of 12.8ms, plotting the 2nd frame in a sequence of frames | |
60 with frameshift 12.8ms. | |
61 | |
62 acf samp=10kHz width=12.8ms frstep=12.8ms frame=2 lag=12.8ms file | x11plot | |
63 | |
64 3. An animated plot of successive acf's of a waveform sampled at 10kHz, | |
65 each computed within a frame of 12.8ms, and shifted by 2 sample points. | |
66 | |
67 acf samp=10kHz width=12.8ms frstep=2p lag=12.8ms file | x11play -n128 | |
68 | |
69 */ | |
70 | |
71 #include <stdio.h> | |
72 #include <math.h> | |
73 #include "options.h" | |
74 #include "units.h" | |
75 #include "strmatch.h" | |
76 #include "sigproc.h" | |
77 | |
78 char applic[] = "autocorrelation function of contiguous frames.\n i/p and o/p data in binary shorts." ; | |
79 | |
80 static char *helpstr, *debugstr, *sampstr, *startstr, *shiftstr, *widthstr, *sizestr ; | |
81 static char *padstr, *wstr, *lagstr, *scalestr, *normstr, *framestr, *echostr, *negstr ; | |
82 | |
83 static Options option[] = { | |
84 { "help" , "off" , &helpstr , "help" , DEBUG }, | |
85 { "debug" , "off" , &debugstr , "debugging switch" , DEBUG }, | |
86 { "samplerate", "20kHz" , &sampstr , "samplerate " , VAL }, | |
87 { "start" , "0" , &startstr , "Start point in i/p file." , VAL }, | |
88 { "frames" , "1-max" , &framestr , "Select frames inclusively" , VAL }, | |
89 { "frstep" , "16ms" , &shiftstr , "Step between input frames." , VAL }, | |
90 { "width" , "32ms" , &widthstr , "Width of input frames." , VAL }, | |
91 { "lag" , "32ms" , &lagstr , "Maximum acf lag (output frame width)." , VAL }, | |
92 { "padding" , "0" , &padstr , "Exponential frame padding" , SVAL }, | |
93 { "window" , "on" , &wstr , "Hamming window" , SETFLAG }, | |
94 { "normalize" , "off" , &normstr , "normalized acf" , SETFLAG }, | |
95 { "scale" , "0.025" , &scalestr , "scale output" , SVAL }, | |
96 { "size" , "off" , &sizestr , "print input/output frame size in samples" , SETFLAG }, | |
97 { "echo" , "off" , &echostr , "echo buffered input without processing", SVAL }, | |
98 { "negative" , "off" , &negstr , "write negative half of acf (zeroth lag on right)", SVAL }, | |
99 ( char * ) 0 } ; | |
100 | |
101 | |
102 int samplerate ; | |
103 int width ; | |
104 int step ; | |
105 int zeroes ; | |
106 int maxlag ; | |
107 int dowindow ; | |
108 double scale ; | |
109 int normalize ; | |
110 int echo ; | |
111 int negative ; | |
112 | |
113 float *vec, *window ; | |
114 short *obuf ; | |
115 | |
116 main (argc, argv) | |
117 int argc; | |
118 char **argv; | |
119 { | |
120 FILE *fp ; | |
121 short *buf ; | |
122 int a, b ; | |
123 | |
124 fp = openopts( option,argc,argv ) ; | |
125 if ( !isoff( helpstr ) ) | |
126 helpopts( helpstr, argv[0], applic, option ) ; | |
127 | |
128 samplerate = to_Hz( sampstr ) ; | |
129 dowindow = ison( wstr ) ; | |
130 normalize = ison( normstr ) ; | |
131 echo = ison( echostr ) ; | |
132 negative = ison( negstr ) ; | |
133 | |
134 width = to_p( widthstr, samplerate ) ; | |
135 step = to_p( shiftstr, samplerate ) ; | |
136 maxlag = to_p( lagstr , samplerate ) ; | |
137 | |
138 if ( ( maxlag << 1 ) < width ) | |
139 zeroes = ( getpower( width ) << atoi( padstr ) ) - width ; | |
140 else if ( maxlag <= width ) | |
141 zeroes = ( getpower( maxlag << 1 ) << atoi( padstr ) ) - width ; | |
142 else { | |
143 fprintf(stderr,"acf: required max lag [%dms] greater than framewidth [%dms]\n", maxlag*1000/samplerate, width*1000/samplerate); | |
144 exit( 1 ) ; | |
145 } | |
146 | |
147 scale = ( 1./(double)(width+zeroes) ) * atof( scalestr ) ; | |
148 | |
149 /* frame size printout */ | |
150 | |
151 if ( ison( sizestr ) ) { | |
152 fprintf(stderr,"acf sizes in sample points:\n" ) ; | |
153 fprintf(stderr," input frame size = %d (framewidth=%d + padding=%d)\n", width+zeroes, width, zeroes ) ; | |
154 fprintf(stderr," output frame size = %d \n", maxlag ) ; | |
155 exit( 0 ) ; | |
156 } | |
157 | |
158 /* parse bounds on number of frames */ | |
159 | |
160 if ( selector( framestr, &a, &b ) == 0 ) { | |
161 fprintf(stderr,"acf: bad frame selector [%s]\n", framestr ) ; | |
162 exit( 1 ) ; | |
163 } | |
164 | |
165 /* Allocate working space */ | |
166 | |
167 obuf = (short *)malloc( maxlag * sizeof(short) ) ; | |
168 vec = (float *)malloc( width+zeroes * sizeof(float) ) ; | |
169 if ( dowindow ) | |
170 window = hamming( width ) ; | |
171 | |
172 /* Compute acf for each frame of width shorts in the input stream */ | |
173 | |
174 if ( seekbytes( fp, (int)( to_p( startstr, samplerate ) * sizeof(short) ) ) == 0 ) { | |
175 fprintf(stderr,"improper seek\n") ; | |
176 exit( 1 ) ; | |
177 } | |
178 | |
179 while ( ( buf = getframe( fp, a, width, step ) ) != (short *)0 && ( a<=b || b==0 ) ) { | |
180 if ( echo ) fwrite( buf, sizeof(short), width, stdout ) ; | |
181 else process( buf ) ; | |
182 a++ ; | |
183 } | |
184 if ( a<=b && b>0 ) | |
185 fprintf(stderr,"warning: not enough frames for request\n"); | |
186 | |
187 fclose( fp ) ; | |
188 } | |
189 | |
190 | |
191 process( buf ) | |
192 short *buf ; | |
193 { | |
194 short *bptr = buf ; | |
195 short *endptr = buf + width ; | |
196 short *optr = obuf ; | |
197 short *endlag = obuf + maxlag ; | |
198 float *wptr = window ; | |
199 float *vptr = vec ; | |
200 float *endvec = vec + width + zeroes ; | |
201 | |
202 if ( dowindow ) | |
203 while ( bptr < endptr ) | |
204 *vptr++ = *bptr++ * *wptr++ ; | |
205 else | |
206 while ( bptr < endptr ) | |
207 *vptr++ = *bptr++ ; | |
208 | |
209 while ( vptr < endvec ) /* padding */ | |
210 *vptr++ = 0 ; | |
211 | |
212 acf( vec, width+zeroes ) ; | |
213 | |
214 if ( normalize ) | |
215 scale = 1000. / *vec ; | |
216 | |
217 vptr = vec ; | |
218 while ( optr < endlag ) | |
219 *optr++ = (short)( scale * *vptr++ ) ; | |
220 | |
221 if ( !negative ) | |
222 fwrite( obuf, sizeof(short), maxlag, stdout ) ; | |
223 else { | |
224 for ( optr = endlag-1 ; optr >= obuf ; optr-- ) /* write in reverse */ | |
225 fwrite( optr, sizeof(short), 1, stdout ) ; | |
226 } | |
227 } | |
228 | |
229 |