function polezero(action)
%POLEZERO Interactive design of linear systems via poles and zeros
%
% Part of the Sheffield Matlab Auditory Demos (freeware)
% Martin Cooke, September 1998
%   updated July 1999 for v2.1

if nargin < 1
    action='init';
end

switch action
case 'init'
    % open gui
    f=findobj('Tag','polezero_fig');
    if ~isempty(f)
        figure(f);
    else     
        polezero_gui;
        ud=get(gcf,'UserData');
        % set up axes etc
        ud.fs=8012;
        ud.npoints=256;
        axes(ud.magAxes);
        set(ud.magAxes,'YLim',[-80 0],'XLim',[0 round(ud.fs/2)]);
        xlabel('frequency (Hz)');
        ylabel('attenuation (dB)');
        title('frequency response on unit circle')
        ud.freqs=linspace(0,ud.fs/2,ud.npoints);
        ud.magline=line(ud.freqs,zeros(size(ud.freqs)));
        set(ud.magline,'EraseMode','xor');
        set(gcf,'KeyPressFcn','polezero keypressed');
        set(gcf,'UserData',ud);
    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);
    polezero '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);
    polezero 'newsig'
  end
    
case 'newsig'
  ud=get(gcf,'UserData');
    set(gcf,'Name',['pole-zero [' ud.name ']'])
    set([ud.playorig ud.playfilt],'Enable','on');
    set(gcf,'UserData',ud);
    polezero 'setfreqaxis'
    polezero 'sysresponse'
  
case 'setfreqaxis'  
  ud=get(gcf,'UserData');
  set(ud.magAxes,'XLim',[0 round(ud.fs/2)]);
  ud.freqs=linspace(0,ud.fs/2,ud.npoints);
  set(ud.magline,'XData',ud.freqs,'YData',zeros(size(ud.freqs)),...
                 'EraseMode','xor');
        set(gcf,'UserData',ud);
 
case 'vowel'
  % set poles to locations for a given vowel
  ud=get(gcf,'UserData');
  % delete existing poles and zeros
  delete(findobj(gcf,'Tag','Pole'));
  delete(findobj(gcf,'Tag','Zero'));
  vowel=get(gcbo,'Label');
  bws=[0.03 0.07 0.1];    %formant freqs from Rabiner & Juang
  switch vowel
    case 'bEEt'
      freqs=[270 2290 3010];  
    case 'bIt'
      freqs=[390 1990 2550];    
    case 'bEt'
      freqs=[530 1840 2480];
    case 'bAt'
      freqs=[660 1720 2410];
    case 'bARt'
      freqs=[730 1090 2440];
    case 'bORt'
      freqs=[570 840 2410];
    case 'bUt'
      freqs=[440 1020 2240];
    case 'bOOt'
      freqs=[300 870 2240];
    case 'bERt'
      freqs=[490 1350 1690];
      otherwise
  end
  % convert freqs and bws to PZ locations
  angs=2*pi*freqs/ud.fs;
  for f=1:length(freqs)
    [x,y]=pol2cart(angs(f),1-bws(f));
    p1=text('Parent',ud.pzAxes,'Position',[x y],'String','X',...
    'ButtonDownFcn','polezero selectpole',...
    'EraseMode','xor',...
    'Tag','Pole');
    p2=text('Parent',ud.pzAxes,'Position',[x -y],'String','X',...
    'ButtonDownFcn','polezero selectpole',...
    'EraseMode','xor',...
    'Tag','Pole');
    set(p1,'UserData',p2);
    set(p2,'UserData',p1); 
   end
    %set(gcf,'UserData',ud);
    polezero 'sysresponse'
       
case 'addpole'  
    ud=get(gcf,'UserData');
    [x,y]=pol2cart(pi/10,0.5*rand(1));
    p1=text('Parent',ud.pzAxes,'Position',[x y],'String','X',...
    'ButtonDownFcn','polezero selectpole',...
    'EraseMode','xor',...
    'Tag','Pole');
    p2=text('Parent',ud.pzAxes,'Position',[x -y],'String','X',...
    'ButtonDownFcn','polezero selectpole',...
    'EraseMode','xor',...
    'Tag','Pole');
    set(p1,'UserData',p2);
    set(p2,'UserData',p1);
    set(gcf,'UserData',ud);
    polezero 'sysresponse'
    
