function auto(action)
%AUTO   Autocorrelation demo

%  Author: Stuart N Wrigley       
%  MAD - Matlab Auditory Demonstrations
%  (c) University of Sheffield 1998
%  Revision 0.01: 25 July 1998
%
% Revised for V2.1 to use create/load signal menus
% MPC 11/6/99

if nargin < 1
   action='init';
end

switch action
case 'init'

f=findobj('Tag','auto_fig');
  if ~isempty(f)
    figure(f);
  else  
   auto_gui;
   ud=get(gcf,'UserData');
   % store handles 
   ud.handle.signalAxes=findobj('Tag','signalAxes');
   ud.handle.signalLine=findobj('Tag','signalLine');
   ud.handle.signalLC=findobj('Tag','signalLC');     % left cursor  (LC)
   ud.handle.signalRC=findobj('Tag','signalRC');     % right cursor (RC)
   ud.handle.autoAxes=findobj('Tag','autoAxes');
   ud.handle.autoLine=findobj('Tag','autoLine');
   ud.handle.contourAxes=findobj('Tag','contourAxes');
   ud.handle.contourLine=findobj('Tag','contourLine');
   % set initial values
   ud.window.typelist={'rectangular';'hanning';'hamming';'triangular'};
   ud.window.sizelist={'8';'16';'32';'64';'128';'256';'512';'1024';'2048';'4096'};
   ud.window.type=4;
   set(ud.windowtype,'String',ud.window.typelist,'Value',1);
   %set(findobj(gcf,'Tag','windowType'),'Value',ud.window.type);
   set(findobj(gcf,'Tag','winSizePopup'),'String',ud.window.sizelist);
   set(findobj(gcf,'Tag','winSizePopup'),'Value',6);
   ud.recalc=get(findobj('Tag','recalcCheck'),'Value');
   ud.linkCursors=get(findobj('Tag','linkCursorsCheck'),'Value');
   ud.clipAmount=30;
   set(findobj(gcf,'Tag','clipAmount'),'String',ud.clipAmount);
   ud.recalcContour=0;
   set(findobj(gcf,'Tag','recalcContourCheck'),'Value',ud.recalcContour);
   ud.signal.vector=[];
   ud.signal.orig=[];
   ud.signal.fs=22050;
   ud.signal.YLim=[-1.1 1.1];
   ud.contour.orig=[];
   ud.contour.vector=[];
   ud.right=5;
   ud.left=0;
   ud.lagstep=2;
   % initially disable certain controls
   set(findobj(gcf,'Style','pushbutton'),'Enable','off');
   set(gcf,'UserData',ud);
   auto useClip;
   auto setWindowSize;
   end
   
case 'changeWin'
   auto setWindowSize;
   ud=get(gcf,'UserData');
   if ud.recalcContour
       auto plotContour;
   end
   
case 'setWindowSize'
   ud=get(gcf,'UserData');
   val=get(findobj('Tag','winSizePopup'),'Value');
   ud.window.size=min((ud.right-ud.left+1),str2num(ud.window.sizelist{val}));
   set(gcf,'UserData',ud);
   auto setWindowVector;
   
case 'setWindowVector'
   ud=get(gcf,'UserData');
   ud.window.type=get(findobj('Tag','windowType'),'Value');
   ud.window.vector = window(ud.window.size,getuicontrolvalue(ud.windowtype));
   set(gcf,'UserData',ud);
   auto plotAuto;
  
case 'useClip'  
   ud=get(gcf,'UserData');
   ud.useClip=get(findobj('Tag','clipCheck'),'Value');
   if ud.useClip
      set(findobj(gcf,'Tag','clipAmount'),'Enable','on');
   else
      set(findobj(gcf,'Tag','clipAmount'),'Enable','off');
   end
   set(gcf,'UserData',ud);      
   if ~isempty(ud.signal.orig)
      if ud.useClip
         ud.signal.vector=ud.signal.clipped;
      else
         ud.signal.vector=ud.signal.orig;
      end
      set(gcf,'UserData',ud);      
      auto plotSignal;
   end
   
