Explanation of the program
First the input file is read into the array x_in. Then, memory is allocated for a floating-point version of x_in, x_in_f , and for an f0 array of the same length as x_in . After the array ans and the first 512 samples of f0 are zeroed, the heart of the program is the following loop:
for (i=0;i<(*length)-512;i++) { data = x_in_f+i-1; correl(data,data,512,ans); maxlag = SR/MAXF0; max = 0; for (j=top;j<=bot;j++) { if (ans[j] > max) { maxlag = j; max = ans[j]; } } f0[i+512] = SR/maxlag; /* i+512 to offset lag introduced by windowing */ if (f0[i+512] >= MAXF0) f0[i+512]=0; } |
The counter variable i counts through the samples of the input from 0, the beginning, to *length–512, i.e. 512 samples from the end (so that the autocorrelation calculations near the end of the signal never try to access samples beyond the end of the signal).
Exercise 5.1. If you change the first line of this loop to “for (i=0;i<(*length)-512;i+=80) ”, the autocorrelation will only be calculated every 80 samples, making the program run much faster. If you do this, use a smaller array for f0, and instead of writing f0 to a signal file, write out the values of f0 as text output. (See the end of cepstral_f0.c for an example.) |
Instead of copying samples from x_in to data for the correl function to work on, we only have to tell correl where it can find its data. We use the pointer variable data to refer to the beginning of each 512-sample portion of x_in that we want correl to work on. The expression “data = x_in_f+i-1; ” can be read as “the data is to be found at the i’th sample of x_in_f”. (The –1 is because correl expects the first sample to be at data[1], not data[0], whereas x_in_f begins at sample 0.)
Next the program calls the function correl, and then inspects ans to find the lag at which the autocorrelation is greatest (within the f0 range of interest). Bearing in mind that small lags correspond to high frequencies and large lags correspond to low frequencies, we inspect the array cells ans[j] from j = top (e.g. 88 samples) to bot (e.g. 200 samples). Thus, rather than looking through all of ans to find the maximum autocorrelation, we restrict the search to the range from ans[88] to ans[200]. To find the autocorrelation peak within that range, we use the variable max to store “the highest magnitude of the autocorrelation found so far”. We set it to 0 initially, and then use a loop that counts j from top to bot :
max = 0; for (j=top;j<=bot;j++) { if (ans[j] > max) { maxlag = j; max = ans[j]; } } |
When the end of this loop is reached, maxlag will be set to the lag at which the autocorrelation is greatest. SR/maxlag gives the corresponding f0, which we write to f0[i+512] . (The offset of 512 is to keep samples of f0 in step with samples of x_in.) Any f0 values found to be at the upper limit of the range are assumed to be out of range, i.e. probably unvoiced, and are set to zero.
When compiling the program, don’t forget to compile and link correl.c and nrutil.c too. For example:
gcc -c autocorr_f0.c
gcc -c nrutil.c
gcc -c correl.c
gcc -o autocorr_f0.exe nrutil.o correl.o autocorr_f0.o
Next: Linear Prediction