% usage: [Timefreq [, f [, t]]] = specgram(x [, n [, Fs [, window [, overlap]]]])
% Original version by Paul Kienzle; modified by Sean Fulop March 2002
% Generate a spectrogram for the signal. This chops the signal into
% overlapping slices, windows each slice and applies a Fourier
% transform to determine the frequency components at that slice.
%
% x: vector of samples
% n: size of fourier transform window, or [] for default=256
% Fs: sample rate, or [] for default=2 Hz
% window: shape of the fourier transform window, or [] for default=hanning(n)
%    Note: window length can be specified instead, in which case
%    window=hanning(length)
% overlap: overlap with previous window, or [] for default=length(window)/2
% Example
%    x = chirp([0:0.001:2],0,2,500);  # freq. sweep from 0-500 over 2 sec.
%    Fs=1000;                  # sampled every 0.001 sec so rate is 1 kHz
%    step=ceil(20*Fs/1000);    # one spectral slice every 20 ms
%    window=ceil(100*Fs/1000); # 100 ms data window
%    specgram(x, 2^nextpow2(window), Fs, window, window-step);
%
function [Timefreq, f_r, t_r] = myspecgram(x, n, Fs, window, overlap)
  if nargin < 1 | nargin > 5
    error('usage: ([Y [, f [, t]]] = specgram(x [, n [, Fs [, window [, overlap]]]]) ')
  end
  % assign defaults
  if nargin < 2 | isempty(n), n = min(256, length(x)); end
  if nargin < 3 | isempty(Fs), Fs = 2; end
  if nargin < 4 | isempty(window), window = hanning(n); end
  if nargin < 5 | isempty(overlap), overlap = length(window)/2; end
  % if only the window length is given, generate hanning window
  if length(window) == 1, window = hanning(window); end
  % should be extended to accept a vector of frequencies at which to
  % evaluate the fourier transform (via filterbank or chirp
  % z-transform)
  if length(n)>1, 
    error('specgram doesn''t handle frequency vectors yet') 
end
  % compute window offsets
  win_size = length(window);
  if (win_size > n)
    n = win_size;
    warning('specgram fft size adjusted---must be at least as long as frame')
end
  step = win_size - overlap;
  % build matrix of windowed data slices
  offset = [ 1 : step : length(x)-win_size ];
  S = zeros (n, length(offset));
  for i=1:length(offset)
    S(1:win_size, i) = x(offset(i):offset(i)+win_size-1) .* window;
end
  % compute fourier transform
  STFT = fft(S);
  
     
  % extract the positive frequency components
  if rem(n,2)==1
    ret_n = (n+1)/2;
  else
    ret_n = n/2;
end
  inst = input('Do you want to see a spectrogram of this STFT (y/n)?', 's');
  if strcmp(inst,'n') | strcmp(inst,'no')
      f = [0:ret_n-1]*Fs/n; t = offset/Fs;
    if nargout>0, Timefreq = STFT; end
    if nargout>1, f_r = f; end
    if nargout>2, t_r = t; end
 
      return
   
else 
     if nargout>0, Timefreq = STFT; end
 
  STFT = STFT(1:ret_n, :);
  f = [0:ret_n-1]*Fs/n;
  t = offset/Fs;
  
  if nargout>1, f_r = f; end
  if nargout>2, t_r = t; end
  maxfreq = input('Please enter the maximum frequency (Hz)\n you wish to see on the display:');
  STFTmag = abs(STFT(2:n*maxfreq/Fs,:)); % magnitude of STFT
STFTmag = STFTmag/max(max(STFTmag)); % normalize so max magnitude will be 0 db
STFTmag = max(STFTmag, 10^(-35/10)); % clip everything below -35 dB
% imagesc(t, f(2:n*maxfreq/Fs), 20*log10(STFTmag)); axis xy; colormap(flipud(gray));
% display as an indexed grayscale image showing the log magnitude of the STFT, 
% i.e. a spectrogram; the colormap is flipped to invert the default setting,
% in which white is most intense and black least---in speech science we want
% the opposite of that.
pcolor(t, f(2:n*maxfreq/Fs), 20*log10(STFTmag));
axis xy;
colormap(flipud(gray));
shading interp;
end 
inst = input('How about a snazzy 3-D color spectrogram (y/n)','s');
if strcmp(inst,'no') | strcmp(inst, 'n')
    return
else figure;
surf(t, f(2:n*maxfreq/Fs), 20*log10(STFTmag));
axis xy; view(20,84);
colormap(jet);
shading interp;
end 
