function wavspect(action)
%WAVSPECT Demonstration of various aspects of spectra
% as a function of time-domain window placement and size.

% Martin Cooke, April 1998
% Updated for V2.1
%   mpc 14/6/99 Bergen

if nargin < 1
  action='init';
end

switch action
case 'init'
  
  f=findobj('Tag','wavspect_fig');
  if ~isempty(f)
    figure(f);
  else     
    wavspect_gui;
    ud.spectRecalc=get(findobj('Tag','spectRecalcCheck'),'Value');
    ud.linkCursors=get(findobj('Tag','linkCursorsCheck'),'Value');
    ud.useHamming=get(findobj('Tag','useHammingCheck'),'Value'); 
    ud.fs=22050;
    set(findobj(gcf,'Style','checkbox'),'Enable','off');
    set(findobj(gcf,'Style','pushbutton'),'Enable','off');
    set(gcf,'UserData',ud,'Name','wavspect - [no data loaded]');
  end

case 'create'
  [sig,fs,name]=createsig;
  if length(sig)
    ud=get(gcf,'UserData');
    ud.sig=sig; ud.name=name; ud.fs=fs; % ud.fs=fs/1000;
    set(gcf,'UserData',ud);
    wavspect 'newsig'
  end
  
case 'load'
  ud=get(gcf,'UserData');
  [name,sig,fs]=loadsig(fullfile(madroot,'data','sounds'));
  if length(sig) 
    ud.sig=sig; ud.name=name; ud.fs=fs; % ud.fs=fs/1000;
    set(gcf,'UserData',ud);
    wavspect 'newsig'
  end

case 'newsig'
  ud=get(gcf,'UserData');
  ud.sig = normalise(ud.sig);
  ud.sig=ud.sig(:)';
  ud.samps=length(ud.sig);
  ud.winleft=1;
    set(findobj(gcf,'Style','checkbox'),'Enable','on');
    set(findobj(gcf,'Style','pushbutton'),'Enable','on');
     ud.winright=ud.samps;
    set(ud.wavAxes,'NextPlot','replacechildren','Drawmode','fast','XLim',[1 length(ud.sig)]);
    axes(ud.wavAxes);
    plot(ud.sig);
    hold on;  
    ud.left=round(0.1*length(ud.sig));
    ud.right=round(0.9*length(ud.sig));   
    ud.l=line([ud.left ud.left],get(gca,'YLim'),'Color','r','ButtonDownFcn','wavspect left','EraseMode','xor');
    ud.r=line([ud.right ud.right],get(gca,'YLim'),'Color','r','ButtonDownFcn','wavspect right','EraseMode','xor');

    ud.freqs=1:10:(ud.fs/2);   % 10 Hz spacing 
    spect=performFFT(ud.sig(ud.left:ud.right),ud.freqs,ud.fs);    
    axes(ud.spectAxes);
    if isfield(ud,'p')
      delete(ud.p)
    end
    ud.p=plot(ud.freqs,spect);
    set(ud.p,'EraseMode','background','LineWidth',2);  % now display it in signal window
    set(ud.spectAxes,'Drawmode','fast','XLim',[1 ud.fs/2],'YLim',[-40 60],...
        'XTick',0:1000:(ud.fs/2),'YTick',-40:10:60);  
    xlabel('frequency (kHz)');
    ylabel('log magnitude (dB)');
    set(gcf,'UserData',ud,'Name',['wavspect - ' ud.name]);
    wavspect 'plotSpect'

  
case 'linkCursors'
  ud=get(gcf,'UserData');
  ud.linkCursors=get(findobj('Tag','linkCursorsCheck'),'Value');
  if ud.linkCursors
    ud.gap=ud.right-ud.left+1;
  end
  set(gcf,'UserData',ud);
  
