function pipeline(action)
%PIPELINE A simple demonstration of time-domain, frequency-domain and cepstral-domain conversion
% 
% To start, load a signal using the 'Load' menu.
%
%  Author: Stuart N Wrigley       
%  MAD - Matlab Auditory Demonstrations
%  (c) University of Sheffield 1998
%  Revision 0.02: 1 September 1998
%  updated July 1999 for v2.1 by Martin

if nargin < 1
  action='init';
end

switch action
case 'init'
  % open gui
  f=findobj('Tag','pipeline_fig');
  if ~isempty(f)
    figure(f);
  else 
    pipeline_gui;
    ud=get(gcf,'UserData');
    % initialise signal data
    ud.sig=[];
    ud.fs=11025;
    
    % set initalised data in gui
    ud.functions={'none';'log';'IDFT';'magnitude DFT'};
    set([ud.fn1 ud.fn2 ud.fn3 ud.fn4],'String',ud.functions,'Value',1);
    ud.fun1=ud.functions{get(ud.fn1,'Value')};
    ud.fun2=ud.functions{get(ud.fn2,'Value')};
    ud.fun3=ud.functions{get(ud.fn3,'Value')};
    ud.fun4=ud.functions{get(ud.fn4,'Value')};
    
    % initialise window data
    ud.window.types={'rectangular';'triangular';'hanning';'hamming'};
    ud.window.sizes={'8';'16';'32';'64';'128';'256';'512';'1024';'2048';'4096'};
    set(ud.winType,'String',ud.window.types,'Value',4);
    set(ud.winSize,'String',ud.window.sizes,'Value',6);
    
    ud.YLim=[-1.1 1.1];
    ud.reLim=1;
    
    set(gcf,'UserData',ud);
    pipeline changeWinSize;
  end
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);
    pipeline '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; 
    set(gcf,'UserData',ud);
    pipeline 'newsig'
  end

case 'newsig'
  ud=get(gcf,'UserData');
  set(gcf,'Name',['pipeline [' ud.name ']'])
  ud.sig=normalise(ud.sig(:));  % ensure column vector
  ud.samples=length(ud.sig);
  ud.winleft=1;
  ud.winright=ud.samples;
  ud.left=round(0.1*length(ud.sig));
  ud.right=ud.left+ud.window.size-1;
  set(ud.fn1,'Value',1);
  set(ud.fn2,'Value',1);
  set(ud.fn3,'Value',1);
  set(ud.fn4,'Value',1);
  set(gcf,'UserData',ud);      
  pipeline clearAxes1to4;
  pipeline plotSignal;
  
  
case 'changeWinType'   
  ud=get(gcf,'UserData');
  ud.window.vector=window(ud.window.size,getuicontrolvalue(ud.winType));
  set(gcf,'UserData',ud);
  pipeline refresh;
  
case 'changeWinSize'
  ud=get(gcf,'UserData');
  ud.window.size=str2num(ud.window.sizes{get(ud.winSize,'Value')});
  ud.nfft=ud.window.size;
  ud.reLim=1;
  set(gcf,'UserData',ud);
  pipeline changeWinType;
  pipeline plotCursors;
  
  
case 'left'
  set(gcf,'WindowButtonMotionFcn','pipeline moveleft');
  set(gcf,'WindowButtonUpFcn','pipeline release');
  
case 'right'
  set(gcf,'WindowButtonMotionFcn','pipeline moveright');
  set(gcf,'WindowButtonUpFcn','pipeline release');
  
case 'release'
  set(gcf,'WindowButtonMotionFcn','');
  set(gcf,'WindowButtonUpFcn','');
  ud=get(gcf,'UserData');
  if get(ud.playOnRelease,'Value')  
    ud=get(gcf,'UserData');
    sound(ud.sig(ud.left:ud.right),ud.fs);
  end	