case 'changeClip'
   ud=get(gcf,'UserData');
   ud.clipAmount=str2num(get(findobj(gcf,'Tag','clipAmount'),'String'));
   ud.signal.clipped=centreclip(ud.signal.orig,ud.clipAmount,'normal');
   ud.signal.vector=ud.signal.clipped;
   set(gcf,'UserData',ud);      
   auto plotSignal;
   
case 'create'
  [sig,fs,name]=createsig;
  if length(sig)
    ud=get(gcf,'UserData');
    ud.sig=sig; ud.name=name; ud.fs=fs;
    set(gcf,'UserData',ud);
    auto 'loadGeneric'
  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;
    set(gcf,'UserData',ud);
    auto 'loadGeneric'
  end
  
case 'loadGeneric'  
   ud=get(gcf,'UserData');
      ud.signal.fs=ud.fs;
      set(findobj(gcf,'Style','pushbutton'),'Enable','on');
      ud.signal.vector = normalise(ud.sig(:));
      ud.signal.orig=ud.signal.vector(:)';
      ud.signal.clipped=centreclip(ud.signal.orig,ud.clipAmount,'normal');
      ud.signal.samples=length(ud.signal.orig);
      ud.signal.winleft=1;
      ud.signal.winright=ud.signal.samples;
      ud.left=round(0.1*length(ud.signal.vector));
      ud.right=round(0.9*length(ud.signal.vector));
      ud.gap=ud.right-ud.left+1;
      ud.contour.orig=[];
      ud.contour.vector=[];
      set(gcf,'UserData',ud);
      auto deleteContour;
      auto useClip;
   
case 'plotSignal'   
   ud=get(gcf,'UserData');
   if ~isempty(ud.signal.vector)      
      set(ud.handle.signalAxes,'YLim',ud.signal.YLim,'XLim',[1 ud.signal.samples]);
      set(ud.handle.signalLine,'XData',1:ud.signal.samples,'YData',ud.signal.vector,'Color','blue');
      set(ud.handle.signalLC,'XData',[ud.left ud.left],'YData',ud.signal.YLim,'Color','red');
      set(ud.handle.signalRC,'XData',[ud.right ud.right],'YData',ud.signal.YLim,'Color','red');
      set(gcf,'UserData',ud);
      auto 'setWindowSize';
      if ud.recalcContour
         auto plotContour;
      end
   end

case 'plotAuto'
   ud=get(gcf,'UserData');
   if ~isempty(ud.signal.vector)      
      x=ista(padSignal(ud.signal.vector,ud.window.size),ud.signal.fs,ud.window.vector,ud.left,ud.lagstep);
      maxX=samplestomilli(ud.window.size,ud.signal.fs);  % display in milli
      set(ud.handle.autoAxes,'NextPlot','replacechildren','Drawmode','fast','XLim',[0 maxX],'YLim',[-1.1 1.1]);
      set(ud.handle.autoLine,'XData',linspace(0,maxX,length(x)),'YData',x);
      set(gcf,'UserData',ud);
   end
   
case 'plotContour'
   ud=get(gcf,'UserData');
   if ~isempty(ud.signal.vector)
      set(gcf,	'Name','Autocorrelation - Calculating...')
      ac=sta(ud.signal.vector,ud.signal.fs,ud.window.vector,ud.window.size/2,1);
      ud.contour.orig=getpitch(ac);
      ud.contour.vector=ud.contour.orig;
      set(gcf,	'Name','Autocorrelation')
   end
   if isempty(ud.contour.vector)
      set(ud.handle.contourAxes,'NextPlot','replacechildren','Drawmode','fast','XLim',[0 1],'YLim',[-1 1]);
      set(ud.handle.contourLine,'XData',[],'YData',[]);      
   else
      maxy=max(ud.contour.vector);
      maxY=samplestomilli(maxy,ud.signal.fs);
      ratio=maxy/maxY;
      set(ud.handle.contourAxes,'NextPlot','replacechildren','Drawmode','fast','XLim',[ud.signal.winleft ud.signal.winright],'YLim',[0 maxY+0.1]);
      set(ud.handle.contourLine,'XData',linspace(0,ud.signal.samples,length(ud.contour.vector)),'YData',ud.contour.vector/ratio,'Color','blue');
   end
   set(gcf,'UserData',ud);
   