case 'spectRecalc'
  ud=get(gcf,'UserData');
  ud.spectRecalc=get(findobj('Tag','spectRecalcCheck'),'Value');
  set(gcf,'UserData',ud);
    if ud.spectRecalc
      set(ud.p,'Color',[0 0 1]);
      wavspect 'plotSpect'
    else
      set(ud.p,'Color',[0.8 0.8 1.0]);
    end  


case 'useHamming'
  ud=get(gcf,'UserData');
  ud.useHamming=get(findobj('Tag','useHammingCheck'),'Value'); 
  set(gcf,'UserData',ud);
    if ud.spectRecalc
      wavspect 'plotSpect'
    end  

case 'unzoom'
  ud=get(gcf,'UserData');
  mid=round((ud.winright-ud.winleft)/2);
  ud.winleft=max(1,ud.winleft-mid);
  ud.winright=min(ud.samps,ud.winright+mid); 	 
  set(ud.wavAxes,'XLim',[ud.winleft ud.winright]);
  %set(ud.l,'XData',[ud.left ud.left]);
  %set(ud.r,'XData',[ud.right ud.right]); 
  set(gcf,'UserData',ud);
  
case 'showall'
  ud=get(gcf,'UserData');
  ud.winleft=1;
  ud.winright=ud.samps; 	 
  set(ud.wavAxes,'XLim',[ud.winleft ud.winright]);
  set(gcf,'UserData',ud);
  
  
case 'zoomToCursors' 
  ud=get(gcf,'UserData'); 
  if ud.linkCursors
    ud.winleft=max(1,round(ud.left-0.1*(ud.right-ud.left)));
    ud.winright = min(ud.samps,round(ud.right+0.1*(ud.right-ud.left)));
    set(ud.wavAxes,'XLim',[ud.winleft ud.winright]);
    set(gcf,'UserData',ud);
  else	 
    ud.winleft = ud.left;
    ud.winright = ud.right;
    ud.left = round(ud.winleft+0.1*(ud.winright-ud.winleft));
    ud.right = round(ud.winright-0.1*(ud.winright-ud.winleft));
    set(ud.wavAxes,'XLim',[ud.winleft ud.winright]);
    set(ud.l,'XData',[ud.left ud.left]);
    set(ud.r,'XData',[ud.right ud.right]);   
    set(gcf,'UserData',ud);
    if ud.spectRecalc
      wavspect 'plotSpect'
    end  
  end 

case 'zoom'
  ud=get(gcf,'UserData');
  if ud.right > ud.left+5
    
    cmid=round((ud.left+ud.right)/2);
    if ud.linkCursors
      ud.winleft = min(ud.left-5,round((ud.winleft+cmid)/2));
      ud.winright = max(ud.right+5,round((ud.winright+cmid)/2));
      set(ud.wavAxes,'XLim',[ud.winleft ud.winright]);
      set(gcf,'UserData',ud);
    else
      ud.winleft = round((ud.winleft+cmid)/2);
      ud.winright = round((ud.winright+cmid)/2);
      set(ud.wavAxes,'XLim',[ud.winleft ud.winright]);
      redo=0;
      if ud.left < ud.winleft+5
        ud.left = ud.winleft+5;
        set(ud.l,'XData',[ud.left ud.left]);
        redo=1;
      end
      if ud.right > ud.winright-5
        ud.right = ud.winright-5;
        set(ud.r,'XData',[ud.right ud.right]);
        redo=1;
      end
      set(gcf,'UserData',ud);
      if and(redo,ud.spectRecalc)
      wavspect 'plotSpect'
    end  
	 
    end	
  end 

case 'left'
  set(gcf,'WindowButtonMotionFcn','wavspect moveleft');
  set(gcf,'WindowButtonUpFcn','wavspect release');
  
case 'right'
  set(gcf,'WindowButtonMotionFcn','wavspect moveright');
  set(gcf,'WindowButtonUpFcn','wavspect release');
  