case 'moveleft'
  ud=get(gcf,'UserData');
  currentPoint=get(gca,'CurrentPoint');
  ud.left=min(ud.right-1,max(1,ceil(currentPoint(1))));
  step=50;
  if ud.left <= ud.winleft
    ud.winleft=max(1,ud.winleft-step);
    if ud.winleft > 1
      ud.winright=ud.winright-step;
    end	  
    set(ud.signalAxes,'XLim',[ud.winleft ud.winright]);
  end
  ud.right = ud.left + ud.window.size;
  if ud.right >= ud.samples
    ud.right=ud.samples;
    ud.left=ud.samples-ud.window.size;
  end
  if ud.right >= ud.winright
    ud.winright=min(ud.samples,ud.winright+step);
    if ud.winright < ud.samples
      ud.winleft=ud.winleft+step;
    end	  
    set(ud.signalAxes,'XLim',[ud.winleft ud.winright]);
  end    
  set(ud.signalLC,'XData',[ud.left ud.left]);
  set(ud.signalRC,'XData',[ud.right ud.right]);
  set(gcf,'UserData',ud);
  pipeline refresh;
  
case 'moveright'
  ud=get(gcf,'UserData');
  currentPoint=get(gca,'CurrentPoint');
  ud.right=min(ud.samples,max(ud.left+1,ceil(currentPoint(1))));
  step=50;
  if ud.right >= ud.winright
    ud.winright=min(ud.samples,ud.winright+step);
    if ud.winright < ud.samples
      ud.winleft=ud.winleft+step;
    end	  
    set(ud.signalAxes,'XLim',[ud.winleft ud.winright]);
  end  
  ud.left=ud.right-ud.window.size;
  if ud.left < 0
    ud.left=1;
    ud.right=ud.left+ud.window.size-1;
  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.signalAxes,'XLim',[ud.winleft ud.winright]);
  end 
  set(ud.signalLC,'XData',[ud.left ud.left]);
  set(ud.signalRC,'XData',[ud.right ud.right]);  
  set(gcf,'UserData',ud);
  pipeline refresh;
  
case 'refresh'
  ud=get(gcf,'UserData');
  if ~isempty(ud.sig)
    pipeline Fn1Calc;
  end

case 'changeFn1'
  ud=get(gcf,'UserData');
  ud.fun1=ud.functions{get(ud.fn1,'Value')};
  set(gcf,'UserData',ud);
  if ~isempty(ud.sig)
    ud.reLim=1;
    set(gcf,'UserData',ud);
    pipeline Fn1Calc;
  end

case 'changeFn2'
  ud=get(gcf,'UserData');
  ud.fun2=ud.functions{get(ud.fn2,'Value')};   
  set(gcf,'UserData',ud);
  if ~isempty(ud.sig)
    ud.reLim=1;
    set(gcf,'UserData',ud);
    pipeline Fn2Calc;
  end

case 'changeFn3'
  ud=get(gcf,'UserData');
  ud.fun3=ud.functions{get(ud.fn3,'Value')};   
  set(gcf,'UserData',ud);
  if ~isempty(ud.sig)
    ud.reLim=1;
    set(gcf,'UserData',ud);
    pipeline Fn3Calc;
  end

case 'changeFn4'
  ud=get(gcf,'UserData');
  ud.fun4=ud.functions{get(ud.fn4,'Value')};   
  set(gcf,'UserData',ud);
  if ~isempty(ud.sig)
    ud.reLim=1;
    set(gcf,'UserData',ud);
    pipeline Fn4Calc;
  end


case 'Fn1Calc'
  ud=get(gcf,'UserData');
  prevSection=ud.sig(ud.left:ud.left+ud.window.size-1).*ud.window.vector;
  prevendIndex=ud.window.size;
  [ud.data1,ud.endIndex1,YLim]=optionCalc(ud.fun1,prevSection,prevendIndex,ud.nfft);
  if ud.reLim
    set(ud.Axes1,'NextPlot','replacechildren','Drawmode','fast','XLim',[1 ud.endIndex1],'YLim',YLim);
  end
  set(ud.Axes1Line,'XData',1:ud.endIndex1,'YData',ud.data1(1:ud.endIndex1),'Color','blue');      
  set(gcf,'UserData',ud);
  pipeline Fn2Calc;pipeline Fn3Calc;pipeline Fn4Calc;
  
