A single source moving clockwise at a constant speed makes a full rotation in 2 seconds. Synthesize 4 seconds of the signal received by each ear using the overlap-add convolution method.
The signal to be processed is a generated Gaussian noise signal, and is divided into chunks before convolving it with the HRTF data, measured at every 5 degrees. Then, the chunks of convolved signal are added to each other, the 'tail end' of the previous convolved signal overlapping with the 'front end' of the next convolved signal. This is a method of interpolation to prevent or reduce the choppy beating effect that would occur if each convolved signal were simply appended to the end of the last one.
The HRTF data provided only gives the calculations for one half of a rotation, going around the right ear from 0 degrees (front of head), to 180 degrees (back of head). If the left and right channels are reversed, it seems as if the sound were travelling around the left ear from 0/360 degrees (front of head) to 180 degrees (back of head). Next, if the channel-swapped signal is played in reverse, then the sound will appear to travel around the left ear, from 180 degrees (back of head) to 0/360 degrees (front of head). Thus, to create a full rotation, the signal will consist of the original half rotation, plus a channel-swapped, reversed signal appended to the end.
function [signal_full] = project_02_part01a(fs, rotation_time, rotations, number_of_measurements) %comment out fs, rotation_time, rotations, and number_of_measurements to specify values from command line fs = 44100; %sampling rate rotation_time = 2; %time it takes in seconds for a full rotation secs = rotation_time/2; %time it takes for half a rotation (from 0 to 180 degrees) rotations = 2; %number of rotations to perform (use whole numbers only!) elev = 0; %elevation angle remains 0 for this simulation azim = 0; %azimuth angle of 0 = directly in front of observer; positive degrees rotate clockwise number_of_measurements = 37; %37 HRTF measurements are provided, from 0 to 180 degrees, in 5 degree increments total_samples = fs*secs; chunk_size = floor(total_samples/number_of_measurements); %number of samples to split each noise chunk into leftover_samples = total_samples - chunk_size*number_of_measurements; %number of samples left over after rounding chunk_size noise = randn(1,fs*secs); i = 0; N_start = 1; %a convolved signal has a length of length(N)+length(M)-1: %with overlap-add, the length of the final signal will be the length of the %entire noise signal (total_samples), plus the length of M (128), minus 1 signal0to180 = zeros(2,total_samples+128-1); while i < number_of_measurements N = noise(N_start:N_start+chunk_size-1); %appends leftover samples to last N chunk if (leftover_samples > 0) && (i == number_of_measurements-1) N = noise(N_start:N_start+chunk_size-1 + leftover_samples); %leftovers_plus_N_length = length(N); end M = readhrtf(elev,azim,'H'); M_left = M(1,:); M_right = M(2,:); %convolve noise and HRTF data signal0to180_left = conv(N,M_left); signal0to180_right = conv(N,M_right); %overlap-add signal0to180(1,N_start:N_start+length(N)+length(M)-2) = signal0to180(1,N_start:N_start+length(N)+length(M)-2) + signal0to180_left; signal0to180(2,N_start:N_start+length(N)+length(M)-2) = signal0to180(2,N_start:N_start+length(N)+length(M)-2) + signal0to180_right; %increment variables N_start = N_start + chunk_size; azim = azim + 5; i = i + 1; end signal_full = zeros(2*rotations*length(signal0to180),2); %copy signal0to180 (first half rotation) to signal_full signal_full(1:length(signal0to180),1) = signal0to180(1,:); signal_full(1:length(signal0to180),2) = signal0to180(2,:); %create 2nd half rotation of signal_full %swapping the channels causes the sound to move from 0 back to 180 degrees CCW %fliplr (reverse matrix order) then causes the sound to move from 180 to 360 degrees CW as intended signal_full(length(signal0to180)+1:2*length(signal0to180),1) = fliplr(signal0to180(2,:)); signal_full(length(signal0to180)+1:2*length(signal0to180),2) = fliplr(signal0to180(1,:)); %copies full rotation as many times as needed for i = 2:rotations signal_full((i*2-2)*length(signal0to180)+1:(i*2)*length(signal0to180),1) = signal_full(1:2*length(signal0to180),1); signal_full((i*2-2)*length(signal0to180)+1:(i*2)*length(signal0to180),2) = signal_full(1:2*length(signal0to180),2); end subplot(211), plot(signal_full(:,1),'Color',[1,0.12,0.12]), grid on, axis tight; title('Left channel'), xlabel('time (samples)'), ylabel('amplitude'); subplot(212), plot(signal_full(:,2),'g'), grid on, axis tight; title('Right channel'), xlabel('time (samples)'), ylabel('amplitude'); %double max(max()) needed, because max() on a matrix returns a row vector signal_full = signal_full/max(max(abs(signal_full))); %normalizes input %print project_02_part01a -dpng -r100; %wavwrite(signal_full,fs,'project_02_part01a'); soundsc(signal_full,fs); |