case 'moveleft'
  ud=get(gcf,'UserData');
  currentPoint=get(gca,'CurrentPoint');
  ud.left=min(ud.right-1,max(1,ceil(currentPoint(1))));
  if ud.linkCursors
    step=50;
  else	
    step=round(0.2*(ud.winright-ud.winleft));
  end	 
  if ud.left <= ud.winleft
    ud.winleft=max(1,ud.winleft-step);
    if ud.winleft > 1
      ud.winright=ud.winright-step;
    end	  
    set(ud.wavAxes,'XLim',[ud.winleft ud.winright]);
  end
  if ud.linkCursors
    ud.right = ud.left + ud.gap;
    if ud.right >= ud.samps
      ud.right=ud.samps;
      ud.left=ud.samps-ud.gap;
    end
  end	  
  if ud.right >= ud.winright
    ud.winright=min(ud.samps,ud.winright+step);
    if ud.winright < ud.samps
      ud.winleft=ud.winleft+step;
    end	  
    set(ud.wavAxes,'XLim',[ud.winleft ud.winright]);
  end    

  set(ud.l,'XData',[ud.left ud.left]);
  set(ud.r,'XData',[ud.right ud.right]);
  set(gcf,'UserData',ud);
    if ud.spectRecalc
      wavspect 'plotSpect'
    end  

case 'moveright'
  ud=get(gcf,'UserData');
  currentPoint=get(gca,'CurrentPoint');
  ud.right=min(ud.samps,max(ud.left+1,ceil(currentPoint(1))));
  if ud.linkCursors
    step=50;
  else	
    step=round(0.2*(ud.winright-ud.winleft));
  end	
  if ud.right >= ud.winright
    ud.winright=min(ud.samps,ud.winright+step);
    if ud.winright < ud.samps
      ud.winleft=ud.winleft+step;
    end	  
    set(ud.wavAxes,'XLim',[ud.winleft ud.winright]);
  end  
  if ud.linkCursors
    ud.left=ud.right-ud.gap;
    if ud.left < 0
      ud.left=1;
      ud.right=ud.left+ud.gap-1;
    end  
  end	
  if ud.left <= ud.winleft
    ud.winleft=max(1,ud.winleft-step);
    if ud.winleft > 1
      ud.winright=ud.winright-step;
    end	  
    set(ud.wavAxes,'XLim',[ud.winleft ud.winright]);
  end 
  set(ud.l,'XData',[ud.left ud.left]);
  set(ud.r,'XData',[ud.right ud.right]);  
  set(gcf,'UserData',ud);
    if ud.spectRecalc
      wavspect 'plotSpect'
    end  

case 'plotSpect'
  ud=get(gcf,'UserData');

  if ud.useHamming
    spect=performFFT(window(ud.right-ud.left+1,'hamming')'.*ud.sig(ud.left:ud.right),ud.freqs,ud.fs);
  else 		  	  
    spect=performFFT(ud.sig(ud.left:ud.right),ud.freqs,ud.fs);
  end

  set(ud.p,'YData',spect,'Color',[0 0 1]);
  set(gcf,'UserData',ud);
  
case 'release'
  set(gcf,'WindowButtonMotionFcn','');
  set(gcf,'WindowButtonUpFcn','');
  if  get(findobj('Tag','playCheck'),'Value'); 
    ud=get(gcf,'UserData');
    sound(ud.sig(ud.left:ud.right),ud.fs);
  end 

otherwise
  maduievent('wavspect',action);
 
end

function s=performFFT(sig,fvals,fs)
  % compute FFT of signal and return result at specified frequencies
  lsig=length(sig);
  lf=length(fvals);
  % find nearest power of 2 to signal length
  f=fft(sig,max(64,power(2,round(log2(lsig)))));
  f=20*log10(1e-10+abs(f(2:round(length(f)/2))));
  s=interp1(linspace(1,fs/2,length(f)),f,fvals);

  function lowlight(h)
  if get(h,'Color')~=[0.8 0.8 1.0]
    set(h,'Color',[0.8 0.8 1.0]);
  end  