case 'Fn2Calc'
  ud=get(gcf,'UserData');
  [ud.data2,ud.endIndex2,YLim]=optionCalc(ud.fun2,ud.data1,ud.endIndex1,ud.nfft);
  if ud.reLim
    set(ud.Axes2,'NextPlot','replacechildren','Drawmode','fast','XLim',[1 ud.endIndex2],'YLim',YLim);
  end
  set(ud.Axes2Line,'XData',1:ud.endIndex2,'YData',ud.data2(1:ud.endIndex2),'Color','blue');      
  set(gcf,'UserData',ud);
  pipeline Fn3Calc;pipeline Fn4Calc;
  
case 'Fn3Calc'
  ud=get(gcf,'UserData');
  [ud.data3,ud.endIndex3,YLim]=optionCalc(ud.fun3,ud.data2,ud.endIndex2,ud.nfft);
  if ud.reLim
    set(ud.Axes3,'NextPlot','replacechildren','Drawmode','fast','XLim',[1 ud.endIndex3],'YLim',YLim);
  end
  set(ud.Axes3Line,'XData',1:ud.endIndex3,'YData',ud.data3(1:ud.endIndex3),'Color','blue');      
  set(gcf,'UserData',ud);
  pipeline Fn4Calc;
  
case 'Fn4Calc'
  ud=get(gcf,'UserData');
  [ud.data4,ud.endIndex4,YLim]=optionCalc(ud.fun4,ud.data3,ud.endIndex3,ud.nfft);
  startIndex=5;
  if ud.reLim
    YLim=[min(real(ud.data4(startIndex:end))) max(real(ud.data4(startIndex:end)))];
    set(ud.Axes4,'NextPlot','replacechildren','Drawmode','fast','XLim',[startIndex ud.endIndex4],'YLim',YLim);
    ud.reLim=0;
  end
  set(ud.Axes4Line,'XData',startIndex:ud.endIndex4,'YData',ud.data4(startIndex:ud.endIndex4),'Color','blue');      
  set(gcf,'UserData',ud);
  
case 'clearAxes1to4'
  ud=get(gcf,'UserData');
  set(ud.Axes1Line,'EraseMode','xor','XData',[],'YData',[],'Color','blue');      
  set(ud.Axes2Line,'EraseMode','xor','XData',[],'YData',[],'Color','blue');      
  set(ud.Axes3Line,'EraseMode','xor','XData',[],'YData',[],'Color','blue');      
  set(ud.Axes4Line,'EraseMode','xor','XData',[],'YData',[],'Color','blue');      
  
  
case 'playSignal'
  ud=get(gcf,'UserData');
  if ~isempty(ud.sig)
    soundsc(ud.sig,ud.fs);
  end


case 'plotSignal'
  ud=get(gcf,'UserData');
  if ~isempty(ud.sig)
    set(ud.signalAxes,'YLim',ud.YLim,'XLim',[1 ud.samples]);
    set(ud.sigline,'XData',1:ud.samples,'YData',ud.sig,'Color','blue');
    set(gcf,'UserData',ud);
    pipeline plotCursors;
    pipeline refresh;
  end

case 'plotCursors'
  ud=get(gcf,'UserData');
  if ~isempty(ud.sig)
    ud.right=ud.left+ud.window.size-1;
    set(ud.signalLC,'XData',[ud.left ud.left],'YData',ud.YLim,'Color','red');
    set(ud.signalRC,'XData',[ud.right ud.right],'YData',ud.YLim,'Color','red');
  end   

otherwise
  maduievent('pipeline',action);
  
end


% ------------------
function [data,endIndex,YLim]=optionCalc(optionStr,prevSection,prevendIndex,nfft)
switch optionStr
case 'none'
  data=prevSection;
  endIndex=prevendIndex;
case 'magnitude DFT'
  data=abs(fft(prevSection,nfft));
  endIndex=fix(nfft/2);
case 'log'
  data=log10(0.00001+prevSection);
  endIndex=prevendIndex;
case 'IDFT'
  data=ifft(prevSection,nfft);
  endIndex=fix(nfft/2);
end
YLim=[min(real(data)) max(real(data))];