case 'deleteContour' 
   ud=get(gcf,'UserData');
   set(ud.handle.contourAxes,'NextPlot','replacechildren','Drawmode','fast','XLim',[0 1],'YLim',[-1 1]);
   set(ud.handle.contourLine,'XData',[],'YData',[]);      
   
   
case 'release'
   set(gcf,'WindowButtonMotionFcn','');
   set(gcf,'WindowButtonUpFcn','');
   if get(findobj('Tag','playCheck'),'Value')
      ud=get(gcf,'UserData');
      soundsc(ud.signal.vector(ud.left:ud.right),ud.signal.fs);
   end	

   
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 'recalc'
   ud=get(gcf,'UserData');
   ud.recalc=get(findobj('Tag','recalcCheck'),'Value');
   set(gcf,'UserData',ud);
   if ud.recalc
      auto 'setWindowSize'
   end
   
case 'recalcContour'
   ud=get(gcf,'UserData');
   ud.recalcContour=get(findobj('Tag','recalcContourCheck'),'Value');
   set(gcf,'UserData',ud);
   
case 'useHamming'
   ud=get(gcf,'UserData');
   ud.useHamming=get(findobj('Tag','useHammingCheck'),'Value'); 
   set(gcf,'UserData',ud);
   if ud.recalc
      auto 'setWindowSize'
   end
   