case 'addzero'
    ud=get(gcf,'UserData');
    [x,y]=pol2cart(pi/10,0.5*rand(1));
    p1=text('Parent',ud.pzAxes,'Position',[x y],'String','o',...
    'ButtonDownFcn','polezero selectzero',...
    'EraseMode','xor',...
    'Tag','Zero','HorizontalAlignment','center'); 
    p2=text('Parent',ud.pzAxes,'Position',[x -y],'String','o',...
    'ButtonDownFcn','polezero selectzero',...
    'EraseMode','xor',...
    'Tag','Zero');
    set(p1,'UserData',p2);
    set(p2,'UserData',p1);
    set(gcf,'UserData',ud);
    polezero 'sysresponse'
    
case 'selectpole'  
    ud=get(gcf,'UserData');
    s=get(gcbo,'UserData');
    set(gcf,'WindowButtonMotionFcn','polezero movepole');
    set(gcf,'WindowButtonUpFcn','polezero releaseobject');
    ud.currentpole=gcbo;
    ud.partnerpole=s;
    set([findobj(gca,'Tag','Pole'); findobj(gca,'Tag','Zero')],'Selected','off');
    set([ud.currentpole ud.partnerpole],'Selected','on');
    set(gcf,'UserData',ud); 
    
case 'movepole'
    ud=get(gcf,'UserData');
    cp=get(ud.pzAxes,'CurrentPoint');
    if (cp(1)*cp(1)+cp(3)*cp(3)) < 0.999
      set(ud.currentpole,'Position',[cp(1) cp(3)]); 
      set(ud.partnerpole,'Position',[cp(1) -cp(3)]);
      set(gcf,'UserData',ud);
      polezero 'sysresponse'
    end  
    
case 'unselectall'
    set(findobj(gca,'Tag','Pole'),'Selected','off');
    set(findobj(gca,'Tag','Zero'),'Selected','off');  
    
case 'selectzero'  
    ud=get(gcf,'UserData');
    s=get(gcbo,'UserData');
    set(gcf,'WindowButtonMotionFcn','polezero movezero');
    set(gcf,'WindowButtonUpFcn','polezero releaseobject');
    ud.currentzero=gcbo;
    ud.partnerzero=s;
    set([findobj(gca,'Tag','Pole'); findobj(gca,'Tag','Zero')],'Selected','off');
    set([ud.currentzero ud.partnerzero],'Selected','on');    
    set(gcf,'UserData',ud); 
    
case 'movezero'
    ud=get(gcf,'UserData');
    cp=get(ud.pzAxes,'CurrentPoint');
    set(ud.currentzero,'Position',[cp(1) cp(3)]); 
    set(ud.partnerzero,'Position',[cp(1) -cp(3)]); 
    set(gcf,'UserData',ud);
    polezero 'sysresponse'
    
case 'releaseobject'
    set(gcf,'WindowButtonMotionFcn','');
    set(gcf,'WindowButtonUpFcn','');
    polezero 'sysresponse'
    
case 'keypressed'
    % if delete key is pressed, delete any selected object
    if double(get(gcf,'CurrentCharacter')) == 8
        delete(findobj(gcf,'Selected','on')) 
    end
    polezero 'sysresponse'

case 'sysresponse'
    % compute the mag and phase response of the current system
    % find all poles/zeros and form polar coordinates
    ud=get(gcf,'UserData');
    polepos=findobj(ud.pzAxes,'Tag','Pole');
    zeropos=findobj(ud.pzAxes,'Tag','Zero');
    len=max(length(polepos),length(zeropos));
    pp=zeros(1,len);  % pp=1e-10*rand(1,len);
    for p=1:length(polepos)
        ppos=get(polepos(p),'Position');
        pp(p)=ppos(1)+ppos(2)*i;
    end  
    zz=zeros(1,len);  % zz=1e-10*rand(1,len);
    for z=1:length(zeropos)
        zp=get(zeropos(z),'Position');  
        zz(z)=zp(1)+zp(2)*i;
    end
    ud.zz=zz;ud.pp=pp;
    [ud.num,ud.den]=zp2tf(zz',pp',1);
    %axes(ud.magAxes);
    [h,w]=freqz(ud.num,ud.den,ud.freqs,ud.fs);
    % normalise so max = 0 dB
    logmag=20*log10(abs(h));
    logmag=logmag-max(logmag);
    set(ud.magline,'YData',logmag);
    set(gcf,'UserData',ud);
    
case 'playFiltered'
    % apply filter
    ud=get(gcf,'UserData');
    f=filter(ud.num,ud.den,ud.sig);
    soundsc(f,ud.fs)  
    
case 'playOriginal'
    % apply filter
    ud=get(gcf,'UserData'); 
    sound(ud.sig,ud.fs);

otherwise
  maduievent('polezero',action);
   
end

