1%% delay tracking
 2%  XSF = delaytracking(x, xPrev, fs, spos, mpos, c, iw)
 3% INPUT
 4% * |x|-each column response a mic track
 5% * |xPrev|-data from a previous window. This data allows for real data to be padded
 6%   at the front of each shifted track .Simply zeros if no previous data      
 7% * |fs|- sampling rate (Hertz)
 8% * |spos| - 3x1 source location point (col vector) (meters)
 9% * |mpos| - column matrix of mic positions (meters)
10% * |c| - speed of sound (meters/sec)
11% * |iw| -(optional) if set to 1, the dsb will apply an inverse distance 
12%         weighting on the microphones, useful for near-field/immersive
13%         applications.  Any other value or its absense will result in
14%         the uniform weight dbs.
15%OUTPUT
16% * |y| - delay tracking
17
18
19%% Function Declaration
20function XSF = delaytracking(x, xPrev, fs, spos, mpos, c, iw)
21
22%% Argument Error Checking
23if nargin == 6 %Set flag to no weighting
24    iw = 0;  
25end
26if isempty(x)||~isreal(x)||~all(all(isfinite(x)))
27    error('x must be a real matrix')
28elseif isempty(xPrev)||~isreal(xPrev)||~all(all(isfinite(xPrev)))
29    error('xPrev must be a real matrix')
30elseif isempty(fs)||~isreal(fs)||~isscalar(fs)||~isfinite(fs)||fs <= 0 
31    error('fs must be positive real scalar');
32elseif isempty(spos)||~isreal(spos)||~all(isfinite(spos))||size(spos,1)~= 3 ...
33        ||size(spos,2)~= 1||length(size(spos))~= 2
34    error('spos must be a real 3x1 vector');
35elseif ~isreal(mpos) || ~all(all(isfinite(mpos))) || size(mpos,1) ~= 3
36    error('mpos must be a real matrix with 3 rows')
37elseif isempty(c) || ~isreal(c) || ~isscalar(c) || ~isfinite(c) || ...
38        c <= 0
39    error('c must be positive real scalar');
40end
41
42%% Setup
43% Initialize vars and get some information about the target audio
44N = size(x,1); % total number of samples in each audio track
45M = size(x,2); % number of microphones in the array
46xShift = zeros(N, M);  % initialize shifted track matrix
47
48%% Beamform
49% delaying each microphone track to bring the target signal into alignment
50% then sum all tracks together.
51
52% d_i = \sqrt{(mpos{i,x}\ ^\_\ s_x)^2+(mpos_{i,y}\ ^\_\ s_y)^2+
53% (mpos{i,z}\ ^\_\ s_z)^2} \quad i \in [1, M] 
54
55%  \tau_i = f_s\left(\frac{d_{max}\ ^\_\ d_i}{c}\right) 
56
57
58% Find the distances of each mic to the source
59% spos*ones: expend one spos to every mpos so as to subtract
60dist = sqrt(sum((mpos-spos*ones(1,size(mpos,2))).^2, 1));
61
62if any(dist==0)
63    error('Cant have a source on top of a mic') 
64end
65if iw == 1
66    wghts = arweights(dist);  % inverse distance weighting
67else
68    wghts = ones(size(dist));  % no weighting
69end
70
71% Divide distances by the speed of sound to find duration of travel
72% for each signal.  Take that time relative to the furthest mic,
73% since all other tracks will be delayed to match the wave that
74% took the longest to be recieved.
75t = (max(dist)-dist)/c;
76
77% Convert TDOA to integer delays
78delays = round(t*fs);
79
80% Shift each track.we're recycling x into xPrev on the next iteration
81% take delay amount from xPrev to new xShift windows 
82
83for k=1:size(x,2)
84    xShift(:,k) = wghts(k)*[xPrev(end-delays(k)+1:end, k);... 
85        x(1:end-delays(k), k)];
86end
87
88% output
89XSF=xShift;
90
91end  % function dsb