function [mag,pts] = locatespeech(sig,N,step,fs)
% [magnitude,points] = locatespeech(signal, window, step, samplingfreq)
%
% locatespeech - returns cut magnitude and a vector of endpoints (pts) of speech signal.
%
% To find the enpoints, locatespeech does the following:
%    1) Removes any DC offset in the signal
%    2) Computes magnitude and zero-crossing rate of the signal
%    3) Computes magnitude and zero-crossing rate of noise at 1st 100 ms.
%    4) Set thresholds based on these values of noise
%    5) For start point:
%       a) Find pt. where mag consistently tops upper mag threshold
%       b) Work backwards to see where it goes below lower mag threshold
%       c) Look in the previous 25 frames of zeroxing to see if it is still
%       above the zero-xing threshold.  If so, move it back to where it
%       first drops below this threshold.
%    6) For end point, follow the same procedure as in (5) except reverse
%    everything
%
% ELEC 301 Project - "Mars Lander the Theologian", aka, "Speaker Verification"
% Sara MacAlpine, Aamir Virani, Nipul Bharani, JP Slavinsky
% WRC (OCEE) Class of 2001 - Fall '99

% 1) Remove DC offset

sig_no_dc = removedc(sig);

% 2) Compute Avg. Mag and Zero-X rate of sig

m = avgmag(sig_no_dc,N,step);
z = zeroxing(sig_no_dc,N,step);

% 3) Compute mag and zero-crossing of noise (first 100 msec of sig) - already computed,
% just cut it out of m and z above

hundredmsec_rel = round((fs*.2)/step); % # samples that equals 100ms

% Ends of these may be corrupted due to zero padding -- chop off N/step
% samples from each side

chop = ceil((N/2-step)/step); % round up for safety

noise_m = m(2+chop:hundredmsec_rel-chop);
noise_z = z(2+chop:hundredmsec_rel-chop);

% Compute means and st. deviations of each, so we can develop thresholds.

noise_m_mean = mean(noise_m);
noise_m_std  = std(noise_m);
noise_z_mean = mean(noise_z);
noise_z_std  = std(noise_z);

% Set lower thresholds

fudge = 5;
ITL = noise_m_mean + fudge*noise_m_std;
IZCT = noise_z_mean + fudge*noise_z_std;

% Define upper threshold for avg mag.

ITU = 3.2*noise_m_mean; % since std << mean, twice the mean should cover it

% find place where sig consistently tops ITU.

start = 3;        % since window goes back two spots, start at 3rd sample
avg_last3pts = 0; % ITU won't be topped in the  first 3 pts, so initialize to 0

while avg_last3pts < ITU,
  start = start + 1;
  avg_last3pts = (m(start) + m(start-1) + m(start-2))/3; 
end

% move backwards to find where we first go under ITL

while m(start) > ITL,
  start = start - 1;
end

% See if need to move start back due to zero-crossing

below_izct_count = 0;
first_below = -999;

if start > 25
  for i = start:-1:start-25,
    if z(i) < IZCT
      below_izct_count = below_izct_count + 1;
      if first_below == -999
	first_below = i;
      end
    end
  end
  if below_izct_count >= 3
    start = first_below;
  end
end

% Now do the same process backwards for the end;

endpt = length(m)-2;
avg_last3pts = 0; % threshhold won't occur in first 3 pts, so initialize to 0

while avg_last3pts < ITU,
  endpt = endpt - 1;
  avg_last3pts = (m(endpt) + m(endpt+1) + m(endpt+2))/3; 
end

% move forwards to find where we first go under ITL

while m(start) > ITL,
  endpt = endpt + 1;
end

% See if need to move start back due to zero-crossing
below_izct_count = 0;
first_below = -999;

if (endpt-length(z)) > 25
  for i = endpt:1:endpt+25,
    if z(i) < IZCT
      below_izct_count = below_izct_count + 1;
      if first_below == -999
	first_below = i;
      end
    end
  end
  if below_izct_count >= 3
    endpt = first_below;
  end
end

% Return values (multiply endpoints by step so that it is scaled
% appropriately for the actual signal

mag = m(start:endpt);
pts = [start*step endpt*step];