case 'playSignal'
    ud=get(gcf,'UserData');
    if ~isempty(ud.signal.vector)
        soundsc(ud.signal.vector,ud.signal.fs);
     end
   
   
   
   
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   %%%%%%%%%%%%%%%%%%%%%%%%%%%% ZOOM CONTROLS FOLLOW %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   
   
   
   
  
case 'unzoom'
   ud=get(gcf,'UserData');
   mid=round((ud.signal.winright-ud.signal.winleft)/2);
   ud.signal.winleft=max(1,ud.signal.winleft-mid);
   ud.signal.winright=min(ud.signal.samples,ud.signal.winright+mid); 	 
   set(ud.handle.signalAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
   set(ud.handle.contourAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
   %set(ud.handle.signalLC,'XData',[ud.left ud.left]);
   %set(ud.handle.signalRC,'XData',[ud.right ud.right]); 
   set(gcf,'UserData',ud);
  
 case 'showall'
   ud=get(gcf,'UserData');
   ud.signal.winleft=1;
   ud.signal.winright=ud.signal.samples; 	 
   set(ud.handle.signalAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
   set(ud.handle.contourAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
   set(gcf,'UserData',ud);
   
   
case 'zoomToCursors' 
   ud=get(gcf,'UserData'); 
   if ud.linkCursors
      ud.signal.winleft=max(1,round(ud.left-0.1*(ud.right-ud.left)));
      ud.signal.winright = min(ud.signal.samples,round(ud.right+0.1*(ud.right-ud.left)));
      set(ud.handle.signalAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
      set(ud.handle.contourAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
      set(gcf,'UserData',ud);
   else	 
      ud.signal.winleft = ud.left;
      ud.signal.winright = ud.right;
      ud.left = round(ud.signal.winleft+0.1*(ud.signal.winright-ud.signal.winleft));
      ud.right = round(ud.signal.winright-0.1*(ud.signal.winright-ud.signal.winleft));
      set(ud.handle.signalAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
      set(ud.handle.contourAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
      set(ud.handle.signalLC,'XData',[ud.left ud.left]);
      set(ud.handle.signalRC,'XData',[ud.right ud.right]);   
      set(gcf,'UserData',ud);
      if ud.recalc
         auto 'setWindowSize'
      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.signal.winleft = min(ud.left-5,round((ud.signal.winleft+cmid)/2));
         ud.signal.winright = max(ud.right+5,round((ud.signal.winright+cmid)/2));
         set(ud.handle.signalAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
         set(ud.handle.contourAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
         set(gcf,'UserData',ud);
      else
         ud.signal.winleft = round((ud.signal.winleft+cmid)/2);
         ud.signal.winright = round((ud.signal.winright+cmid)/2);
         set(ud.handle.signalAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
         set(ud.handle.contourAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
         redo=0;
         if ud.left < ud.signal.winleft+5
            ud.left = ud.signal.winleft+5;
            set(ud.handle.signalLC,'XData',[ud.left ud.left]);
            redo=1;
         end
         if ud.right > ud.signal.winright-5
            ud.right = ud.signal.winright-5;
            set(ud.handle.signalRC,'XData',[ud.right ud.right]);
            redo=1;
         end
         set(gcf,'UserData',ud);
         if and(redo,ud.recalc)
            auto 'setWindowSize'
         end	 
      end	
   end 
   
case 'left'
   set(gcf,'WindowButtonMotionFcn','auto moveleft');
   set(gcf,'WindowButtonUpFcn','auto release');
   
case 'right'
   set(gcf,'WindowButtonMotionFcn','auto moveright');
   set(gcf,'WindowButtonUpFcn','auto 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.signal.winright-ud.signal.winleft));
   end	 
   if ud.left <= ud.signal.winleft
      ud.signal.winleft=max(1,ud.signal.winleft-step);
      if ud.signal.winleft > 1
         ud.signal.winright=ud.signal.winright-step;
      end	  
      set(ud.handle.signalAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
      set(ud.handle.contourAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
   end
   if ud.linkCursors
      ud.right = ud.left + ud.gap;
      if ud.right >= ud.signal.samples
         ud.right=ud.signal.samples;
         ud.left=ud.signal.samples-ud.gap;
      end
   end	  
   if ud.right >= ud.signal.winright
      ud.signal.winright=min(ud.signal.samples,ud.signal.winright+step);
      if ud.signal.winright < ud.signal.samples
         ud.signal.winleft=ud.signal.winleft+step;
      end	  
      set(ud.handle.signalAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
      set(ud.handle.contourAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
   end    
   
   set(ud.handle.signalLC,'XData',[ud.left ud.left]);
   set(ud.handle.signalRC,'XData',[ud.right ud.right]);
   set(gcf,'UserData',ud);
   if ud.recalc
      auto 'setWindowSize'
   end	
   
case 'moveright'
   ud=get(gcf,'UserData');
   currentPoint=get(gca,'CurrentPoint');
   ud.right=min(ud.signal.samples,max(ud.left+1,ceil(currentPoint(1))));
   if ud.linkCursors
      step=50;
   else	
      step=round(0.2*(ud.signal.winright-ud.signal.winleft));
   end	
   if ud.right >= ud.signal.winright
      ud.signal.winright=min(ud.signal.samples,ud.signal.winright+step);
      if ud.signal.winright < ud.signal.samples
         ud.signal.winleft=ud.signal.winleft+step;
      end	  
      set(ud.handle.signalAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
      set(ud.handle.contourAxes,'XLim',[ud.signal.winleft ud.signal.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.signal.winleft
      ud.signal.winleft=max(1,ud.signal.winleft-step);
      if ud.signal.winleft > 1
         ud.signal.winright=ud.signal.winright-step;
      end	  
      set(ud.handle.signalAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
      set(ud.handle.contourAxes,'XLim',[ud.signal.winleft ud.signal.winright]);
   end 
   set(ud.handle.signalLC,'XData',[ud.left ud.left]);
   set(ud.handle.signalRC,'XData',[ud.right ud.right]);  
   set(gcf,'UserData',ud);
   if ud.recalc
      auto 'setWindowSize'
   end
     
otherwise
  maduievent('auto',action);
  
end


%-------------------------------------------------------
function signal=padSignal(signal,padLength)
signal=signal(:);
signal=[signal;zeros(padLength,1)];
