[xiph-commits] r18349 - trunk/spectrum

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Sat Jun 2 18:22:51 PDT 2012


Author: xiphmont
Date: 2012-06-02 18:22:50 -0700 (Sat, 02 Jun 2012)
New Revision: 18349

Modified:
   trunk/spectrum/analyzer.h
   trunk/spectrum/io.c
   trunk/spectrum/io.h
   trunk/spectrum/spec_panel.c
   trunk/spectrum/spec_plot.c
   trunk/spectrum/spec_plot.h
   trunk/spectrum/spec_process.c
   trunk/spectrum/version.h
Log:
Modify fish to not spin when input is suspended
runbutton now down at start instaed of waiting for data
Wholesale rework of data/locking flow between io and ui threads; spectrum is now close to being able to reconfig on the fly when a pipe is closed and reopened with a fresh data stream/new header



Modified: trunk/spectrum/analyzer.h
===================================================================
--- trunk/spectrum/analyzer.h	2012-06-02 16:38:29 UTC (rev 18348)
+++ trunk/spectrum/analyzer.h	2012-06-03 01:22:50 UTC (rev 18349)
@@ -1,24 +1,24 @@
 /*
  *
  *  gtk2 spectrum analyzer
- *    
+ *
  *      Copyright (C) 2004-2012 Monty
  *
  *  This analyzer is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2, or (at your option)
  *  any later version.
- *   
+ *
  *  The analyzer is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *   
+ *
  *  You should have received a copy of the GNU General Public License
  *  along with Postfish; see the file COPYING.  If not, write to the
  *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * 
+ *
  */
 
 #ifndef _ANALYZER_H_
@@ -40,6 +40,7 @@
 #include <signal.h>
 #include <fcntl.h>
 #include <fftw3.h>
+#include "spec_plot.h"
 
 /* blocksize for the FFT */
 extern int blocksize;
@@ -83,27 +84,16 @@
 extern void *process_thread(void *dummy);
 extern void process_dump(int mode);
 extern void rundata_clear();
-extern void clear_noise_floor();
-extern float **process_fetch(int scale, int mode, int link, 
-			     int *active, int width, 
-			     float *ymax, float *pmax, float *pmin);
+extern fetchdata *process_fetch(int scale, int mode, int link,
+                                 int *process, int process_n,
+                                 int height, int width);
 
-extern pthread_mutex_t feedback_mutex;
-extern int feedback_increment;
-extern float **feedback_acc;
-extern float **feedback_max;
-extern float **feedback_instant;
-extern float **feedback_rp;
-extern sig_atomic_t acc_clear;
 extern sig_atomic_t acc_rewind;
 extern sig_atomic_t acc_loop;
-
 extern sig_atomic_t process_active;
 extern sig_atomic_t process_exit;
 
 #define LINKS 5
-static char *link_entries[LINKS]={"independent","sum","subtract ref","subtract from",
-				  "response/phase"};
 #define LINK_INDEPENDENT  0
 #define LINK_SUMMED       1
 #define LINK_SUB_REF      2

Modified: trunk/spectrum/io.c
===================================================================
--- trunk/spectrum/io.c	2012-06-02 16:38:29 UTC (rev 18348)
+++ trunk/spectrum/io.c	2012-06-03 01:22:50 UTC (rev 18349)
@@ -39,7 +39,6 @@
 int rate_force[MAX_FILES] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
 int signed_force[MAX_FILES] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
 
-extern sig_atomic_t acc_loop;
 extern int blocksize;
 int blockslice[MAX_FILES]= {-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1};
 
@@ -425,6 +424,21 @@
   return 0;
 }
 
+/* attempts to reopen any inputs that are pipes.  Does not check for
+   EOF, ignores non-fifo inputs.  Returns nonzero if any pipes
+   reopened. */
+
+int pipe_reload(){
+  int fi;
+  int ret=0;
+  for(fi=0;fi<inputs;fi++)
+    if(!seekable[fi] && isapipe[fi] && !load_one_input(fi)){
+      fprintf(stderr,"reloading....\n");
+      ret=1;
+    }
+  return ret;
+}
+
 /* Convert new data from readbuffer into the blockbuffers until the
    blockbuffer is full */
 static void LBEconvert(int *localslice){
@@ -608,28 +622,21 @@
                     inputname[fi],strerror(ferror(f[fi])));
 	  }else if (actually_readbytes==0){
             /* real, hard EOF/error in a partially filled block */
-            /* if this input is a pipe, reload its input state */
-            if(!seekable[fi] && isapipe[fi] && !load_one_input(fi)){
-              fprintf(stderr,"reloading....\n");
+            if(!partialok){
+              /* partial frame is *not* ok.  zero it out. */
+              memset(readbuffer[fi],0,readbuffersize);
+              bytesleft[fi]=0;
+              readbufferfill[fi]=0;
+              readbufferptr[fi]=0;
+              blockbufferfill[fi]=0;
+            }
+            if(loop && seekable[fi] && (!rewound[fi] || (partialok && blockbufferfill[fi]))){
+              /* rewind this file and continue */
+              fseek(f[fi],offset[fi],SEEK_SET);
+              if(length[fi]!=-1)
+                bytesleft[fi]=length[fi]*channels[fi]*((bits[fi]+7)/8);
               notdone=1;
-            }else{
-
-              if(!partialok){
-                /* partial frame is *not* ok.  zero it out. */
-                memset(readbuffer[fi],0,readbuffersize);
-                bytesleft[fi]=0;
-                readbufferfill[fi]=0;
-                readbufferptr[fi]=0;
-                blockbufferfill[fi]=0;
-              }
-              if(loop && (!rewound[fi] || (partialok && blockbufferfill[fi]))){
-                /* rewind this file and continue */
-                fseek(f[fi],offset[fi],SEEK_SET);
-                if(length[fi]!=-1)
-                  bytesleft[fi]=length[fi]*channels[fi]*((bits[fi]+7)/8);
-                notdone=1;
-                rewound[fi]=1;
-              }
+              rewound[fi]=1;
             }
 	  }else{
             /* got a read */

Modified: trunk/spectrum/io.h
===================================================================
--- trunk/spectrum/io.h	2012-06-02 16:38:29 UTC (rev 18348)
+++ trunk/spectrum/io.h	2012-06-03 01:22:50 UTC (rev 18349)
@@ -48,6 +48,7 @@
 
 extern pthread_mutex_t ioparam_mutex;
 extern int input_load(void);
+extern int pipe_reload(void);
 extern int input_read(int loop_p, int partial_p);
 extern int rewind_files(void);
 

Modified: trunk/spectrum/spec_panel.c
===================================================================
--- trunk/spectrum/spec_panel.c	2012-06-02 16:38:29 UTC (rev 18348)
+++ trunk/spectrum/spec_panel.c	2012-06-03 01:22:50 UTC (rev 18349)
@@ -18,7 +18,7 @@
  *  along with Postfish; see the file COPYING.  If not, write to the
  *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * 
+ *
  */
 
 #include "analyzer.h"
@@ -26,32 +26,29 @@
 #include <gdk/gdkkeysyms.h>
 #include "fisharray.h"
 #include "spec_plot.h"
-#include "io.h"
 
-sig_atomic_t increment_fish=0;
+GtkWidget *twirlimage;
+GdkPixmap *ff[19];
+GdkBitmap *fb[19];
 
-static struct panel {
-  GtkWidget *twirlimage;
-  GdkPixmap *ff[19];
-  GdkBitmap *fb[19];
+GtkAccelGroup *group;
+GtkWidget *toplevel;
 
-  GtkAccelGroup *group;
-  GtkWidget *toplevel;
+guint fishframe_timer;
+int fishframe_init;
+int fishframe;
 
+GtkWidget *plot;
+GtkWidget *run;
+GtkWidget **chbuttons;
+GtkWidget *bwtable;
+GtkWidget *bwbutton;
+GtkWidget *bwmodebutton;
+GtkWidget *plot_label_al;
 
-  guint fishframe_timer;
-  int fishframe_init;
-  int fishframe;
+int plot_ch=0;
+int plot_inputs=0;
 
-  GtkWidget *plot;
-  GtkWidget *run;
-  GtkWidget **chbuttons;
-  GtkWidget *bwtable;
-  GtkWidget *bwbutton;
-  GtkWidget *bwmodebutton;
-  GtkWidget *plot_label_al;
-} p;
-
 int plot_scale=0;
 int plot_mode=0;
 int plot_link=0;
@@ -59,117 +56,304 @@
 int plot_lock_y=0;
 int plot_depth=90;
 int plot_noise=0;
-int plot_last_update=0;
 int plot_bw=0;
 int plot_bwmode=0;
 int plot_bold=0;
 int *active;
 
-static void override_base(GtkWidget *w, int active){
-  gtk_widget_modify_base (w, GTK_STATE_NORMAL, &w->style->bg[active?GTK_STATE_ACTIVE:GTK_STATE_NORMAL]);
-}
+/* first up... the Fucking Fish */
+sig_atomic_t increment_fish=0;
 
-static void replot(struct panel *p){
-  int i,lactive[total_ch];
-  for(i=0;i<total_ch;i++)
-    lactive[i]=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p->chbuttons[i]));
-
-  /* update the spectral display; send new data */
-  if(!plot_hold){
-    pthread_mutex_lock(&feedback_mutex);
-    plot_refresh(PLOT(p->plot),lactive);
-    plot_last_update=feedback_increment;
-    pthread_mutex_unlock(&feedback_mutex);
-  }
-}
-
-static void shutdown(void){
-  gtk_main_quit();
-}
-
-/* gotta have the Fucking Fish */
-static int reanimate_fish(struct panel *p){
-  if(process_active || (p->fishframe>0 && p->fishframe<12)){
+static int reanimate_fish(void){
+  if(process_active || (fishframe>0 && fishframe<12)){
     /* continue spinning */
-    if(increment_fish)p->fishframe++;
-    if(p->fishframe>=12)p->fishframe=0;
+    if(increment_fish || fishframe>0)fishframe++;
+    if(fishframe==1)increment_fish=0;
+    if(fishframe>=12)fishframe=0;
 
-    gtk_image_set_from_pixmap(GTK_IMAGE(p->twirlimage),
-                              p->ff[p->fishframe],
-                              p->fb[p->fishframe]);
+    gtk_image_set_from_pixmap(GTK_IMAGE(twirlimage),
+                              ff[fishframe],
+                              fb[fishframe]);
 
-    if(p->fishframe==0 && !process_active){
+    if(fishframe==0 && !process_active){
       /* reschedule to blink */
-      p->fishframe_timer=
-	g_timeout_add(rand()%1000*30,(GSourceFunc)reanimate_fish,p);
+      fishframe_timer=
+	g_timeout_add(rand()%1000*30,(GSourceFunc)reanimate_fish,NULL);
       return FALSE;
     }
 
   }else{
-    p->fishframe++;
-    if(p->fishframe<=1)p->fishframe=12;
-    if(p->fishframe>=19)p->fishframe=0;
+    fishframe++;
+    if(fishframe<=1)fishframe=12;
+    if(fishframe>=19)fishframe=0;
 
-    gtk_image_set_from_pixmap(GTK_IMAGE(p->twirlimage),
-                              p->ff[p->fishframe],
-                              p->fb[p->fishframe]);
+    gtk_image_set_from_pixmap(GTK_IMAGE(twirlimage),
+                              ff[fishframe],
+                              fb[fishframe]);
 
-    if(p->fishframe==12){
+    if(fishframe==12){
       /* reschedule to animate */
-      p->fishframe_timer=
-	g_timeout_add(10,(GSourceFunc)reanimate_fish,p);
+      fishframe_timer=
+	g_timeout_add(10,(GSourceFunc)reanimate_fish,NULL);
       return FALSE;
     }
-    if(p->fishframe==0){
+    if(fishframe==0){
       /* reschedule to blink */
-      p->fishframe_timer=
-	g_timeout_add(rand()%1000*30,(GSourceFunc)reanimate_fish,p);
+      fishframe_timer=
+	g_timeout_add(rand()%1000*30,(GSourceFunc)reanimate_fish,NULL);
       return FALSE;
     }
   }
   return TRUE;
 }
 
-static void animate_fish(struct panel *p){
-  if(p->fishframe_init){
-    g_source_remove(p->fishframe_timer);
-    p->fishframe_timer=
-      g_timeout_add(70,(GSourceFunc)reanimate_fish,p);
+static void animate_fish(void){
+  if(fishframe_init){
+    g_source_remove(fishframe_timer);
+    fishframe_timer=
+      g_timeout_add(70,(GSourceFunc)reanimate_fish,NULL);
   }else{
-    p->fishframe_init=1;
-    p->fishframe_timer=
-      g_timeout_add(rand()%1000*30,(GSourceFunc)reanimate_fish,p);
+    fishframe_init=1;
+    fishframe_timer=
+      g_timeout_add(rand()%1000*30,(GSourceFunc)reanimate_fish,NULL);
   }
 }
 
-static void dump(GtkWidget *widget,struct panel *p){
-  process_dump(plot_mode);
+/* autoscale movement calculation and damping */
+
+typedef struct {
+  float a;
+  float b1;
+  float b2;
+  float x[2];
+  float y[2];
+} pole2;
+
+static float plot_ymax_target;
+static int plot_ymaxtimer;
+static pole2 plot_ymax_damp;
+static float plot_pmax_target;
+static pole2 plot_pmax_damp;
+static int plot_pmaxtimer;
+static float plot_pmin_target;
+static pole2 plot_pmin_damp;
+static int plot_pmintimer;
+
+static void filter_reset(pole2 *p, float val){
+  p->x[0]=p->x[1]=val;
+  p->y[0]=p->y[1]=val;
 }
 
-#if 0
-static void noise(GtkWidget *widget,struct panel *p){
-  if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))){
-    if(plot_noise){
-      plot_noise=0;
-      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),0);
-      clear_noise_floor();
-      plot_setting(PLOT(p->plot),plot_scale,plot_mode,plot_link,plot_depth,0);
+static void filter_make_critical(float w, pole2 *f){
+  float w0 = tan(M_PI*w*pow(pow(2,.5)-1,-.5));
+  f->a  = w0*w0/(1+(2*w0)+w0*w0);
+  f->b1 = 2*f->a*(1/(w0*w0)-1);
+  f->b2 = 1-(4*f->a+f->b1);
+  filter_reset(f,0);
+}
+
+static float filter_filter(float x, pole2 *p){
+  float y =
+    p->a*x + 2*p->a*p->x[0] + p->a*p->x[1] +
+    p->b1*p->y[0] + p->b2*p->y[1];
+  p->y[1] = p->y[0]; p->y[0] = y;
+  p->x[1] = p->x[0]; p->x[0] = x;
+  return y;
+}
+
+#define HYSTERESIS_THRESHOLD .25
+#define HYSTERESIS_TIMERFRAMES 30
+
+static void calculate_autoscale (fetchdata *f,
+                                 plotparams *pp,
+                                 int request_reset){
+  int phase = f->phase_active;
+  int height = f->height;
+  int plot_ymax_limit = (plot_depth>140 ? plot_depth : 140);
+  float ymax = f->ymax;
+  float pmax = f->pmax;
+  float pmin = f->pmin;
+
+  /* graph limit updates are conditional depending on mode/link */
+  switch(f->link){
+  case LINK_INDEPENDENT:
+  case LINK_SUMMED:
+  case LINK_PHASE:
+    {
+      float dBpp = plot_depth/height;
+      ymax += dBpp*25;
+    }
+    break;
+  }
+
+  if(ymax<plot_depth - plot_ymax_limit) ymax=plot_depth-plot_ymax_limit;
+  if(ymax>plot_ymax_limit)ymax=plot_ymax_limit;
+
+  pmax+=10;
+  pmin-=10;
+  if(pmax<5)pmax=5;
+  if(pmax>190)pmax=190;
+  if(pmin>-20)pmin=-20;
+  if(pmin<-190)pmin=-190;
+
+  /* phase/response zeros align on phase graphs; verify targets
+     against phase constraints */
+  if(phase){
+    float pzero,mzero = height/plot_depth*ymax;
+
+    /* move mag zero back onscreen if it's off */
+    if(mzero < height*HYSTERESIS_THRESHOLD){
+      ymax = (plot_depth*height*HYSTERESIS_THRESHOLD)/height;
+    }
+    if(mzero > height*(1-HYSTERESIS_THRESHOLD)){
+      ymax = (plot_depth*height*(1-HYSTERESIS_THRESHOLD))/height;
+    }
+
+    mzero = height/plot_depth*ymax;
+    pzero = height/(pmax-pmin)*pmax;
+
+    if(mzero<pzero){
+      /* straightforward; move the dB range down */
+      ymax = pzero*plot_depth/height;
     }else{
-      plot_noise=1;
-      plot_setting(PLOT(p->plot),plot_scale,plot_mode,plot_link,plot_depth,0);
+      /* a little harder as phase has a min and a max.
+         First increase the pmax to match the dB zero. */
+
+      pmax = pmin/(1-height/mzero);
+      pzero = height/(pmax-pmin)*pmax;
+
+      /* That worked, but might have run pmax overrange */
+      if(pmax>190.){
+        /* reconcile by allowing mag to overrange */
+        pmax = 190.;
+        pzero = height/(pmax-pmin)*pmax;
+        ymax = plot_depth*pzero/height;
+        plot_ymaxtimer=0;
+      }
     }
+  }
+
+  if(request_reset){
+    pp->ymax=plot_ymax_target=ymax;
+    filter_reset(&plot_ymax_damp,pp->ymax);
+    plot_ymaxtimer=HYSTERESIS_TIMERFRAMES;
+
+    if(phase){
+      pp->pmax=plot_pmax_target=pmax;
+      pp->pmin=plot_pmin_target=pmin;
+      filter_reset(&plot_pmax_damp,pp->pmax);
+      filter_reset(&plot_pmin_damp,pp->pmin);
+      plot_pmaxtimer=HYSTERESIS_TIMERFRAMES;
+      plot_pmintimer=HYSTERESIS_TIMERFRAMES;
+    }
+
   }else{
-    if(plot_noise){
-      gtk_button_set_label(GTK_BUTTON(widget),"clear _noise floor");
-      plot_noise=2;
-      plot_setting(PLOT(p->plot),plot_scale,plot_mode,plot_link,plot_depth,1);
-    }else
-      gtk_button_set_label(GTK_BUTTON(widget),"sample _noise floor");
+    /* conditionally set new damped ymax target */
+    if(plot_ymaxtimer>0)
+      plot_ymaxtimer--;
+
+    if(ymax > plot_ymax_target-plot_depth*HYSTERESIS_THRESHOLD)
+      plot_ymaxtimer=HYSTERESIS_TIMERFRAMES;
+
+    if(ymax > plot_ymax_target || plot_ymaxtimer<=0)
+      plot_ymax_target=ymax;
+
+    /* update ymax through scale damping filter */
+    pp->ymax = filter_filter(plot_ymax_target,&plot_ymax_damp);
+
+    /* apply same hyteresis and update to phase */
+    if(phase){
+
+      if(plot_pmaxtimer>0)
+        plot_pmaxtimer--;
+      if(plot_pmintimer>0)
+        plot_pmintimer--;
+
+      if(pmax > plot_pmax_target*(1-HYSTERESIS_THRESHOLD))
+        plot_pmaxtimer=HYSTERESIS_TIMERFRAMES;
+      if(pmax > plot_pmax_target || plot_pmaxtimer<=0)
+        plot_pmax_target=pmax;
+
+      if(pmin < plot_pmin_target*(1-HYSTERESIS_THRESHOLD))
+        plot_pmintimer=HYSTERESIS_TIMERFRAMES;
+      if(pmin < plot_pmin_target || plot_pmintimer<=0)
+        plot_pmin_target=pmin;
+
+      pp->pmax = filter_filter(plot_pmax_target,&plot_pmax_damp);
+      pp->pmin = filter_filter(plot_pmin_target,&plot_pmin_damp);
+
+    }
   }
+
+  if(phase){
+    /* when phase is active, the plot_ymax in use is dictated by
+       plot_pmax/plot_pmin, which in turn already took the desired ymax
+       into consideration above */
+    pp->ymax = plot_depth*pp->pmax/(pp->pmax-pp->pmin);
+  }
 }
-#endif
 
-static void depthchange(GtkWidget *widget,struct panel *p){
+/* a gtk2 hack to override checkbox background color */
+static void override_base(GtkWidget *w, int active){
+  gtk_widget_modify_base
+    (w, GTK_STATE_NORMAL,
+     &w->style->bg[active?GTK_STATE_ACTIVE:GTK_STATE_NORMAL]);
+}
+
+/* scale_reset != 0  requests an instant optimal rescale */
+/* inactive_reset    performs a reset only if processing is not active */
+/*  scale_damp != 0  requests a normal animated rescaling operation.
+                     It processing is not active, this is promoted to
+                     an instant optimal rescale */
+/* plot_lock_y overrides all scaling requests */
+
+static plotparams pp;
+static int oldphase=0;
+void replot(int scale_reset, int inactive_reset, int scale_damp){
+  int i,process[plot_ch];
+
+  for(i=0;i<plot_ch;i++)
+    process[i]=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(chbuttons[i]));
+
+  /* update the spectral display; send new data */
+  fetchdata *f = process_fetch
+    (plot_scale, plot_mode, plot_link,
+     process, plot_ch, plot_height(PLOT(plot)), plot_width(PLOT(plot)));
+
+  /* the fetched data may indicate the underlying file data has
+     changed... */
+  if(f->reload){
+    /* rebuild the button and file lists */
+
+
+
+  }
+
+ 
+  if(!plot_lock_y){
+    if(scale_reset ||
+       (f->phase_active != oldphase) ||
+       (!process_active && (inactive_reset || scale_damp)))
+      calculate_autoscale(f,&pp,1);
+    else if(scale_damp)
+      calculate_autoscale(f,&pp,0);
+  }
+  oldphase = f->phase_active;
+
+  pp.depth=plot_depth;
+  pp.bold=plot_bold;
+  plot_draw(PLOT(plot),f,&pp);
+}
+
+static void shutdown(void){
+  gtk_main_quit();
+}
+
+static void dump(GtkWidget *widget,gpointer in){
+  process_dump(plot_mode);
+}
+
+static void depthchange(GtkWidget *widget,gpointer in){
   int choice=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
   switch(choice){
   case 0: /* 1dB */
@@ -190,11 +374,11 @@
   case 5: /*140dB */
     plot_depth=140;
     break;
-  case 6: /*200dB */
-    plot_depth=200;
+  case 6: /*190dB */
+    plot_depth=190;
     break;
   }
-  plot_setting(PLOT(p->plot),plot_scale,plot_mode,plot_link,plot_depth,plot_noise);
+  replot(1,1,0);
 }
 
 static void set_fg(GtkWidget *c, gpointer in){
@@ -209,152 +393,122 @@
     gtk_container_forall (GTK_CONTAINER(c),set_fg,in);
 }
 
-static void set_via_active(struct panel *p, int *active, int *bactive){
-  int fi,i;
-  int ch=0;
-  for(fi=0;fi<inputs;fi++){
-    for(i=ch;i<ch+channels[fi];i++)
-      gtk_widget_set_sensitive(p->chbuttons[i],1);
-    ch+=channels[fi];
-  }
-  plot_set_active(PLOT(p->plot),active,bactive);  
-  gtk_alignment_set_padding(GTK_ALIGNMENT(p->plot_label_al),0,0,0,plot_get_right_pad(PLOT(p->plot)));
-}
-
-static void chlabels(GtkWidget *widget,struct panel *p){
+static void chlabels(GtkWidget *widget,gpointer in){
   /* scan state, update labels on channel buttons, set sensitivity
      based on grouping and mode */
   int fi,ch,i;
   char buf[80];
-  int bactive[total_ch];
 
-  for(i=0;i<total_ch;i++)
-    bactive[i]=active[i]=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p->chbuttons[i]));
-
   /* set sensitivity */
   switch(plot_link){
   case LINK_SUB_REF:
-
-    /*  first channel in each group insensitive/inactive, used as a reference */
+    /* first channel in each group insensitive/inactive, used as a
+       reference */
     ch=0;
-    for(fi=0;fi<inputs;fi++){
+    for(fi=0;fi<plot_inputs;fi++){
       for(i=ch;i<ch+channels[fi];i++){
 	if(i==ch){
-	  gtk_widget_set_sensitive(p->chbuttons[i],0);
-	  active[i]=0; /* do not frob widget, only plot settings */
+	  gtk_widget_set_sensitive(chbuttons[i],0);
 	}else{
-	  gtk_widget_set_sensitive(p->chbuttons[i],1);
+	  gtk_widget_set_sensitive(chbuttons[i],1);
 	}
       }
       ch+=channels[fi];
     }
- 
-    plot_set_active(PLOT(p->plot),active,bactive);
-    break;    
+    break;
 
   case LINK_SUMMED: /* summing mode */
   case LINK_SUB_FROM: /* subtract channels from reference */
+  case LINK_INDEPENDENT: /* normal/independent mode */
+
     ch=0;
-    for(fi=0;fi<inputs;fi++){
-      int any=0;
-      for(i=ch;i<ch+channels[fi];i++){
-	if(active[i])any=1;
-	active[i]=0;
-      }
-      active[ch]=any;
+    for(fi=0;fi<plot_inputs;fi++){
+      for(i=ch;i<ch+channels[fi];i++)
+        gtk_widget_set_sensitive(chbuttons[i],1);
       ch+=channels[fi];
     }
-
-    set_via_active(p,active,bactive);
     break;
 
-  case LINK_INDEPENDENT: /* normal/independent mode */
-    set_via_active(p,active,bactive);
-    break;    
-
   case LINK_PHASE: /* response/phase */
     ch=0;
-    for(fi=0;fi<inputs;fi++){
+    for(fi=0;fi<plot_inputs;fi++){
       for(i=ch;i<ch+channels[fi];i++)
 	if(channels[fi]<2){
-	  gtk_widget_set_sensitive(p->chbuttons[i],0);
-	  active[i]=0;
+	  gtk_widget_set_sensitive(chbuttons[i],0);
 	}else{
 	  if(i<ch+2){
-	    gtk_widget_set_sensitive(p->chbuttons[i],1);
+	    gtk_widget_set_sensitive(chbuttons[i],1);
 	  }else{
-	    gtk_widget_set_sensitive(p->chbuttons[i],0);
-	    active[i]=0;
+	    gtk_widget_set_sensitive(chbuttons[i],0);
 	  }
 	}
       ch+=channels[fi];
     }
-    plot_set_active(PLOT(p->plot),active,bactive);
-    break;    
+    break;
   }
 
   /* set labels */
   switch(plot_link){
   case LINK_SUB_REF:
     ch=0;
-    for(fi=0;fi<inputs;fi++){
+    for(fi=0;fi<plot_inputs;fi++){
       for(i=ch;i<ch+channels[fi];i++){
 	if(i==ch){
-	  gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),"reference");
+	  gtk_button_set_label(GTK_BUTTON(chbuttons[i]),"reference");
 	}else{
 	  sprintf(buf,"channel %d", i-ch);
-	  gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),buf);
+	  gtk_button_set_label(GTK_BUTTON(chbuttons[i]),buf);
 	}
       }
       ch+=channels[fi];
     }
-    break;    
+    break;
   case LINK_SUB_FROM:
     ch=0;
-    for(fi=0;fi<inputs;fi++){
+    for(fi=0;fi<plot_inputs;fi++){
       for(i=ch;i<ch+channels[fi];i++){
 	if(i==ch){
-	  gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),"output");
+	  gtk_button_set_label(GTK_BUTTON(chbuttons[i]),"output");
 	}else{
 	  sprintf(buf,"channel %d", i-ch);
-	  gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),buf);
+	  gtk_button_set_label(GTK_BUTTON(chbuttons[i]),buf);
 	}
       }
       ch+=channels[fi];
     }
-    break;    
+    break;
 
   case LINK_INDEPENDENT:
   case LINK_SUMMED:
 
     ch=0;
-    for(fi=0;fi<inputs;fi++){
+    for(fi=0;fi<plot_inputs;fi++){
       for(i=ch;i<ch+channels[fi];i++){
 	sprintf(buf,"channel %d", i-ch);
-	gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),buf);
+	gtk_button_set_label(GTK_BUTTON(chbuttons[i]),buf);
       }
       ch+=channels[fi];
     }
-    break;    
+    break;
 
   case LINK_PHASE:
 
     ch=0;
-    for(fi=0;fi<inputs;fi++){
+    for(fi=0;fi<plot_inputs;fi++){
       for(i=ch;i<ch+channels[fi];i++){
 	if(channels[fi]<2){
-	  gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),"unused");
+	  gtk_button_set_label(GTK_BUTTON(chbuttons[i]),"unused");
 	}else if(i==ch){
-	  gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),"response");
+	  gtk_button_set_label(GTK_BUTTON(chbuttons[i]),"response");
 	}else if(i==ch+1){
-	  gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),"phase");
+	  gtk_button_set_label(GTK_BUTTON(chbuttons[i]),"phase");
 	}else{
-	  gtk_button_set_label(GTK_BUTTON(p->chbuttons[i]),"unused");
+	  gtk_button_set_label(GTK_BUTTON(chbuttons[i]),"unused");
 	}
       }
       ch+=channels[fi];
     }
-    break;    
+    break;
   }
 
   /* set colors */
@@ -362,11 +516,11 @@
   case LINK_SUMMED:
   case LINK_SUB_FROM:
     ch=0;
-    for(fi=0;fi<inputs;fi++){
+    for(fi=0;fi<plot_inputs;fi++){
       GdkColor rgb = chcolor(ch);
 
       for(i=ch;i<ch+channels[fi];i++){
-	GtkWidget *button=p->chbuttons[i];	
+	GtkWidget *button=chbuttons[i];
 	set_fg(button,&rgb);
       }
       ch+=channels[fi];
@@ -375,113 +529,104 @@
 
   default:
     ch=0;
-    for(fi=0;fi<inputs;fi++){
+    for(fi=0;fi<plot_inputs;fi++){
       for(i=ch;i<ch+channels[fi];i++){
 	GdkColor rgb = chcolor(i);
-	GtkWidget *button=p->chbuttons[i];
+	GtkWidget *button=chbuttons[i];
 	set_fg(button,&rgb);
       }
       ch+=channels[fi];
     }
     break;
   }
-  gtk_alignment_set_padding(GTK_ALIGNMENT(p->plot_label_al),0,0,0,plot_get_right_pad(PLOT(p->plot)));
+
+  if(widget)replot(0,1,0);
+  gtk_alignment_set_padding(GTK_ALIGNMENT(plot_label_al),0,0,0,
+                            plot_get_right_pad(PLOT(plot)));
 }
 
-static void scalechange(GtkWidget *widget,struct panel *p){
+static void scalechange(GtkWidget *widget,gpointer in){
   plot_scale=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
-  plot_setting(PLOT(p->plot),plot_scale,plot_mode,plot_link,plot_depth,plot_noise);
+  replot(0,0,0);
 }
 
-static void modechange(GtkWidget *widget,struct panel *p){
+static void modechange(GtkWidget *widget,gpointer in){
   plot_mode=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
-  replot(p);
-  plot_setting(PLOT(p->plot),plot_scale,plot_mode,plot_link,plot_depth,plot_noise);
+  replot(0,1,0);
 }
 
-static void linkchange(GtkWidget *widget,struct panel *p){
+static void linkchange(GtkWidget *widget,gpointer in){
   plot_link=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
-  replot(p);
-  plot_setting(PLOT(p->plot),plot_scale,plot_mode,plot_link,plot_depth,plot_noise);
-  chlabels(widget,p);
-  gtk_alignment_set_padding(GTK_ALIGNMENT(p->plot_label_al),0,0,0,plot_get_right_pad(PLOT(p->plot)));
+  chlabels(NULL,NULL);
+  gtk_alignment_set_padding(GTK_ALIGNMENT(plot_label_al),
+                            0,0,0,plot_get_right_pad(PLOT(plot)));
+  replot(0,1,0);
 }
 
-static void runchange(GtkWidget *widget,struct panel *p){
+static void runchange(GtkWidget *widget,gpointer in){
   if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))){
     if(!process_active){
       pthread_t thread_id;
       process_active=1;
       process_exit=0;
-      animate_fish(p);
+      animate_fish();
       pthread_create(&thread_id,NULL,&process_thread,NULL);
     }
   }else{
     process_exit=1;
-    while(process_active)sched_yield();
+    //while(process_active)sched_yield();
   }
 }
 
-static void holdchange(GtkWidget *widget,struct panel *p){
+static void holdchange(GtkWidget *widget,gpointer in){
   plot_hold=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
   override_base(widget,plot_hold);
-  replot(p);
-  plot_draw(PLOT(p->plot));
+  replot(0,1,0);
 }
 
-static void lockchange(GtkWidget *widget,struct panel *p){
+static void lockchange(GtkWidget *widget,gpointer in){
   plot_lock_y=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
   override_base(widget,plot_lock_y);
-  plot_set_autoscale(PLOT(p->plot),!plot_lock_y);
+  if(!plot_lock_y)replot(0,1,0);
 }
 
-static void boldchange(GtkWidget *widget,struct panel *p){
+static void boldchange(GtkWidget *widget,gpointer in){
   plot_bold=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
   override_base(widget,plot_bold);
-  plot_set_bold(PLOT(p->plot),plot_bold);
+  replot(0,0,0);
 }
 
-static void loopchange(GtkWidget *widget,struct panel *p){
+static void loopchange(GtkWidget *widget,gpointer in){
   acc_loop=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
 }
 
-static void clearchange(GtkWidget *widget,struct panel *p){
-  acc_clear=1;
-  plot_clear(PLOT(p->plot));
-  if(!process_active){
-    rundata_clear();
-  }
+static void clearchange(GtkWidget *widget,gpointer in){
+  rundata_clear();
+  replot(0,0,0);
 }
 
-static void rewindchange(GtkWidget *widget,struct panel *p){
+static void rewindchange(GtkWidget *widget,gpointer in){
   acc_rewind=1;
 }
 
-static void bwchange(GtkWidget *widget,struct panel *p){
+static void bwchange(GtkWidget *widget,gpointer in){
   plot_bw=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
   if(plot_bw==0){
-
-    gtk_widget_set_sensitive(GTK_WIDGET(p->bwmodebutton),0);
-    //gtk_widget_hide(p->bwmodebutton);
-    //gtk_container_remove(GTK_CONTAINER(p->bwtable),p->bwbutton);
-    //gtk_table_attach_defaults(GTK_TABLE(p->bwtable),p->bwbutton,0,2,0,1);
+    gtk_widget_set_sensitive(GTK_WIDGET(bwmodebutton),0);
   }else{
-
-    gtk_widget_set_sensitive(GTK_WIDGET(p->bwmodebutton),1);
-    //gtk_container_remove(GTK_CONTAINER(p->bwtable),p->bwbutton);
-    //gtk_table_attach_defaults(GTK_TABLE(p->bwtable),p->bwbutton,0,1,0,1);
-    //gtk_widget_show(p->bwmodebutton);
+    gtk_widget_set_sensitive(GTK_WIDGET(bwmodebutton),1);
   }
+  replot(0,1,0);
 }
 
-static void bwmodechange(GtkWidget *widget,struct panel *p){
+static void bwmodechange(GtkWidget *widget,gpointer in){
   plot_bwmode=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
+  replot(0,1,0);
 }
 
 static gint watch_keyboard(GtkWidget *grab_widget,
                            GdkEventKey *event,
-                           gpointer func_data){
-  struct panel *p=(struct panel *)func_data;
+                           gpointer in){
 
   if(event->type == GDK_KEY_PRESS){
     if(event->state == GDK_CONTROL_MASK){
@@ -493,7 +638,7 @@
 }
 
 extern char *version;
-void panel_create(struct panel *panel){
+void panel_create(void){
   int i;
 
   GdkWindow *root=gdk_get_default_root_window();
@@ -506,16 +651,17 @@
   GtkWidget *plot_control_al;
   GtkWidget *wbold;
 
-  active = calloc(total_ch,sizeof(*active));
+  active = calloc(plot_ch,sizeof(*active));
 
-  panel->toplevel=gtk_window_new (GTK_WINDOW_TOPLEVEL);
-  panel->group = gtk_accel_group_new ();
-  gtk_window_add_accel_group (GTK_WINDOW(panel->toplevel), panel->group);
-  gtk_window_set_title(GTK_WINDOW(panel->toplevel),(const gchar *)"Spectrum Analyzer");
-  gtk_window_set_default_size(GTK_WINDOW(panel->toplevel),1024,400);
-  //gtk_widget_set_size_request(GTK_WIDGET(panel->toplevel),1024,400);
-  gtk_container_add (GTK_CONTAINER (panel->toplevel), topbox);
-  g_signal_connect (G_OBJECT (panel->toplevel), "delete_event",
+  toplevel=gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  group = gtk_accel_group_new ();
+  gtk_window_add_accel_group (GTK_WINDOW(toplevel), group);
+  gtk_window_set_title(GTK_WINDOW(toplevel),
+                       (const gchar *)"Spectrum Analyzer");
+  gtk_window_set_default_size(GTK_WINDOW(toplevel),1024,400);
+  //gtk_widget_set_size_request(GTK_WIDGET(toplevel),1024,400);
+  gtk_container_add (GTK_CONTAINER (toplevel), topbox);
+  g_signal_connect (G_OBJECT (toplevel), "delete_event",
 		    G_CALLBACK (shutdown), NULL);
   gtk_widget_set_name(topbox,"panel");
 
@@ -539,20 +685,27 @@
     gtk_widget_set_name(lock_range,"top-control");
     gtk_widget_set_name(hold_display,"top-control");
     gtk_widget_set_name(wbold,"top-control");
-    g_signal_connect (G_OBJECT (hold_display), "clicked", G_CALLBACK (holdchange), panel);
-    gtk_widget_add_accelerator (hold_display, "activate", panel->group, GDK_h, 0, 0);
-    g_signal_connect (G_OBJECT (lock_range), "clicked", G_CALLBACK (lockchange), panel);
-    gtk_widget_add_accelerator (lock_range, "activate", panel->group, GDK_y, 0, 0);
-    gtk_widget_add_accelerator (lock_range, "activate", panel->group, GDK_Y, 0, 0);
-    g_signal_connect (G_OBJECT (wbold), "clicked", G_CALLBACK (boldchange), panel);
-    gtk_widget_add_accelerator (wbold, "activate", panel->group, GDK_b, 0, 0);
+    g_signal_connect (G_OBJECT (hold_display), "clicked",
+                      G_CALLBACK (holdchange), NULL);
+    gtk_widget_add_accelerator (hold_display, "activate",
+                                group, GDK_h, 0, 0);
+    g_signal_connect (G_OBJECT (lock_range), "clicked",
+                      G_CALLBACK (lockchange), NULL);
+    gtk_widget_add_accelerator (lock_range, "activate",
+                                group, GDK_y, 0, 0);
+    gtk_widget_add_accelerator (lock_range, "activate",
+                                group, GDK_Y, 0, 0);
+    g_signal_connect (G_OBJECT (wbold), "clicked",
+                      G_CALLBACK (boldchange), NULL);
+    gtk_widget_add_accelerator (wbold, "activate",
+                                group, GDK_b, 0, 0);
 
   }
 
   /* plot informational labels */
   {
     char buf[80];
-    GtkWidget *al=panel->plot_label_al=gtk_alignment_new(1,.5,0,0);
+    GtkWidget *al=plot_label_al=gtk_alignment_new(1,.5,0,0);
     GtkWidget *box=gtk_hbox_new(0,2);
     GtkWidget *text1=gtk_label_new("window:");
     GtkWidget *text2=gtk_label_new("sin^4  ");
@@ -577,8 +730,8 @@
   }
 
   /* add the spectrum plot box */
-  panel->plot=plot_new(blocksize/2+1,inputs,channels,rate);
-  gtk_table_attach_defaults (GTK_TABLE (lefttable), panel->plot,0,1,2,3);
+  plot=plot_new();
+  gtk_table_attach_defaults (GTK_TABLE (lefttable), plot,0,1,2,3);
   gtk_table_set_row_spacing (GTK_TABLE (lefttable), 2, 4);
   gtk_table_set_col_spacing (GTK_TABLE (lefttable), 0, 2);
 
@@ -607,10 +760,10 @@
     w/=19;
 
     for(i=0;i<19;i++){
-      panel->ff[i]=gdk_pixmap_new(tp,w,h,-1);
-      panel->fb[i]=gdk_pixmap_new(tb,w,h,-1);
-      gdk_draw_drawable(panel->ff[i],cgc,tp,i*w,0,0,0,w,h);
-      gdk_draw_drawable(panel->fb[i],bgc,tb,i*w,0,0,0,w,h);
+      ff[i]=gdk_pixmap_new(tp,w,h,-1);
+      fb[i]=gdk_pixmap_new(tb,w,h,-1);
+      gdk_draw_drawable(ff[i],cgc,tp,i*w,0,0,0,w,h);
+      gdk_draw_drawable(fb[i],bgc,tb,i*w,0,0,0,w,h);
     }
 
     g_object_unref(cgc);
@@ -618,12 +771,12 @@
     g_object_unref(tp);
     g_object_unref(tb);
 
-    panel->twirlimage=gtk_image_new_from_pixmap(panel->ff[0],panel->fb[0]);
+    twirlimage=gtk_image_new_from_pixmap(ff[0],fb[0]);
 
     gtk_container_set_border_width (GTK_CONTAINER (toptable), 1);
     gtk_box_pack_start(GTK_BOX(righttopbox),toptable,0,0,0);
     gtk_container_add (GTK_CONTAINER (sepbox), topsep);
-    gtk_container_add(GTK_CONTAINER(fishbox),panel->twirlimage);
+    gtk_container_add(GTK_CONTAINER(fishbox),twirlimage);
     gtk_table_attach_defaults (GTK_TABLE (toptable), fishbox,0,1,1,2);
     gtk_table_attach_defaults (GTK_TABLE (toptable), sepbox,0,1,1,2);
     gtk_table_set_row_spacing (GTK_TABLE (toptable), 0, 6);
@@ -638,27 +791,28 @@
     char buffer[160];
     GtkWidget *label;
 
-    panel->chbuttons = calloc(total_ch,sizeof(*panel->chbuttons));
-    for(fi=0;fi<inputs;fi++){
+    chbuttons = calloc(plot_ch,sizeof(*chbuttons));
+    for(fi=0;fi<plot_inputs;fi++){
       GtkWidget *al=gtk_alignment_new(0,0,1,0);
       GtkWidget *vbox=gtk_vbox_new(0,0);
-      
+
       char *lastslash = strrchr(inputname[fi],'/');
       sprintf(buffer,"%s",(lastslash?lastslash+1:inputname[fi]));
       label=gtk_label_new(buffer);
       gtk_widget_set_name(label,"readout");
       gtk_box_pack_start(GTK_BOX(vbox),label,0,0,0);
-      
+
       sprintf(buffer,"%dHz %dbit",rate[fi],bits[fi]);
       label=gtk_label_new(buffer);
       gtk_widget_set_name(label,"readout");
       gtk_box_pack_start(GTK_BOX(vbox),label,0,0,0);
 
       for(i=ch;i<ch+channels[fi];i++){
-	GtkWidget *button=panel->chbuttons[i]=gtk_toggle_button_new();
+	GtkWidget *button=chbuttons[i]=gtk_toggle_button_new();
 
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),1);  
-	g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (chlabels), panel);
+	g_signal_connect (G_OBJECT (button), "clicked",
+                          G_CALLBACK (chlabels), NULL);
 	gtk_box_pack_start(GTK_BOX(vbox),button,0,0,0);
       }
 
@@ -669,7 +823,7 @@
       ch+=channels[fi];
 
     }
-    chlabels(NULL,panel);
+    chlabels(NULL,NULL);
   }
   
   /* add the action buttons */
@@ -677,9 +831,9 @@
 
   {
   /* bandwidth mode */
-    GtkWidget *tbox=panel->bwtable=gtk_table_new(2,2,0);
+    GtkWidget *tbox=bwtable=gtk_table_new(2,2,0);
 
-    GtkWidget *menu=panel->bwbutton=gtk_combo_box_new_text();
+    GtkWidget *menu=bwbutton=gtk_combo_box_new_text();
     char *entries[]={"native","display"};
     //"1Hz","3Hz","10Hz","30Hz","100Hz","300Hz","1kHz",
     //"1/24oct","1/12oct","1/6oct","1/3oct"};
@@ -689,15 +843,15 @@
     //gtk_combo_box_set_active(GTK_COMBO_BOX(menu),0);
     
     g_signal_connect (G_OBJECT (menu), "changed",
-    		      G_CALLBACK (bwchange), panel);
+    		      G_CALLBACK (bwchange), NULL);
 
-    GtkWidget *menu2=panel->bwmodebutton=gtk_combo_box_new_text();
+    GtkWidget *menu2=bwmodebutton=gtk_combo_box_new_text();
     char *entries2[]={"RBW","VBW"};
     for(i=0;i<2;i++)
       gtk_combo_box_append_text (GTK_COMBO_BOX (menu2), entries2[i]);
     
     g_signal_connect (G_OBJECT (menu2), "changed",
-    		      G_CALLBACK (bwmodechange), panel);
+    		      G_CALLBACK (bwmodechange), NULL);
     gtk_combo_box_set_active(GTK_COMBO_BOX(menu2),0);
 
     gtk_table_attach_defaults(GTK_TABLE(tbox),menu,0,1,0,1);
@@ -711,18 +865,17 @@
     for(i=0;i<3;i++)
       gtk_combo_box_append_text (GTK_COMBO_BOX (menu3), entries3[i]);
     gtk_combo_box_set_active(GTK_COMBO_BOX(menu3),plot_scale);
-    plot_setting(PLOT(panel->plot),plot_scale,plot_mode,plot_link,plot_depth,plot_noise);
     
     g_signal_connect (G_OBJECT (menu3), "changed",
-		      G_CALLBACK (scalechange), panel);
+		      G_CALLBACK (scalechange), NULL);
 
     GtkWidget *menu4=gtk_combo_box_new_text();
-    char *entries4[]={"1dB","10dB","20dB","45dB","90dB","140dB","200dB"};
+    char *entries4[]={"1dB","10dB","20dB","45dB","90dB","140dB","190dB"};
     for(i=0;i<7;i++)
       gtk_combo_box_append_text (GTK_COMBO_BOX (menu4), entries4[i]);
     
     g_signal_connect (G_OBJECT (menu4), "changed",
-		      G_CALLBACK (depthchange), panel);
+		      G_CALLBACK (depthchange), NULL);
     gtk_combo_box_set_active(GTK_COMBO_BOX(menu4),4);
 
     gtk_table_attach_defaults(GTK_TABLE(tbox),menu3,0,1,1,2);
@@ -742,19 +895,25 @@
     gtk_box_pack_start(GTK_BOX(bbox),menu,0,0,0);
     
     g_signal_connect (G_OBJECT (menu), "changed",
-		      G_CALLBACK (modechange), panel);
+		      G_CALLBACK (modechange), NULL);
   }
   
   /* link */
   {
     GtkWidget *menu=gtk_combo_box_new_text();
+    char *entries[LINKS]={"independent",
+                          "sum",
+                          "subtract ref",
+                          "subtract from",
+                          "response/phase"};
+
     for(i=0;i<LINKS;i++)
-      gtk_combo_box_append_text (GTK_COMBO_BOX (menu), link_entries[i]);
+      gtk_combo_box_append_text (GTK_COMBO_BOX (menu), entries[i]);
     gtk_combo_box_set_active(GTK_COMBO_BOX(menu),0);
     gtk_box_pack_start(GTK_BOX(bbox),menu,0,0,0);
     
     g_signal_connect (G_OBJECT (menu), "changed",
-		      G_CALLBACK (linkchange), panel);
+		      G_CALLBACK (linkchange), NULL);
   }
   
 
@@ -766,11 +925,11 @@
   /* run/pause */
   {
     GtkWidget *button=gtk_toggle_button_new_with_mnemonic("_run");
-    gtk_widget_add_accelerator (button, "activate", panel->group, GDK_space, 0, 0);
-    gtk_widget_add_accelerator (button, "activate", panel->group, GDK_r, 0, 0);
-    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (runchange), panel);
+    gtk_widget_add_accelerator (button, "activate", group, GDK_space, 0, 0);
+    gtk_widget_add_accelerator (button, "activate", group, GDK_r, 0, 0);
+    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (runchange), NULL);
     gtk_box_pack_start(GTK_BOX(bbox),button,0,0,0);
-    panel->run=button;
+    run=button;
   }
   
   /* loop */
@@ -778,15 +937,15 @@
   {
     GtkWidget *box=gtk_hbox_new(1,1);
     GtkWidget *button=gtk_toggle_button_new_with_mnemonic("_loop");
-    gtk_widget_add_accelerator (button, "activate", panel->group, GDK_l, 0, 0);
-    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (loopchange), panel);
+    gtk_widget_add_accelerator (button, "activate", group, GDK_l, 0, 0);
+    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (loopchange), NULL);
     gtk_box_pack_start(GTK_BOX(box),button,1,1,0);
     gtk_widget_set_sensitive(button,global_seekable);
     
 
     button=gtk_button_new_with_mnemonic("re_wind");
-    gtk_widget_add_accelerator (button, "activate", panel->group, GDK_w, 0, 0);
-    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (rewindchange), panel);
+    gtk_widget_add_accelerator (button, "activate", group, GDK_w, 0, 0);
+    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (rewindchange), NULL);
     gtk_widget_set_sensitive(button,global_seekable);
     gtk_box_pack_start(GTK_BOX(box),button,1,1,0);
     
@@ -798,14 +957,14 @@
   {
     GtkWidget *box=gtk_hbox_new(1,1);
     GtkWidget *button=gtk_button_new_with_mnemonic("_clear data");
-    gtk_widget_add_accelerator (button, "activate", panel->group, GDK_c, 0, 0);
-    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (clearchange), panel);
+    gtk_widget_add_accelerator (button, "activate", group, GDK_c, 0, 0);
+    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (clearchange), NULL);
     gtk_box_pack_start(GTK_BOX(box),button,1,1,0);
     
 
     button=gtk_button_new_with_mnemonic("_dump data");
-    gtk_widget_add_accelerator (button, "activate", panel->group, GDK_d, 0, 0);
-    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (dump), panel);
+    gtk_widget_add_accelerator (button, "activate", group, GDK_d, 0, 0);
+    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (dump), NULL);
     gtk_box_pack_start(GTK_BOX(box),button,1,1,0);
 
     gtk_box_pack_start(GTK_BOX(bbox),box,0,0,0);
@@ -815,28 +974,27 @@
 #if 0
   {
     GtkWidget *button=gtk_toggle_button_new_with_mnemonic("sample _noise floor");
-    gtk_widget_add_accelerator (button, "activate", panel->group, GDK_n, 0, 0);
-    g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (noise), panel);
+    gtk_widget_add_accelerator (button, "activate", group, GDK_n, 0, 0);
+    g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (noise), NULL);
     gtk_box_pack_start(GTK_BOX(bbox),button,0,0,0);
   }
 #endif
 
   gtk_box_pack_end(GTK_BOX(rightbox),bbox,0,0,0);
-  gtk_widget_show_all(panel->toplevel);
-  gtk_combo_box_set_active(GTK_COMBO_BOX(panel->bwbutton),0);
+  gtk_widget_show_all(toplevel);
+  gtk_combo_box_set_active(GTK_COMBO_BOX(bwbutton),0);
   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wbold),plot_bold);
 
-  gtk_key_snooper_install(watch_keyboard,panel);
+  gtk_key_snooper_install(watch_keyboard,NULL);
 
-  gtk_alignment_set_padding(GTK_ALIGNMENT(plot_control_al),0,0,plot_get_left_pad(PLOT(panel->plot)),0);
-  gtk_alignment_set_padding(GTK_ALIGNMENT(panel->plot_label_al),0,0,0,plot_get_right_pad(PLOT(panel->plot)));
+  gtk_alignment_set_padding(GTK_ALIGNMENT(plot_control_al),0,0,plot_get_left_pad(PLOT(plot)),0);
+  gtk_alignment_set_padding(GTK_ALIGNMENT(plot_label_al),0,0,0,plot_get_right_pad(PLOT(plot)));
 
 }
 
 static gboolean async_event_handle(GIOChannel *channel,
 				   GIOCondition condition,
 				   gpointer data){
-  struct panel *panel=data;
   char buf[1];
 
   /* read all pending */
@@ -845,24 +1003,20 @@
   increment_fish=1;
 
   /* check playback status and update the run button if needed */
-  if(process_active && panel->run && 
-     !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(panel->run)))
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(panel->run),1);
-  if(!process_active && panel->run && 
-     gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(panel->run)))
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(panel->run),0);
+  if(process_active && run &&
+     !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(run)))
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(run),1);
+  if(!process_active && run &&
+     gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(run)))
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(run),0);
 
   /* update the spectral display; send new data */
-  pthread_mutex_lock(&feedback_mutex);
-  if(plot_last_update!=feedback_increment){
-    pthread_mutex_unlock(&feedback_mutex);
-    replot(panel);
-    plot_draw(PLOT(panel->plot));
+  if(!plot_hold)replot(0,0,1);
 
-    while (gtk_events_pending())
-      gtk_main_iteration();
-  }else
-    pthread_mutex_unlock(&feedback_mutex);
+  /* if we're near CPU limit, service the rest of Gtk over next async
+     update request */
+  while (gtk_events_pending())
+    gtk_main_iteration();
 
   return TRUE;
 }
@@ -880,7 +1034,6 @@
 void panel_go(int argc,char *argv[]){
   char *homedir=getenv("HOME");
   int found=0;
-  memset(&p,0,sizeof(p));
 
   found|=look_for_gtkrc(STR(ETCDIR) "/spectrum-gtkrc");
   {
@@ -906,17 +1059,21 @@
   found|=look_for_gtkrc("./spectrum-gtkrc");
 
   if(!found){
-  
-    fprintf(stderr,"Could not find the spectrum-gtkrc configuration file normally\n"
+
+    fprintf(stderr,
+            "Could not find the spectrum-gtkrc configuration file normally\n"
 	    "installed in one of the following places:\n"
 
 	    "\t./spectrum-gtkrc\n"
 	    "\t$(SPECTRUM_RCDIR)/spectrum-gtkrc\n"
 	    "\t~/.spectrum/spectrum-gtkrc\n\t"
 	    STR(ETCDIR) "/spectrum-gtkrc\n"
-	    "This configuration file is used to tune the color, font and other detail aspects\n"
-	    "of the user interface.  Although the analyzer will work without it, the UI\n"
-	    "appearence will likely make the application harder to use due to missing visual\n"
+	    "This configuration file is used to tune the color, "
+            "font and other detail aspects\n"
+	    "of the user interface.  Although the analyzer will "
+            "work without it, the UI\n"
+	    "appearence will likely make the application harder to "
+            "use due to missing visual\n"
 	    "cues.\n");
   }
 
@@ -932,32 +1089,28 @@
   gtk_rc_add_default_file("spectrum-gtkrc");
   gtk_init (&argc, &argv);
 
-  panel_create(&p);
-  animate_fish(&p);
+  plot_ch = total_ch; /* true now, won't necessarily be true later */
+  plot_inputs = inputs; /* true now, won't necessarily be true later */
 
+  filter_make_critical(.04,&plot_ymax_damp);
+  filter_make_critical(.04,&plot_pmax_damp);
+  filter_make_critical(.04,&plot_pmin_damp);
+
+  panel_create();
+  animate_fish();
+
   /* set up watching the event pipe */
   {
     GIOChannel *channel = g_io_channel_unix_new (eventpipe[0]);
-    guint id;
-
     g_io_channel_set_encoding (channel, NULL, NULL);
     g_io_channel_set_buffered (channel, FALSE);
     g_io_channel_set_close_on_unref (channel, TRUE);
-
-    id = g_io_add_watch (channel, G_IO_IN, async_event_handle, &p);
-
+    g_io_add_watch (channel, G_IO_IN, async_event_handle, NULL);
     g_io_channel_unref (channel);
+  }
 
-  }
-  
   /* we want to be running by default */
-  {
-    pthread_t thread_id;
-    animate_fish(&p);
-    process_active=1;
-    pthread_create(&thread_id,NULL,&process_thread,NULL);
-  }
-
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(run),TRUE);
   gtk_main ();
 
 }

Modified: trunk/spectrum/spec_plot.c
===================================================================
--- trunk/spectrum/spec_plot.c	2012-06-02 16:38:29 UTC (rev 18348)
+++ trunk/spectrum/spec_plot.c	2012-06-03 01:22:50 UTC (rev 18349)
@@ -29,9 +29,9 @@
 #include "spec_plot.h"
 
 static double log_lfreqs[5]={10.,100.,1000.,10000.,100000};
-static double log_llfreqs[15]={10.,20.,30.,50.,100.,200.,300.,500.,
+static double log_llfreqs[16]={10.,20.,30.,50.,100.,200.,300.,500.,
                               1000.,2000.,3000.,5000.,10000.,
-                              20000.,30000.};
+                               20000.,30000.,50000.};
 static double log_tfreqs[37]={5.,6.,7.,8.,9.,20.,30.,40.,50.,60.,70.,80.,90.
 			 ,200.,300.,400.,500.,600.,700.,800.,900.,
 			 2000.,3000.,4000.,5000.,6000.,7000.,8000.,9000.,
@@ -45,68 +45,25 @@
 
 static GtkDrawingAreaClass *parent_class = NULL;
 
-static void compute_imp_scale(GtkWidget *widget){
-  Plot *p=PLOT(widget);
-  int height=widget->allocation.height-p->pady;
-  int i;
-  double lfreqs[9]={10000000.,1000000.,100000.,10000.,1000.,100.,10.,1.,.1};
-  double tfreqs[64]={9000000.,8000000.,7000000.,6000000.,
-		     5000000.,4000000.,3000000.,2000000.,
-		     900000.,800000.,700000.,600000.,
-		     500000.,400000.,300000.,200000.,
-		     90000.,80000.,70000.,60000.,
-		     50000.,40000.,30000.,20000.,
-		     9000.,8000.,7000.,6000.,
-		     5000.,4000.,3000.,2000.,
-		     900.,800.,700.,600.,
-		     500.,400.,300.,200.,
-		     90.,80.,70.,60.,
-		     50.,40.,30.,20,
-		     9.,8.,7.,6.,
-		     5.,4.,3.,2.,
-		     .9,.8,.7,.6,
-		     .5,.4,.3,.2};
+static void compute_xgrid(Plot *p, fetchdata *f){
+  if(p->maxrate!=f->maxrate || p->scale!=f->scale || p->width != f->width){
+    GtkWidget *widget=GTK_WIDGET(p);
+    int width = widget->allocation.width-p->padx-(f->phase_active?p->phax:0);
+    int nyq=f->maxrate/2.;
+    int i,j;
 
-  for(i=0;i<9;i++)
-    p->ygrid[i]=rint( (log10(p->ymax)-log10(lfreqs[i]))/(log10(p->ymax)-log10(.1)) * (height-1));
-  for(i=0;i<64;i++)
-    p->ytic[i]=rint( (log10(p->ymax)-log10(tfreqs[i]))/(log10(p->ymax)-log10(.1)) * (height-1));
-  p->ygrids=9;
-  p->ytics=64;
+    p->xgrids=0;
+    p->xtics=0;
 
-}
+    /* find the places to plot the x grid lines according to scale */
+    switch(f->scale){
+    case 0: /* log */
 
-int phase_active_p(Plot *p){
-  if(p->link == LINK_PHASE){
-    int cho=0;
-    int gi;
-    for(gi=0;gi<p->groups;gi++)
-      if(p->ch[gi]>1 && p->ch_active[cho+1])
-        return 1;
-  }
-  return 0;
-}
-
-static void compute_metadata(GtkWidget *widget){
-  Plot *p=PLOT(widget);
-  int phase = phase_active_p(p);
-  int width = widget->allocation.width-p->padx-(phase?p->phax:0);
-  int rate=p->maxrate;
-  int nyq=p->maxrate/2.;
-  int i;
-
-  p->xgrids=0;
-  p->xtics=0;
-
-  /* find the places to plot the x grid lines according to scale */
-  switch(p->scale){
-  case 0: /* log */
-    {
       for(i=0;i<5;i++){
         if(log_lfreqs[i]<(nyq-.1))
           p->xgrids=i+1;
       }
-      for(i=0;i<15;i++){
+      for(i=0;i<16;i++){
         if(log_llfreqs[i]<(nyq-.1))
           p->xlgrids=i+1;
       }
@@ -116,18 +73,17 @@
       }
 
       for(i=0;i<p->xgrids;i++)
-	p->xgrid[i]=rint( (log10(log_lfreqs[i])-log10(5.))/(log10(nyq)-log10(5.)) * (width-1))+p->padx;
+        p->xgrid[i]=rint( (log10(log_lfreqs[i])-log10(5.))/(log10(nyq)-log10(5.)) * (width-1))+p->padx;
       for(i=0;i<p->xlgrids;i++)
-	p->xlgrid[i]=rint( (log10(log_llfreqs[i])-log10(5.))/(log10(nyq)-log10(5.)) * (width-1))+p->padx;
+        p->xlgrid[i]=rint( (log10(log_llfreqs[i])-log10(5.))/(log10(nyq)-log10(5.)) * (width-1))+p->padx;
       for(i=0;i<p->xtics;i++)
-	p->xtic[i]=rint( (log10(log_tfreqs[i])-log10(5.))/(log10(nyq)-log10(5.)) * (width-1))+p->padx;
-    }
+        p->xtic[i]=rint( (log10(log_tfreqs[i])-log10(5.))/(log10(nyq)-log10(5.)) * (width-1))+p->padx;
 
-    break;
-  case 1: /* ISO log */
-    {
+      break;
+    case 1: /* ISO log */
+
       for(i=0;i<12;i++){
-       if(iso_lfreqs[i]<(nyq-.1)){
+        if(iso_lfreqs[i]<(nyq-.1)){
           p->xgrids=i+1;
           p->xlgrids=i+1;
         }
@@ -138,15 +94,30 @@
       }
 
       for(i=0;i<p->xgrids;i++)
-	p->xgrid[i]=p->xlgrid[i]=rint( (log2(iso_lfreqs[i])-log2(25.))/(log2(nyq)-log2(25.)) * (width-1))+p->padx;
+        p->xgrid[i]=p->xlgrid[i]=rint( (log2(iso_lfreqs[i])-log2(25.))/(log2(nyq)-log2(25.)) * (width-1))+p->padx;
       for(i=0;i<p->xtics;i++)
-	p->xtic[i]=rint( (log2(iso_tfreqs[i])-log2(25.))/(log2(nyq)-log2(25.)) * (width-1))+p->padx;
-    }
+        p->xtic[i]=rint( (log2(iso_tfreqs[i])-log2(25.))/(log2(nyq)-log2(25.)) * (width-1))+p->padx;
 
-    break;
-  case 2: /* linear spacing */
-    {
-      int j;
+      break;
+    case 2: /* linear spacing */
+
+      if(f->maxrate > 100000){
+        p->lin_major = 10000.;
+        p->lin_minor = 2000.;
+        p->lin_mult = 5;
+        p->lin_layout = p->lin_layout_200;
+      }else if(f->maxrate > 50000){
+        p->lin_major = 5000.;
+        p->lin_minor = 1000.;
+        p->lin_mult = 5;
+        p->lin_layout = p->lin_layout_100;
+      }else{
+        p->lin_major=2000.;
+        p->lin_minor=500.;
+        p->lin_mult=4;
+        p->lin_layout = p->lin_layout_50;
+      }
+
       for(i=0;;i++){
         if(i*p->lin_major >= nyq-.1 || i*p->lin_major>=100000-.1)
           break;
@@ -171,8 +142,8 @@
         lfreq=j*p->lin_minor;
         p->xtic[i]=rint(lfreq/nyq * (width-1))+p->padx;
       }
+      break;
     }
-    break;
   }
 }
 
@@ -220,27 +191,27 @@
   return rgb;
 }
 
-static void draw(GtkWidget *widget){
+void plot_draw(Plot *p, fetchdata *f, plotparams *pp){
   int i;
-  Plot *p=PLOT(widget);
+  GtkWidget *widget=GTK_WIDGET(p);
+  GtkWidget *parent=gtk_widget_get_parent(widget);
   int height=widget->allocation.height;
   int width=widget->allocation.width;
-  GtkWidget *parent=gtk_widget_get_parent(widget);
-#if 0
-  int impedence = (p->link == LINK_IMPEDENCE_p1 ||
-		   p->link == LINK_IMPEDENCE_1 ||
-		   p->link == LINK_IMPEDENCE_10);
-#endif
-  int phase = phase_active_p(p);
+
+  if(!GDK_IS_DRAWABLE(p->backing))return;
+  if(!pp)return;
+  if(!f)return;
+
+  int phase = f->phase_active;
   int padx = p->padx;
   int phax = phase ? p->phax : 0;
   int pwidth = width - padx - phax;
 
+  /* lazy GC init */
   if(!p->drawgc){
     p->drawgc=gdk_gc_new(p->backing);
     gdk_gc_copy(p->drawgc,widget->style->black_gc);
   }
-
   if(!p->dashes){
     p->dashes=gdk_gc_new(p->backing);
     gdk_gc_copy(p->dashes, p->drawgc);
@@ -268,10 +239,10 @@
     gdk_gc_set_line_attributes(p->phasegc,1,GDK_LINE_SOLID,GDK_CAP_PROJECTING,GDK_JOIN_MITER);
   }
 
+  /* set clip rectangle */
   {
     const GdkRectangle clip = {p->padx,0,pwidth,height-p->pady};
     GdkGCValues values;
-    //gdk_gc_get_values(p->drawgc,&values);
     values.line_width=1;
     gdk_gc_set_values(p->drawgc,&values,GDK_GC_LINE_WIDTH);
     gdk_gc_set_clip_rectangle (p->drawgc, &clip);
@@ -289,24 +260,12 @@
     gdk_draw_rectangle(p->backing,gc,1,padx,0,pwidth,height-p->pady);
   }
 
-  /* draw the noise floor if active */
-  #if 0
-  if(p->floor){
-    GdkColor rgb = {0,0xd000,0xd000,0xd000};
-    gdk_gc_set_rgb_fg_color(p->drawgc,&rgb);
+  compute_xgrid(p,f);
+  p->maxrate=f->maxrate;
+  p->scale=f->scale;
+  p->phase_active=f->phase_active;
+  p->width=f->width;
 
-    for(i=0;i<pwidth;i++){
-      float val=p->floor[i];
-      int y;
-
-      /* No noise floor is passed back for display in the modes where it's irrelevant */
-      y= rint((height-p->pady-1)/p->depth*(p->ymax-val));
-      if(y<height-p->pady)
-	gdk_draw_line(p->backing,p->drawgc,padx+i,y,padx+i,height-p->pady-1);
-    }
-  }
-  #endif
-
   /* draw the light x grid */
   {
     int i;
@@ -318,10 +277,11 @@
     gdk_gc_set_rgb_fg_color(p->drawgc,&rgb);
 
     for(i=0;i<p->xtics;i++)
-      gdk_draw_line(p->backing,p->drawgc,p->xtic[i],0,p->xtic[i],height-p->pady);
+      gdk_draw_line(p->backing,p->drawgc,p->xtic[i],0,
+                    p->xtic[i],height-p->pady);
   }
 
-    /* draw the x labels */
+  /* draw the x labels */
   {
     PangoLayout **proper;
     switch(p->scale){
@@ -348,46 +308,11 @@
   }
 
   /* draw the y grid */
-  //if(impedence){ /* impedence mode */
-  if(0){
-
-    /* light grid */
-
+  {
     GdkColor rgb={0,0,0,0};
-    rgb.red=0xc000;
-    rgb.green=0xff00;
-    rgb.blue=0xff00;
-    gdk_gc_set_rgb_fg_color(p->drawgc,&rgb);
-
-    compute_imp_scale(widget);
-
-    for(i=0;i<p->ytics;i++)
-      gdk_draw_line(p->backing,p->drawgc,padx,p->ytic[i],pwidth,p->ytic[i]);
-
-    /* dark grid */
-    rgb.red=0x0000;
-    rgb.green=0xc000;
-    rgb.blue=0xc000;
-
-    gdk_gc_set_rgb_fg_color(p->drawgc,&rgb);
-
-    for(i=0;i<p->ygrids;i++){
-      int px,py;
-      pango_layout_get_pixel_size(p->imp_layout[i],&px,&py);
-
-      gdk_draw_layout (p->backing,
-		       widget->style->black_gc,
-		       padx-px-2, p->ygrid[i]-py/2,
-		       p->imp_layout[i]);
-
-      gdk_draw_line(p->backing,p->drawgc,padx,p->ygrid[i],pwidth,p->ygrid[i]);
-    }
-
-  }else{
-    GdkColor rgb={0,0,0,0};
     float emheight = (height-p->pady)/p->pady;
-    float emperdB = emheight/p->depth;
-    float pxperdB = (height-p->pady)/p->depth;
+    float emperdB = emheight/pp->depth;
+    float pxperdB = (height-p->pady)/pp->depth;
 
     /* we want no more than <n> major lines per graph */
     int maxmajorper = 15;
@@ -411,7 +336,7 @@
       /* minimum em seperation? */
       if(emperdB>majorsep*majordeltest[i] &&
          /* Not over the number of lines limit? */
-         p->depth*majordeltest[i]<maxmajorper){
+         pp->depth*majordeltest[i]<maxmajorper){
         majordel=majordellist[i];
         break;
       }
@@ -419,9 +344,11 @@
 
     /* choose appropriate minor and subminor spacing */
     int minordellist[]=
-      { 10,  25,  50,  100, 250, 500, 1000, 2500, 5000, 10000, 25000, -1, -1};
+      { 10,  25,  50,  100, 250, 500, 1000, 2500, 5000,
+        10000, 25000, -1, -1};
     float minordeltest[]=
-      {100,  40,  20,   10,   4,   2,    1,   .4,   .2,   .1,    .04, -1, -1};
+      {100,  40,  20,   10,   4,   2,    1,   .4,   .2,
+       .1,    .04, -1, -1};
 
     for(i=0;minordellist[i]>0;i++){
       /* minimum px seperation? */
@@ -448,18 +375,18 @@
       }
     }
 
-    /* Light Y grid */
+    /* draw the light Y grid */
     rgb.red=0xc000;
     rgb.green=0xff00;
     rgb.blue=0xff00;
     gdk_gc_set_rgb_fg_color(p->drawgc,&rgb);
     gdk_gc_set_rgb_fg_color(p->dashes,&rgb);
 
-    float ymin = (p->ymax - p->depth)*1000;
-    int yval = rint((p->ymax*1000/subminordel)+1)*subminordel;
+    float ymin = (pp->ymax - pp->depth)*1000;
+    int yval = rint((pp->ymax*1000/subminordel)+1)*subminordel;
 
     while(1){
-      float ydel = (yval - ymin)/(p->depth*1000);
+      float ydel = (yval - ymin)/(pp->depth*1000);
       int ymid = rint(height-p->pady-1 - (height-p->pady) * ydel);
 
       if(ymid>=height-p->pady)break;
@@ -475,14 +402,14 @@
       yval-=subminordel;
     }
 
-    /* Dark Y grid */
+    /* draw the dark Y grid */
     rgb.red=0x0000;
     rgb.green=0xc000;
     rgb.blue=0xc000;
     gdk_gc_set_rgb_fg_color(p->drawgc,&rgb);
 
-    ymin = (p->ymax - p->depth)*1000;
-    yval = rint((p->ymax*1000/majordel)+1)*majordel;
+    ymin = (pp->ymax - pp->depth)*1000;
+    yval = rint((pp->ymax*1000/majordel)+1)*majordel;
 
     {
       int px,py,pxdB,pxN,pxMAX;
@@ -492,25 +419,25 @@
       pxMAX+=pxdB;
 
       while(1){
-        float ydel = (yval - ymin)/(p->depth*1000);
+        float ydel = (yval - ymin)/(pp->depth*1000);
         int ymid = rint(height-p->pady-1 - (height-p->pady) * ydel);
 
         if(ymid>=height-p->pady)break;
 
         if(ymid>=0){
-          int do_dB=0;
           int label = yval/100+2000;
 
           if(label>=0 && label<=4000 /* in range check */
-             && (p->scale<2 || ymid+py/2 < height-p->pady) /* don't collide with DC label */
+             && (p->scale<2 || ymid+py/2 < height-p->pady)
+             /* don't collide with DC label */
              ){
 
             if(label%10){ /* fractional (decimal) dB */
               int sofar=0;
               /*  -.9dB
-                 -9.9dB
+                  -9.9dB
                   -99.9
-                 -999.9 */
+                  -999.9 */
 
               if(fabsf(yval*.001)<9.98){
                 gdk_draw_layout (p->backing,
@@ -565,7 +492,7 @@
     }
   }
 
-  /* dark x grid */
+  /* draw the dark x grid */
   {
     int i;
     GdkColor rgb={0,0,0,0};
@@ -576,84 +503,74 @@
     gdk_gc_set_rgb_fg_color(p->drawgc,&rgb);
 
     for(i=0;i<p->xgrids;i++)
-      gdk_draw_line(p->backing,p->drawgc,p->xgrid[i],0,p->xgrid[i],height-p->pady);
+      gdk_draw_line(p->backing,p->drawgc,p->xgrid[i],0,
+                    p->xgrid[i],height-p->pady);
   }
 
 
-  gdk_gc_set_line_attributes(p->drawgc,p->bold+1,GDK_LINE_SOLID,GDK_CAP_PROJECTING,
-                             GDK_JOIN_MITER);
+  gdk_gc_set_line_attributes(p->drawgc,pp->bold+1,GDK_LINE_SOLID,
+                             GDK_CAP_PROJECTING, GDK_JOIN_MITER);
 
   /* draw actual data */
-  if(p->ydata){
+  if(f->data){
     int cho=0;
     int gi;
-    for(gi=0;gi<p->groups;gi++){
+    for(gi=0;gi<f->groups;gi++){
       int ch;
       GdkColor rgb;
 
-      for(ch=cho;ch<cho+p->ch[gi];ch++){
-	if(p->ch_active[ch]){
+      for(ch=cho;ch<cho+f->channels[gi];ch++){
+        if(f->active[ch]){
 
-	  rgb = chcolor(ch);
-	  gdk_gc_set_rgb_fg_color(p->drawgc,&rgb);
+          rgb = chcolor(ch);
+          gdk_gc_set_rgb_fg_color(p->drawgc,&rgb);
 
-	  for(i=0;i<pwidth;i++){
-	    float valmin=p->ydata[ch][i*2];
-	    float valmax=p->ydata[ch][i*2+1];
+          for(i=0;i<pwidth;i++){
+            float valmin=f->data[ch][i*2];
+            float valmax=f->data[ch][i*2+1];
             float ymin, ymax;
 
             if(!isnan(valmin) && !isnan(valmax)){
 
-              //if(impedence){ /* log scale for impedence */
-              if(0){
+              if(phase && ch==cho+1){
 
-                ymin = rint( (log10(p->ymax)-log10(valmin))/
-                             (log10(p->ymax)-log10(.1)) *
-                             (height-p->pady-1));
-                ymax = rint( (log10(p->ymax)-log10(valmax))/
-                             (log10(p->ymax)-log10(.1)) *
-                             (height-p->pady-1));
-
-              }else if(phase && ch==cho+1){
-
                 ymin = rint((height-p->pady-1)/
-                            (p->pmax-p->pmin)*
-                            (p->pmax-valmin));
+                            (pp->pmax-pp->pmin)*
+                            (pp->pmax-valmin));
                 ymax = rint((height-p->pady-1)/
-                            (p->pmax-p->pmin)*
-                            (p->pmax-valmax));
+                            (pp->pmax-pp->pmin)*
+                            (pp->pmax-valmax));
 
               }else{
 
-                ymin = rint((height-p->pady-1)/p->depth*(p->ymax-valmin));
-                ymax = rint((height-p->pady-1)/p->depth*(p->ymax-valmax));
+                ymin = rint((height-p->pady-1)/pp->depth*(pp->ymax-valmin));
+                ymax = rint((height-p->pady-1)/pp->depth*(pp->ymax-valmax));
 
               }
 
               gdk_draw_line(p->backing,p->drawgc,padx+i,ymin,padx+i,ymax);
             }
-	  }
-	}
+          }
+        }
       }
-      cho+=p->ch[gi];
+      cho+=f->channels[gi];
     }
   }
 
-  /* phase?  draw in phase and tics on right axis */
+  /* draw in phase labels and tics on right axis */
+  /* currently messy as hell cut&paste spaghetti, but working */
   if(phase){
-    float depth = p->pmax-p->pmin;
-    int label=ceil(p->pmax/10+18),i;
-    float del=(height-p->pady-1)/depth,step;
-    float off=p->pmax-ceil(p->pmax*.1)*10;
-    step=2;
-    if(del>8)step=1;
+    float depth = pp->pmax-pp->pmin;
+    float del=(height-p->pady-1)/depth;
+    float off=pp->pmax-ceil(pp->pmax*.1)*10;
 
     for(i=0;;i++){
       int ymid=rint(del * (i*10+off));
-      int pv = rint((p->pmax - ymid/(float)(height-p->pady) * (p->pmax - p->pmin))/10);
+      int pv = rint((pp->pmax - ymid/(float)(height-p->pady) *
+                     (pp->pmax - pp->pmin))/10);
       if(ymid>=height-p->pady)break;
       if(ymid>=0 && pv>=-18 && pv<=18 && (pv&1)==0){
-	int px,py;
+        int px,py;
         pango_layout_get_pixel_size(p->phase_layout[pv+18],&px,&py);
         gdk_draw_layout (p->backing,p->phasegc,
                          width-p->phax+2, ymid-py/2,
@@ -663,78 +580,86 @@
 
     if(del>10){
       for(i=0;;i++){
-	int ymid=rint(del * (i+off));
-        int pv = rint(p->pmax - ymid/(float)(height-p->pady) * (p->pmax - p->pmin));
-	if(ymid>=height-p->pady)break;
-	if(ymid>=0 && pv>=-180 && pv<=180)
-	  gdk_draw_line(p->backing,p->phasegc,width-p->phax-(i%5==0?15:10),ymid,width-p->phax-(i%5==0?5:7),ymid);
+        int ymid=rint(del * (i+off));
+        int pv = rint(pp->pmax - ymid/(float)(height-p->pady) *
+                      (pp->pmax - pp->pmin));
+        if(ymid>=height-p->pady)break;
+        if(ymid>=0 && pv>=-180 && pv<=180)
+          gdk_draw_line(p->backing,p->phasegc,width-p->phax-(i%5==0?15:10),
+                        ymid,width-p->phax-(i%5==0?5:7),ymid);
       }
     }else if(del>5){
       for(i=0;;i++){
-	int ymid=rint(del * (i*2+off));
-        int pv = rint(p->pmax - ymid/(float)(height-p->pady) * (p->pmax - p->pmin));
-	if(ymid>=height-p->pady)break;
-	if(ymid>=0 && pv>=-180 && pv<=180)
-	  gdk_draw_line(p->backing,p->phasegc,width-p->phax-12,ymid,width-p->phax-7,ymid);
+        int ymid=rint(del * (i*2+off));
+        int pv = rint(pp->pmax - ymid/(float)(height-p->pady) *
+                      (pp->pmax - pp->pmin));
+        if(ymid>=height-p->pady)break;
+        if(ymid>=0 && pv>=-180 && pv<=180)
+          gdk_draw_line(p->backing,p->phasegc,width-p->phax-12,ymid,
+                        width-p->phax-7,ymid);
       }
     } else if(del>2){
       for(i=0;;i++){
-	int ymid=rint(del * (i*5+off));
-        int pv = rint(p->pmax - ymid/(float)(height-p->pady) * (p->pmax - p->pmin));
-	if(ymid>=height-p->pady)break;
-	if(ymid>=0 && pv>=-180 && pv<=180)
-	  gdk_draw_line(p->backing,p->phasegc,width-p->phax-15,ymid,width-p->phax-5,ymid);
+        int ymid=rint(del * (i*5+off));
+        int pv = rint(pp->pmax - ymid/(float)(height-p->pady) *
+                      (pp->pmax - pp->pmin));
+        if(ymid>=height-p->pady)break;
+        if(ymid>=0 && pv>=-180 && pv<=180)
+          gdk_draw_line(p->backing,p->phasegc,width-p->phax-15,ymid,
+                        width-p->phax-5,ymid);
       }
     }
 
     if(del>=2){
       for(i=0;;i++){
         int ymid=rint(del * (i*10+off));
-        int pv = rint(p->pmax - ymid/(float)(height-p->pady) * (p->pmax - p->pmin));
+        int pv = rint(pp->pmax - ymid/(float)(height-p->pady) *
+                      (pp->pmax - pp->pmin));
         if(ymid>=height-p->pady)break;
-	if(ymid>=0 && pv>=-180 && pv<=180){
-          gdk_draw_line(p->backing,p->phasegc,width-p->phax-5,ymid-1,width-p->phax-1,ymid-1);
-          gdk_draw_line(p->backing,p->phasegc,width-p->phax-25,ymid,width-p->phax-1,ymid);
-          gdk_draw_line(p->backing,p->phasegc,width-p->phax-5,ymid+1,width-p->phax-1,ymid+1);
+        if(ymid>=0 && pv>=-180 && pv<=180){
+          gdk_draw_line(p->backing,p->phasegc,width-p->phax-5,ymid-1,
+                        width-p->phax-1,ymid-1);
+          gdk_draw_line(p->backing,p->phasegc,width-p->phax-25,ymid,
+                        width-p->phax-1,ymid);
+          gdk_draw_line(p->backing,p->phasegc,width-p->phax-5,ymid+1,
+                        width-p->phax-1,ymid+1);
         }
       }
     }else{
 
       for(i=0;;i++){
-	int ymid=rint(del * (i*10+off));
-        int pv = rint(p->pmax - ymid/(float)(height-p->pady) * (p->pmax - p->pmin));
-	if(ymid>=height-p->pady)break;
-	if(ymid>=0 && pv>=-180 && pv<=180)
-	  gdk_draw_line(p->backing,p->phasegc,width-p->phax-15,ymid,width-p->phax-5,ymid);
+        int ymid=rint(del * (i*10+off));
+        int pv = rint(pp->pmax - ymid/(float)(height-p->pady) *
+                      (pp->pmax - pp->pmin));
+        if(ymid>=height-p->pady)break;
+        if(ymid>=0 && pv>=-180 && pv<=180)
+          gdk_draw_line(p->backing,p->phasegc,width-p->phax-15,ymid,
+                        width-p->phax-5,ymid);
       }
 
       for(i=0;;i++){
         int ymid=rint(del * (i*10+off));
-        int pv = rint((p->pmax - ymid/(float)(height-p->pady) * (p->pmax - p->pmin))/10);
+        int pv = rint((pp->pmax - ymid/(float)(height-p->pady) *
+                       (pp->pmax - pp->pmin))/10);
         if(ymid>=height-p->pady)break;
-	if(ymid>=0 && pv>=-18 && pv<=18 && (pv&1)==0){
-          gdk_draw_line(p->backing,p->phasegc,width-p->phax-5,ymid-1,width-p->phax-1,ymid-1);
-          gdk_draw_line(p->backing,p->phasegc,width-p->phax-25,ymid,width-p->phax-1,ymid);
-          gdk_draw_line(p->backing,p->phasegc,width-p->phax-5,ymid+1,width-p->phax-1,ymid+1);
+        if(ymid>=0 && pv>=-18 && pv<=18 && (pv&1)==0){
+          gdk_draw_line(p->backing,p->phasegc,width-p->phax-5,ymid-1,
+                        width-p->phax-1,ymid-1);
+          gdk_draw_line(p->backing,p->phasegc,width-p->phax-25,ymid,
+                        width-p->phax-1,ymid);
+          gdk_draw_line(p->backing,p->phasegc,width-p->phax-5,ymid+1,
+                        width-p->phax-1,ymid+1);
         }
       }
     }
   }
-}
 
-static void draw_and_expose(GtkWidget *widget){
-  Plot *p=PLOT(widget);
-  if(!GDK_IS_DRAWABLE(p->backing))return;
-  draw(widget);
-  if(!GTK_WIDGET_DRAWABLE(widget))return;
-  if(!GDK_IS_DRAWABLE(widget->window))return;
   gdk_draw_drawable(widget->window,
-		    widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
-		    p->backing,
-		    0, 0,
-		    0, 0,
-		    widget->allocation.width,
-		    widget->allocation.height);
+                    widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+                    p->backing,
+                    0, 0,
+                    0, 0,
+                    width, height);
 }
 
 static gboolean expose( GtkWidget *widget, GdkEventExpose *event ){
@@ -759,15 +684,14 @@
   {
     int max=0;
     int maxy=0;
-    for(i=0;p->lin_layout[i];i++){
-      if(p->lin_major*i >= p->maxrate/2-.1)break;
-      pango_layout_get_pixel_size(p->lin_layout[i],&px,&py);
+    for(i=0;p->lin_layout_50[i];i++){
+      pango_layout_get_pixel_size(p->lin_layout_50[i],&px,&py);
       if(px>max)max=px;
       if(py>pady)pady=py;
       if(py>maxy)maxy=py;
     }
-    max+=maxy*1.5;
     max*=i+1;
+    max+=maxy*1.5;
     if(axisx<max)axisx=max;
   }
   /* find max log layout */
@@ -775,14 +699,13 @@
     int max=0;
     int maxy=0;
     for(i=0;p->log_layout[i];i++){
-      if(log_lfreqs[i] >= p->maxrate/2-.1)break;
       pango_layout_get_pixel_size(p->log_layout[i],&px,&py);
       if(px>max)max=px;
       if(py>pady)pady=py;
       if(py>maxy)maxy=py;
     }
+    max*=(i+1);
     max+=maxy*1.5;
-    max*=(i+1)*3;
     if(axisx<max)axisx=max;
   }
   /* find max iso layout */
@@ -790,18 +713,16 @@
     int max=0;
     int maxy=0;
     for(i=0;p->iso_layout[i];i++){
-      if(iso_lfreqs[i] >= p->maxrate/2-.1)break;
       pango_layout_get_pixel_size(p->iso_layout[i],&px,&py);
       if(px>max)max=px;
       if(py>pady)pady=py;
       if(py>maxy)maxy=py;
     }
-    max+=maxy*1.5;
     max*=i+1;
+    max+=maxy*1.5;
     if(axisx<max)axisx=max;
   }
 
-
   /* find max db layout */
   {
     int max=0;
@@ -812,20 +733,6 @@
     axisy=(max)*8;
     if(axisy<max)axisy=max;
   }
-  /* find max imped layout */
-#if 0
-  {
-    int max=0;
-    for(i=0;p->imp_layout[i];i++){
-      pango_layout_get_pixel_size(p->imp_layout[i],&px,&py);
-      //if(py>max)max=py;
-      if(px>padx)padx=px;
-    }
-    axisy=(max)*8;
-    if(axisy<max)axisy=max;
-  }
-#endif
-
   /* find max phase layout */
   {
     int max=0;
@@ -845,173 +752,8 @@
   p->phax=phax+2;
 }
 
-
-static void filter_reset(pole2 *p, double val){
-  p->x[0]=p->x[1]=val;
-  p->y[0]=p->y[1]=val;
-}
-
-static void filter_make_critical(double w, pole2 *f){
-  double w0 = tan(M_PI*w*pow(pow(2,.5)-1,-.5));
-  f->a  = w0*w0/(1+(2*w0)+w0*w0);
-  f->b1 = 2*f->a*(1/(w0*w0)-1);
-  f->b2 = 1-(4*f->a+f->b1);
-  filter_reset(f,0);
-}
-
-static double filter_filter(double x, pole2 *p){
-  double y =
-    p->a*x + 2*p->a*p->x[0] + p->a*p->x[1] +
-    p->b1*p->y[0] + p->b2*p->y[1];
-  p->y[1] = p->y[0]; p->y[0] = y;
-  p->x[1] = p->x[0]; p->x[0] = x;
-  return y;
-}
-
-#define THRESH .25
-#define TIMERFRAMES 20
-
-void plot_rescale (Plot *p, int request_reset){
-  float ymax,pmax,pmin;
-  int phase = phase_active_p(p);
-  int width=GTK_WIDGET(p)->allocation.width-p->padx-(phase ? p->phax : 0);
-  int height=GTK_WIDGET(p)->allocation.height-p->pady;
-  float **data;
-
-  if(!p->configured)return;
-
-  data = process_fetch(p->scale, p->mode, p->link,
-		       p->ch_process,width,&ymax,&pmax,&pmin);
-
-  p->ydata=data;
-
-  if(!p->autoscale) return;
-
-  /* graph limit updates are conditional depending on mode/link */
-  switch(p->link){
-  case LINK_INDEPENDENT:
-  case LINK_SUMMED:
-  case LINK_PHASE:
-    {
-      float dBpp = p->depth/height;
-      ymax += dBpp*25;
-    }
-    break;
-  }
-
-  if(ymax<p->depth-p->ymax_limit)ymax=p->depth-p->ymax_limit;
-  if(ymax>p->ymax_limit)ymax=p->ymax_limit;
-
-  pmax+=10;
-  pmin-=10;
-  if(pmax<5)pmax=5;
-  if(pmax>190)pmax=190;
-  if(pmin>-20)pmin=-20;
-  if(pmin<-190)pmin=-190;
-
-  /* phase/response zeros align on phase graphs; verify targets
-     against phase constraints */
-  if(phase){
-    float pzero,mzero = height/p->depth*ymax;
-
-    /* move mag zero back onscreen if it's off */
-    if(mzero < height*THRESH){
-      ymax = (p->depth*height*THRESH)/height;
-    }
-    if(mzero > height*(1-THRESH)){
-      ymax = (p->depth*height*(1-THRESH))/height;
-    }
-
-    mzero = height/p->depth*ymax;
-    pzero = height/(pmax-pmin)*pmax;
-
-    if(mzero<pzero){
-      /* straightforward; move the dB range down */
-      ymax = pzero*p->depth/height;
-    }else{
-      /* a little harder as phase has a min and a max.
-         First increase the pmax to match the dB zero. */
-
-      pmax = pmin/(1-height/mzero);
-      pzero = height/(pmax-pmin)*pmax;
-
-      /* That worked, but might have run p->max overrange */
-      if(pmax>190.){
-        /* reconcile by allowing mag to overrange */
-        pmax = 190.;
-        pzero = height/(pmax-pmin)*pmax;
-        ymax = p->depth*pzero/height;
-        p->ymaxtimer=0;
-      }
-    }
-  }
-
-  if(request_reset){
-    p->ymax=p->ymax_target=ymax;
-    filter_reset(&p->ymax_damp,p->ymax);
-    p->ymaxtimer=TIMERFRAMES;
-
-    if(phase){
-      p->pmax=p->pmax_target=pmax;
-      p->pmin=p->pmin_target=pmin;
-      filter_reset(&p->pmax_damp,p->pmax);
-      filter_reset(&p->pmin_damp,p->pmin);
-      p->pmaxtimer=TIMERFRAMES;
-      p->pmintimer=TIMERFRAMES;
-    }
-
-  }else{
-    /* conditionally set new damped ymax target */
-    if(p->ymaxtimer>0 && ymax < p->ymax*(1-THRESH))
-      p->ymaxtimer--;
-
-    if(ymax > p->ymax_target){
-      p->ymax_target=ymax;
-      p->ymaxtimer=TIMERFRAMES;
-    }
-
-    if(p->ymaxtimer<=0)
-      p->ymax_target=ymax;
-
-    /* update ymax through scale damping filter */
-    p->ymax = filter_filter(p->ymax_target,&p->ymax_damp);
-
-    /* apply same hyteresis and update to phase */
-    if(phase){
-
-      if(p->pmaxtimer>0 && pmax < p->pmax*(1-THRESH))
-        p->pmaxtimer--;
-      if(pmax > p->pmax_target){
-        p->pmax_target=pmax;
-        p->pmaxtimer=TIMERFRAMES;
-      }
-      if(p->pmaxtimer<=0)
-        p->pmax_target=pmax;
-      p->pmax = filter_filter(p->pmax_target,&p->pmax_damp);
-
-      if(p->pmintimer>0 && pmin > p->pmin*(1-THRESH))
-        p->pmintimer--;
-      if(pmin < p->pmin_target){
-        p->pmin_target=pmin;
-        p->pmintimer=TIMERFRAMES;
-      }
-      if(p->pmintimer<=0)
-        p->pmin_target=pmin;
-      p->pmin = filter_filter(p->pmin_target,&p->pmin_damp);
-    }
-  }
-
-  if(phase){
-    /* when phase is active, the p->ymax in use is dictated by
-       p->pmax/p->pmin, which in turn already took the desired ymax
-       into consideration above */
-    p->ymax = p->depth*p->pmax/(p->pmax-p->pmin);
-  }
-}
-
 static gboolean configure(GtkWidget *widget, GdkEventConfigure *event){
   Plot *p=PLOT(widget);
-  int rescale = !p->configured;
   if (p->backing)
     g_object_unref(p->backing);
 
@@ -1019,20 +761,13 @@
 			      widget->allocation.width,
 			      widget->allocation.height,
 			      -1);
-  p->ydata=NULL;
   p->configured=1;
-
-  compute_metadata(widget);
-  plot_rescale(p,rescale);
-  draw_and_expose(widget);
-
+  replot(0,0,0);
   return TRUE;
 }
 
 static void plot_class_init (PlotClass *class){
-  int i,w,h;
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
-  GdkWindow *root=gdk_get_default_root_window();
   parent_class = g_type_class_peek_parent (class);
 
   widget_class->expose_event = expose;
@@ -1041,9 +776,6 @@
 }
 
 static void plot_init (Plot *p){
-  p->mode=0;
-  p->scale=0;
-  p->depth=45.;
 }
 
 GType plot_get_type (void){
@@ -1062,67 +794,62 @@
       0
     };
 
-    m_type = g_type_register_static (GTK_TYPE_DRAWING_AREA, "Plot", &m_info, 0);
+    m_type = g_type_register_static (GTK_TYPE_DRAWING_AREA, "Plot",
+                                     &m_info, 0);
   }
 
   return m_type;
 }
 
-GtkWidget* plot_new (int size, int groups, int *channels, int *rate){
+GtkWidget* plot_new (void){
   GtkWidget *ret= GTK_WIDGET (g_object_new (plot_get_type (), NULL));
   Plot *p=PLOT(ret);
-  int g,i;
-  int ch=0;
-  int maxrate=-1;
-  p->groups = groups;
-  for(g=0;g<groups;g++){
-    ch+=channels[g];
-    if(rate[g]>maxrate)maxrate=rate[g];
+  int i;
+
+  /* generate all the text layouts we'll need */
+  /* linear X scale */
+  {
+    char *labels[10]={"DC","10kHz","20kHz","30kHz","40kHz","50kHz","60kHz",
+                        "70kHz","80kHz","90kHz"};
+    p->lin_layout_200=calloc(11,sizeof(*p->lin_layout_200));
+    for(i=0;i<10;i++)
+      p->lin_layout_200[i]=gtk_widget_create_pango_layout(ret,labels[i]);
   }
+  {
+    char *labels[10]={"DC","5kHz","10kHz","15kHz","20kHz","25kHz","30kHz",
+                      "35kHz","40kHz","45kHz"};
+    p->lin_layout_100=calloc(11,sizeof(*p->lin_layout_100));
+    for(i=0;i<10;i++)
+      p->lin_layout_100[i]=gtk_widget_create_pango_layout(ret,labels[i]);
+  }
+  {
+    char *labels[13]={"DC","2kHz","4kHz","6kHz","8kHz","10kHz","12kHz",
+                      "14kHz","16kHz","18kHz","20kHz","22kHz","24kHz"};
+    p->lin_layout_50=calloc(14,sizeof(*p->lin_layout_50));
+    for(i=0;i<13;i++)
+      p->lin_layout_50[i]=gtk_widget_create_pango_layout(ret,labels[i]);
+  }
 
-  p->total_ch = ch;
-
-  p->ch=channels;
-  p->rate=rate;
-  p->maxrate=maxrate;
-
-  if(maxrate > 100000){
-    p->lin_major = 10000.;
-    p->lin_minor = 2000.;
-    p->lin_mult = 5;
-  }else if(maxrate > 50000){
-    p->lin_major = 5000.;
-    p->lin_minor = 1000.;
-    p->lin_mult = 5;
-  }else{
-    p->lin_major=2000.;
-    p->lin_minor=500.;
-    p->lin_mult=4;
+  /* log X scale */
+  {
+    char *labels[16]={"10Hz","20","30","50","100Hz",
+                     "200","300","500","1kHz",
+                     "2k","3k","5k","10kHz",
+                      "20k","30k","50k"};
+    p->log_layout=calloc(17,sizeof(*p->log_layout));
+    for(i=0;i<16;i++)
+      p->log_layout[i]=gtk_widget_create_pango_layout(ret,labels[i]);
   }
 
-  /* generate all the text layouts we'll need */
-  /* linear X scale */
+  /* ISO log X scale */
   {
-    if(maxrate>100000){
-      char *labels[11]={"DC","10kHz","20kHz","30kHz","40kHz","50kHz","60kHz",
-                        "70kHz","80kHz","90kHz",""};
-      p->lin_layout=calloc(12,sizeof(*p->lin_layout));
-      for(i=0;i<11;i++)
-        p->lin_layout[i]=gtk_widget_create_pango_layout(ret,labels[i]);
-    }else if(maxrate > 50000){
-      char *labels[11]={"DC","5kHz","10kHz","15kHz","20kHz","25kHz","30kHz",
-                        "35kHz","40kHz","45kHz",""};
-      p->lin_layout=calloc(12,sizeof(*p->lin_layout));
-      for(i=0;i<11;i++)
-        p->lin_layout[i]=gtk_widget_create_pango_layout(ret,labels[i]);
-    }else{
-      char *labels[14]={"DC","2kHz","4kHz","6kHz","8kHz","10kHz","12kHz",
-                        "14kHz","16kHz","18kHz","20kHz","22kHz","24kHz",""};
-      p->lin_layout=calloc(15,sizeof(*p->lin_layout));
-      for(i=0;i<14;i++)
-        p->lin_layout[i]=gtk_widget_create_pango_layout(ret,labels[i]);
-    }
+    char *labels[12]={"31Hz","63Hz","125Hz","250Hz","500Hz","1kHz","2kHz",
+		      "4kHz","8kHz","16kHz","32kHz","64kHz"};
+    p->iso_layout=calloc(13,sizeof(*p->iso_layout));
+    for(i=0;i<12;i++)
+      p->iso_layout[i]=gtk_widget_create_pango_layout(ret,labels[i]);
   }
+
   /* phase Y scale */
   {
     char *labels[37]={"-180\xC2\xB0","-170\xC2\xB0","-160\xC2\xB0",
@@ -1142,32 +869,7 @@
     for(i=0;i<37;i++)
       p->phase_layout[i]=gtk_widget_create_pango_layout(ret,labels[i]);
   }
-  /* log X scale */
-  {
-    char *labels[15]={"10Hz","20","30","50","100Hz",
-                     "200","300","500","1kHz",
-                     "2k","3k","5k","10kHz",
-                     "20k","30k"};
-    p->log_layout=calloc(16,sizeof(*p->log_layout));
-    for(i=0;i<15;i++)
-      p->log_layout[i]=gtk_widget_create_pango_layout(ret,labels[i]);
-  }
-  /* Impedence Y scale */
-  {
-    char *labels[9]={"10M\xCE\xA9","1M\xCE\xA9","100k\xCE\xA9","10k\xCE\xA9",
-		     "1k\xCE\xA9","100\xCE\xA9","10\xCE\xA9","1\xCE\xA9",".1\xCE\xA9"};
-    p->imp_layout=calloc(10,sizeof(*p->imp_layout));
-    for(i=0;i<9;i++)
-      p->imp_layout[i]=gtk_widget_create_pango_layout(ret,labels[i]);
-  }
-  /* ISO log X scale */
-  {
-    char *labels[12]={"31Hz","63Hz","125Hz","250Hz","500Hz","1kHz","2kHz",
-		      "4kHz","8kHz","16kHz","32kHz",""};
-    p->iso_layout=calloc(13,sizeof(*p->iso_layout));
-    for(i=0;i<12;i++)
-      p->iso_layout[i]=gtk_widget_create_pango_layout(ret,labels[i]);
-  }
+
   /* dB Y scale (integer) */
   {
     char buf[10];
@@ -1177,6 +879,7 @@
       p->db_layout[i+200]=gtk_widget_create_pango_layout(ret,buf);
     }
   }
+
   /* dB Y scale (decimal) */
   {
     char buf[10];
@@ -1186,119 +889,29 @@
       p->db_layout1[i]=gtk_widget_create_pango_layout(ret,buf);
     }
   }
+
   /* dB Y scale (dB) */
   p->db_layoutdB=gtk_widget_create_pango_layout(ret,"dB");
+
   /* dB Y scale (-) */
   p->db_layoutN=gtk_widget_create_pango_layout(ret,"-");
 
-  p->ch_active=calloc(ch,sizeof(*p->ch_active));
-  p->ch_process=calloc(ch,sizeof(*p->ch_process));
-
-  p->autoscale=1;
-
-  filter_make_critical(.04,&p->ymax_damp);
-  filter_make_critical(.04,&p->pmax_damp);
-  filter_make_critical(.04,&p->pmin_damp);
-
+  p->phase_active=0;
   return ret;
 }
 
-void plot_refresh (Plot *p, int *process){
-
-  if(!p->configured)return;
-
-  if(process)
-    memcpy(p->ch_process,process,p->total_ch*sizeof(*process));
-
-  plot_rescale(p, 0);
+int plot_get_left_pad (Plot *m){
+  return m->padx;
 }
 
-void plot_clear (Plot *p){
-  GtkWidget *widget=GTK_WIDGET(p);
-  int phase = phase_active_p(p);
-  int width=GTK_WIDGET(p)->allocation.width-p->padx-(phase ? p->phax : 0);
-  int i,j;
-
-  if(p->ydata)
-    for(i=0;i<p->total_ch;i++)
-      for(j=0;j<width*2;j++)
-	p->ydata[i][j]=-300;
-
-  p->ymax_target=p->ymax;
-  p->pmax_target=p->pmax;
-  p->pmin_target=p->pmin;
-  filter_reset(&p->ymax_damp,p->ymax);
-  filter_reset(&p->pmax_damp,p->pmax);
-  filter_reset(&p->pmin_damp,p->pmin);
-
-  draw_and_expose(widget);
+int plot_get_right_pad (Plot *m){
+  return (m->phase_active ? m->phax : 0);
 }
 
-float **plot_get (Plot *p){
-  return(p->ydata);
+int plot_width (Plot *m){
+  return GTK_WIDGET(m)->allocation.width;
 }
 
-void plot_setting (Plot *p, int scale, int mode, int link, int depth, int noise){
-  GtkWidget *widget=GTK_WIDGET(p);
-  int phase = phase_active_p(p);
-  int request_scale_reset=0;
-
-  p->scale=scale;
-  p->noise=noise;
-
-  if(p->depth != depth ||
-     p->mode != mode ||
-     p->link!=link){
-    if(depth>140)
-      p->ymax_limit=depth;
-    else
-      p->ymax_limit=140;
-    request_scale_reset=1;
-  }
-
-  compute_metadata(widget);
-
-  if(!phase && phase_active_p(p))
-    request_scale_reset=1;
-
-  p->depth=depth;
-  p->mode=mode;
-  p->link=link;
-
-  plot_rescale(p,request_scale_reset);
-  draw_and_expose(widget);
+int plot_height (Plot *m){
+  return GTK_WIDGET(m)->allocation.height;
 }
-
-void plot_draw (Plot *p){
-  GtkWidget *widget=GTK_WIDGET(p);
-  draw_and_expose(widget);
-}
-
-void plot_set_active(Plot *p, int *a, int *b){
-  GtkWidget *widget=GTK_WIDGET(p);
-  memcpy(p->ch_active,a,p->total_ch*sizeof(*a));
-  memcpy(p->ch_process,b,p->total_ch*sizeof(*b));
-  plot_rescale(p,1);
-  draw_and_expose(widget);
-}
-
-void plot_set_autoscale(Plot *p, int a){
-  GtkWidget *widget=GTK_WIDGET(p);
-  p->autoscale=a;
-  plot_rescale(p,a);
-  draw_and_expose(widget);
-}
-
-void plot_set_bold(Plot *p, int b){
-  GtkWidget *widget=GTK_WIDGET(p);
-  p->bold=b;
-  draw_and_expose(widget);
-}
-
-int plot_get_left_pad (Plot *m){
-  return m->padx;
-}
-
-int plot_get_right_pad (Plot *m){
-  return (phase_active_p(m) ? m->phax : 0);
-}

Modified: trunk/spectrum/spec_plot.h
===================================================================
--- trunk/spectrum/spec_plot.h	2012-06-02 16:38:29 UTC (rev 18348)
+++ trunk/spectrum/spec_plot.h	2012-06-03 01:22:50 UTC (rev 18349)
@@ -1,24 +1,24 @@
 /*
  *
  *  gtk2 spectrum analyzer
- *    
+ *
  *      Copyright (C) 2004-2012 Monty
  *
  *  This analyzer is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2, or (at your option)
  *  any later version.
- *   
+ *
  *  The analyzer is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *   
+ *
  *  You should have received a copy of the GNU General Public License
  *  along with Postfish; see the file COPYING.  If not, write to the
  *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * 
+ *
  */
 
 #ifndef __PLOT_H__
@@ -27,6 +27,7 @@
 #include <glib.h>
 #include <glib-object.h>
 #include <gtk/gtk.h>
+#include "io.h"
 
 G_BEGIN_DECLS
 
@@ -40,22 +41,48 @@
 typedef struct _PlotClass  PlotClass;
 
 typedef struct {
-  double a;
-  double b1;
-  double b2;
-  double x[2];
-  double y[2];
-} pole2;
+  int bits[MAX_FILES];
+  int channels[MAX_FILES];
+  int rate[MAX_FILES];
+  int groups;
+  int total_ch;
+  int maxrate;
+  int reload;
+  int scale;
+  int mode;
+  int link;
+  int phase_active;
 
+  float **data;
+  float *active;
+  float ymax;
+  float pmax;
+  float pmin;
+  int height;
+  int width;
+  int increment;
+} fetchdata;
+
+typedef struct {
+  float ymax;
+  float pmax;
+  float pmin;
+  float depth;
+  float bold;
+} plotparams;
+
 struct _Plot{
 
-  GtkDrawingArea canvas;  
+  GtkDrawingArea canvas;
   GdkPixmap *backing;
   GdkGC     *drawgc;
   GdkGC     *dashes;
   GdkGC     *graygc;
   GdkGC     *phasegc;
 
+  PangoLayout **lin_layout_200;
+  PangoLayout **lin_layout_100;
+  PangoLayout **lin_layout_50;
   PangoLayout **lin_layout;
   PangoLayout **log_layout;
   PangoLayout **iso_layout;
@@ -67,21 +94,11 @@
   PangoLayout **phase_layout;
 
   int configured;
-  float **ydata;
-  float *floor;
-
-  int groups;
-  int *ch;
-  int *ch_active;
-  int *ch_process;
   int total_ch;
-  int datasize;
-  int mode;
-  int link;
   int scale;
-  int noise;
-  int *rate;
   int maxrate;
+  int phase_active;
+  int width;
 
   float lin_major;
   float lin_minor;
@@ -99,31 +116,9 @@
   int ytic[200];
   int ytics;
 
-  float depth;
-  float ymax;
-  float pmax;
-  float pmin;
-
-  pole2 ymax_damp;
-  pole2 pmax_damp;
-  pole2 pmin_damp;
-
-  float ymax_target;
-  float pmax_target;
-  float pmin_target;
-  int ymaxtimer;
-  int pmaxtimer;
-  int pmintimer;
-
-  float ymax_limit;
-
   float padx;
   float phax;
   float pady;
-
-
-  int bold;
-  int autoscale;
 };
 
 struct _PlotClass{
@@ -133,21 +128,15 @@
 };
 
 GType          plot_get_type        (void);
-GtkWidget*     plot_new             (int n, int inputs, int *channels, int *rate);
-void	       plot_refresh         (Plot *m, int *process);
-void	       plot_setting         (Plot *m, int scale, int mode, int link, int depth, int noise);
-void	       plot_draw            (Plot *m);
-void	       plot_clear           (Plot *m);
-int 	       plot_width           (Plot *m);
-float**        plot_get             (Plot *m);
-void           plot_set_active      (Plot *m, int *, int *);
-void           plot_set_autoscale   (Plot *m, int);
-void           plot_set_bold   (Plot *m, int);
-
+GtkWidget*     plot_new             (void);
+void	       plot_draw            (Plot *m, fetchdata *f, plotparams *pp);
 int            plot_get_left_pad    (Plot *m);
 int            plot_get_right_pad   (Plot *m);
+int            plot_height          (Plot *m);
+int            plot_width           (Plot *m);
 
 GdkColor chcolor(int ch);
+extern void replot(int scale_reset, int inactive_reset, int scale_damp);
 
 G_END_DECLS
 

Modified: trunk/spectrum/spec_process.c
===================================================================
--- trunk/spectrum/spec_process.c	2012-06-02 16:38:29 UTC (rev 18348)
+++ trunk/spectrum/spec_process.c	2012-06-03 01:22:50 UTC (rev 18349)
@@ -1,24 +1,24 @@
 /*
  *
  *  gtk2 spectrum analyzer
- *    
+ *
  *      Copyright (C) 2004-2012 Monty
  *
  *  This analyzer is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2, or (at your option)
  *  any later version.
- *   
+ *
  *  The analyzer is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
- *   
+ *
  *  You should have received a copy of the GNU General Public License
  *  along with Postfish; see the file COPYING.  If not, write to the
  *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * 
+ *
  */
 
 #include "analyzer.h"
@@ -26,31 +26,30 @@
 
 static float *window=NULL;
 static float *freqbuffer=0;
-static fftwf_plan plan;
+static fftwf_plan plan=NULL;
+static int prev_total_ch=-1;
 
 pthread_mutex_t feedback_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 int feedback_increment=0;
 
-float *feedback_count;
-float **plot_data;
-float *process_work;
+float *feedback_count=NULL;
+float *process_work=NULL;
 
-float **feedback_acc;
-float **feedback_max;
-float **feedback_instant;
+float **feedback_acc=NULL;
+float **feedback_max=NULL;
+float **feedback_instant=NULL;
 
-float **ph_acc;
-float **ph_max;
-float **ph_instant;
+float **ph_acc=NULL;
+float **ph_max=NULL;
+float **ph_instant=NULL;
 
-float **xmappingL;
-float **xmappingM;
-float **xmappingH;
+float **xmappingL=NULL;
+float **xmappingM=NULL;
+float **xmappingH=NULL;
 int metascale = -1;
 int metawidth = -1;
-int metanoise = 0;
+int metareload = 0;
 
-sig_atomic_t acc_clear=0;
 sig_atomic_t acc_rewind=0;
 sig_atomic_t acc_loop=0;
 
@@ -59,10 +58,50 @@
 
 static void init_process(void){
   int i;
-  if(window==NULL){
+
+  if(!window || prev_total_ch != total_ch){
+
+    if(plan)fftwf_destroy_plan(plan);
+
+    if(feedback_acc){
+      for(i=0;i<prev_total_ch;i++)
+        if(feedback_acc[i])free(feedback_acc[i]);
+      free(feedback_acc);
+    }
+    if(feedback_max){
+      for(i=0;i<prev_total_ch;i++)
+        if(feedback_max[i])free(feedback_max[i]);
+      free(feedback_max);
+    }
+    if(feedback_instant){
+      for(i=0;i<prev_total_ch;i++)
+        if(feedback_instant[i])free(feedback_instant[i]);
+      free(feedback_instant);
+    }
+    if(ph_acc){
+      for(i=0;i<prev_total_ch;i++)
+        if(ph_acc[i])free(ph_acc[i]);
+      free(ph_acc);
+    }
+    if(ph_max){
+      for(i=0;i<prev_total_ch;i++)
+        if(ph_max[i])free(ph_max[i]);
+      free(ph_max);
+    }
+    if(ph_instant){
+      for(i=0;i<prev_total_ch;i++)
+        if(ph_instant[i])free(ph_instant[i]);
+      free(ph_instant);
+    }
+
+    if(process_work)free(process_work);
+    if(feedback_count)free(feedback_count);
+
+    if(freqbuffer)free(freqbuffer);
+    if(window)free(window);
+
     process_work=calloc(blocksize+2,sizeof(*process_work));
     feedback_count=calloc(total_ch,sizeof(*feedback_count));
-    plot_data=calloc(total_ch,sizeof(*plot_data));
 
     feedback_acc=malloc(total_ch*sizeof(*feedback_acc));
     feedback_max=malloc(total_ch*sizeof(*feedback_max));
@@ -84,6 +123,8 @@
       ph_instant[i]=calloc(blocksize+2,sizeof(**ph_instant));
     }
 
+    prev_total_ch = total_ch;
+
     plan=fftwf_plan_dft_r2c_1d(blocksize,freqbuffer,
                                (fftwf_complex *)freqbuffer,
                                FFTW_ESTIMATE);
@@ -99,6 +140,7 @@
 
 void rundata_clear(){
   int i,j;
+  pthread_mutex_lock(&feedback_mutex);
   for(i=0;i<total_ch;i++){
     feedback_count[i]=0;
     memset(feedback_acc[i],0,(blocksize/2+1)*sizeof(**feedback_acc));
@@ -111,16 +153,12 @@
       ph_instant[i][j]=0;
     }
   }
-  acc_clear=0;
+  pthread_mutex_unlock(&feedback_mutex);
 }
 
-extern int plot_noise;
-
 /* return 0 on EOF, 1 otherwise */
 static int process(){
   int fi,i,j,ch;
-  int eof_all;
-  int noise=plot_noise;  
 
   if(acc_rewind)
     rewind_files();
@@ -129,25 +167,22 @@
   if(input_read(acc_loop,0))
     return 0;
 
-  if(acc_clear)
-    rundata_clear();
-
   /* by channel */
   ch=0;
   for(fi=0;fi<inputs;fi++){
     if(blockbufferfill[fi]){
       for(i=ch;i<ch+channels[fi];i++){
-	
+
 	float *data=blockbuffer[i];
 
 	/* window the blockbuffer into the FFT buffer */
 	for(j=0;j<blocksize;j++){
 	  freqbuffer[j]=data[j]*window[j];
 	}
-	
+
 	/* transform */
 	fftwf_execute(plan);
-	
+
 	pthread_mutex_lock(&feedback_mutex);
 
 	/* perform desired accumulations */
@@ -178,22 +213,22 @@
 
 	    ph_acc[i][j]+=pR;
 	    ph_acc[i][j+1]+=pI;
-	    
+
 	    if(feedback_max[i][j>>1]<sqM){
 	      ph_max[i][j]=pR;
 	      ph_max[i][j+1]=pI;
 	    }
 	  }
-	  
+
 	  feedback_instant[i][j>>1]=sqM;
 	  feedback_acc[i][j>>1]+=sqM;
-	  
+
 	  if(feedback_max[i][j>>1]<sqM)
 	    feedback_max[i][j>>1]=sqM;
-	  
+
 	}
 	feedback_count[i]++;
-	
+
 	pthread_mutex_unlock(&feedback_mutex);
       }
     }
@@ -206,8 +241,23 @@
 }
 
 void *process_thread(void *dummy){
+  pthread_mutex_lock(&feedback_mutex);
   init_process();
-  while(!process_exit && process());
+  pthread_mutex_unlock(&feedback_mutex);
+
+  while(1){
+    while(!process_exit && process());
+    pthread_mutex_lock(&feedback_mutex);
+    if(!process_exit && pipe_reload()){
+      /* ah, at least one input was a pipe */
+      init_process();
+      metareload=1;
+      pthread_mutex_unlock(&feedback_mutex);
+    }else{
+      pthread_mutex_unlock(&feedback_mutex);
+      break;
+    }
+  }
   process_active=0;
   write(eventpipe[1],"",1);
   return NULL;
@@ -217,104 +267,156 @@
   int fi,i,j,ch;
   FILE *out;
 
-  {   
-    out=fopen("accumulate.m","w");
-    ch = 0;
-    for(fi=0;fi<inputs;fi++){
-      for(i=0;i<blocksize/2+1;i++){
-	fprintf(out,"%f ",(double)i*rate[fi]/blocksize);
-	
-	for(j=ch;j<ch+channels[fi];j++)
-	  fprintf(out,"%f ",todB(feedback_acc[j][i])*.5);
-	fprintf(out,"\n");
-      }
+  pthread_mutex_lock(&feedback_mutex);
+
+  out=fopen("accumulate.m","w");
+  ch = 0;
+  for(fi=0;fi<inputs;fi++){
+    for(i=0;i<blocksize/2+1;i++){
+      fprintf(out,"%f ",(double)i*rate[fi]/blocksize);
+
+      for(j=ch;j<ch+channels[fi];j++)
+        fprintf(out,"%f ",todB(feedback_acc[j][i])*.5);
       fprintf(out,"\n");
-      ch+=channels[fi];
     }
-    fclose(out);
+    fprintf(out,"\n");
+    ch+=channels[fi];
   }
+  fclose(out);
 
-  {   
-    out=fopen("max.m","w");
-    ch = 0;
-    for(fi=0;fi<inputs;fi++){
-      for(i=0;i<blocksize/2+1;i++){
-	fprintf(out,"%f ",(double)i*rate[fi]/blocksize);
-	
-	for(j=ch;j<ch+channels[fi];j++)
-	  fprintf(out,"%f ",todB(feedback_max[j][i])*.5);
-	fprintf(out,"\n");
-      }
+  out=fopen("max.m","w");
+  ch = 0;
+  for(fi=0;fi<inputs;fi++){
+    for(i=0;i<blocksize/2+1;i++){
+      fprintf(out,"%f ",(double)i*rate[fi]/blocksize);
+
+      for(j=ch;j<ch+channels[fi];j++)
+        fprintf(out,"%f ",todB(feedback_max[j][i])*.5);
       fprintf(out,"\n");
-      ch+=channels[fi];
     }
-    fclose(out);
+    fprintf(out,"\n");
+    ch+=channels[fi];
   }
+  fclose(out);
 
-  {   
-    out=fopen("instant.m","w");
-    ch = 0;
-    for(fi=0;fi<inputs;fi++){
-      for(i=0;i<blocksize/2+1;i++){
-	fprintf(out,"%f ",(double)i*rate[fi]/blocksize);
-	
-	for(j=ch;j<ch+channels[fi];j++)
-	  fprintf(out,"%f ",todB(feedback_instant[j][i])*.5);
-	fprintf(out,"\n");
-      }
+  out=fopen("instant.m","w");
+  ch = 0;
+  for(fi=0;fi<inputs;fi++){
+    for(i=0;i<blocksize/2+1;i++){
+      fprintf(out,"%f ",(double)i*rate[fi]/blocksize);
+
+      for(j=ch;j<ch+channels[fi];j++)
+        fprintf(out,"%f ",todB(feedback_instant[j][i])*.5);
       fprintf(out,"\n");
-      ch+=channels[fi];
     }
-    fclose(out);
+    fprintf(out,"\n");
+    ch+=channels[fi];
   }
+  fclose(out);
 
-  {   
-    out=fopen("accphase.m","w");
-    ch = 0;
-    for(fi=0;fi<inputs;fi++){
+  out=fopen("accphase.m","w");
+  ch = 0;
+  for(fi=0;fi<inputs;fi++){
 
-      /* phase */ 
-      for(i=0;i<blocksize+2;i+=2){
-	fprintf(out,"%f ",(double)i*.5*rate[fi]/blocksize);
-	fprintf(out,"%f ",atan2(ph_acc[ch+1][i+1],ph_acc[ch+1][i])*57.29);
-	fprintf(out,"\n");
-      }
+    /* phase */
+    for(i=0;i<blocksize+2;i+=2){
+      fprintf(out,"%f ",(double)i*.5*rate[fi]/blocksize);
+      fprintf(out,"%f ",atan2(ph_acc[ch+1][i+1],ph_acc[ch+1][i])*57.29);
       fprintf(out,"\n");
-      ch+=channels[fi];
     }
-    fclose(out);
+    fprintf(out,"\n");
+    ch+=channels[fi];
   }
+  fclose(out);
 
+  pthread_mutex_unlock(&feedback_mutex);
 }
 
 /* how many bins to 'trim' off the edge of calculated data when we
    know we've hit a boundary of marginal measurement */
 #define binspan 5
 
+static fetchdata fetch_ret;
+
 /* the data returned is now 2 vals per bin; a min and a max.  The spec
    plot merely draws a vertical line between. */
-float **process_fetch(int scale, int mode, int link,
-		      int *active, int width,
-		      float *ymax, float *pmax, float *pmin){
+fetchdata *process_fetch(int scale, int mode, int link,
+                         int *process_in, int process_n,
+                         int height, int width){
   int ch,ci,i,j,fi;
   float **data;
   float **ph;
   float *normptr;
   float maxrate=-1.;
   float nyq;
+  int process[total_ch];
 
+  pthread_mutex_lock(&feedback_mutex);
   init_process();
 
+  if(total_ch!=fetch_ret.total_ch){
+    if(fetch_ret.data){
+      for(i=0;i<fetch_ret.total_ch;i++)
+        if(fetch_ret.data[i])free(fetch_ret.data[i]);
+      free(fetch_ret.data);
+      fetch_ret.data=NULL;
+    }
+    if(fetch_ret.active){
+      free(fetch_ret.active);
+      fetch_ret.active=NULL;
+    }
+  }
+
+  if(!fetch_ret.data)
+    fetch_ret.data = calloc(total_ch,sizeof(*fetch_ret.data));
+
+  if(!fetch_ret.active)
+    fetch_ret.active = calloc(total_ch,sizeof(*fetch_ret.active));
+
+  fetch_ret.groups=inputs;
+  fetch_ret.scale=scale;
+  fetch_ret.mode=mode;
+  fetch_ret.link=link;
+
+  fetch_ret.height=height;
+  fetch_ret.width=width;
+  fetch_ret.total_ch=total_ch;
+  fetch_ret.increment=feedback_increment;
+  memcpy(fetch_ret.bits,bits,sizeof(fetch_ret.bits));
+  memcpy(fetch_ret.channels,channels,sizeof(fetch_ret.channels));
+  memcpy(fetch_ret.rate,rate,sizeof(fetch_ret.rate));
+
+  /* the passed in process array length doesn't necesarity match the
+     current number of channels */
+  for(i=0;i<process_n && i<total_ch;i++)
+    fetch_ret.active[i] = process[i] = process_in[i];
+  for(;i<total_ch;i++)
+    fetch_ret.active[i] = process[i] = 0;
+
   for(fi=0;fi<inputs;fi++)
     if(rate[fi]>maxrate)maxrate=rate[fi];
+
   nyq=maxrate/2.;
+  fetch_ret.maxrate=maxrate;
+  fetch_ret.reload=metareload;
+  metareload=0;
 
+  if(link == LINK_PHASE){
+    int cho=0;
+    int gi;
+    fetch_ret.phase_active=0;
+    for(gi=0;gi<inputs;gi++)
+      if(channels[gi]>1 && fetch_ret.active[cho+1]){
+        fetch_ret.phase_active=1;
+        break;
+      }
+  }
+
   /* are our scale mappings up to date? */
   if(scale != metascale || width != metawidth){
     if(!xmappingL) xmappingL = calloc(inputs, sizeof(*xmappingL));
     if(!xmappingM) xmappingM = calloc(inputs, sizeof(*xmappingM));
     if(!xmappingH) xmappingH = calloc(inputs, sizeof(*xmappingH));
-    metanoise=-1;
 
     for(fi=0;fi<inputs;fi++){
 
@@ -395,10 +497,11 @@
     }
 
     for(i=0;i<total_ch;i++)
-      if(plot_data[i]){
-	plot_data[i] = realloc(plot_data[i],(width+1)*2*sizeof(**plot_data));
+      if(fetch_ret.data[i]){
+	fetch_ret.data[i] = realloc
+          (fetch_ret.data[i],(width+1)*2*sizeof(**fetch_ret.data));
       }else{
-	plot_data[i] = malloc((width+1)*2*sizeof(**plot_data));
+	fetch_ret.data[i] = malloc((width+1)*2*sizeof(**fetch_ret.data));
       }
   }
 
@@ -423,11 +526,11 @@
     normptr=feedback_count;
     break;
   }
-  
+
   ch=0;
-  *ymax = -210.;
-  *pmax = -180.;
-  *pmin = 180.;
+  fetch_ret.ymax = -210.;
+  fetch_ret.pmax = -180.;
+  fetch_ret.pmin = 180.;
   for(fi=0;fi<inputs;fi++){
     float *L = xmappingL[fi];
     float *M = xmappingM[fi];
@@ -438,8 +541,8 @@
     case LINK_INDEPENDENT:
 
       for(ci=0;ci<channels[fi];ci++){
-	if(active[ch+ci]){
-          float *y = plot_data[ci+ch];
+	if(process[ch+ci]){
+          float *y = fetch_ret.data[ci+ch];
           float *m = data[ci+ch];
           int prevbin;
           float prevy;
@@ -473,7 +576,7 @@
 
             max*=.5;
             min*=.5;
-	    if(max>*ymax)*ymax=max;
+	    if(max>fetch_ret.ymax)fetch_ret.ymax=max;
 
             /* link non-overlapping bins into contiguous lines */
             if(i>0){
@@ -496,8 +599,20 @@
       break;
 
     case LINK_SUMMED:
+
+      /* display first channel, but only if any channels in the group
+         are processed */
       {
-        float *y = plot_data[ch];
+        int any=0;
+        for(i=ch;i<ch+channels[fi];i++){
+          if(fetch_ret.active[i])any=1;
+          fetch_ret.active[i]=0;
+        }
+        fetch_ret.active[ch]=any;
+      }
+
+      {
+        float *y = fetch_ret.data[ch];
         float **m = data+ch;
         int prevbin;
         float prevy;
@@ -516,7 +631,7 @@
             int mid = floor(M[i]);
             float del=M[i]-floor(M[i]);
             for(ci=0;ci<channels[fi];ci++){
-              if(active[ch+ci]){
+              if(process[ch+ci]){
                 a+=m[ci][mid];
                 b+=m[ci][mid+1];
               }
@@ -527,14 +642,14 @@
           }else{
             float a=0.;
             for(ci=0;ci<channels[fi];ci++){
-              if(active[ch+ci]) a+=m[ci][first];
+              if(process[ch+ci]) a+=m[ci][first];
             }
             firsty=min=max=a;
 
             for(j=first+1;j<last;j++){
               a=0.;
               for(ci=0;ci<channels[fi];ci++){
-                if(active[ch+ci]) a+=m[ci][j];
+                if(process[ch+ci]) a+=m[ci][j];
               }
               if(a<min)min=a;
               if(a>max)max=a;
@@ -549,7 +664,7 @@
           min*=.5;
           max*=.5;
 
-          if(max>*ymax)*ymax=max;
+          if(max>fetch_ret.ymax)fetch_ret.ymax=max;
 
           /* link non-overlapping bins into contiguous lines */
           if(i>0){
@@ -571,96 +686,106 @@
       break;
 
     case LINK_SUB_FROM:
-      {
-	float *y = plot_data[ch];
-	if(active[ch]==0){
-	  for(i=0;i<width*2+2;i++)
-	    y[i]=-300;
-	}else{
-          float *y = plot_data[ch];
-          float **m = data+ch;
-          int prevbin;
-          float prevy;
-          for(i=0;i<width;i++){
-            int first=ceil(L[i]);
-            int last=ceil(H[i]);
-            float firsty,lasty,min,max;
 
-            /* don't allow roundoff error to skip a bin entirely */
-            if(i>0 && prevbin<first)first=prevbin;
-            prevbin=last;
+      for(i=ch;i<ch+channels[fi];i++)
+        fetch_ret.active[i]=0;
 
-            if(first==last){
-              int mid = floor(M[i]);
-              float del=M[i]-floor(M[i]);
-              float a=m[0][mid];
-              float b=m[0][mid+1];
-              for(ci=1;ci<channels[fi];ci++){
-                if(active[ch+ci]){
-                  a-=m[ci][mid];
-                  b-=m[ci][mid+1];
-                }
+      if(process[ch]==0){
+        float *y = fetch_ret.data[ch];
+        for(i=0;i<width*2+2;i++)
+          y[i]=-300;
+      }else{
+        float *y = fetch_ret.data[ch];
+        float **m = data+ch;
+        int prevbin;
+        float prevy;
+
+        fetch_ret.active[ch]=1;
+
+        for(i=0;i<width;i++){
+          int first=ceil(L[i]);
+          int last=ceil(H[i]);
+          float firsty,lasty,min,max;
+
+          /* don't allow roundoff error to skip a bin entirely */
+          if(i>0 && prevbin<first)first=prevbin;
+          prevbin=last;
+
+          if(first==last){
+            int mid = floor(M[i]);
+            float del=M[i]-floor(M[i]);
+            float a=m[0][mid];
+            float b=m[0][mid+1];
+            for(ci=1;ci<channels[fi];ci++){
+              if(process[ch+ci]){
+                a-=m[ci][mid];
+                b-=m[ci][mid+1];
               }
-              a=todB(a*normalize);
-              b=todB(b*normalize);
-              firsty=lasty=min=max=(a+(b-a)*del);
-            }else{
-              float a=m[0][first];
+            }
+            a=todB(a*normalize);
+            b=todB(b*normalize);
+            firsty=lasty=min=max=(a+(b-a)*del);
+          }else{
+            float a=m[0][first];
+            for(ci=1;ci<channels[fi];ci++){
+              if(process[ch+ci]) a-=m[ci][first];
+            }
+            firsty=min=max=a;
+
+            for(j=first+1;j<last;j++){
+              a=m[0][j];
               for(ci=1;ci<channels[fi];ci++){
-                if(active[ch+ci]) a-=m[ci][first];
+                if(process[ch+ci]) a-=m[ci][j];
               }
-              firsty=min=max=a;
+              if(a<min)min=a;
+              if(a>max)max=a;
+            }
 
-              for(j=first+1;j<last;j++){
-                a=m[0][j];
-                for(ci=1;ci<channels[fi];ci++){
-                  if(active[ch+ci]) a-=m[ci][j];
-                }
-                if(a<min)min=a;
-                if(a>max)max=a;
-              }
+            lasty=todB(a*normalize);
+            firsty=todB(firsty*normalize);
+            min=todB(min*normalize);
+            max=todB(max*normalize);
+          }
 
-              lasty=todB(a*normalize);
-              firsty=todB(firsty*normalize);
-              min=todB(min*normalize);
-              max=todB(max*normalize);
-            }
+          min*=.5;
+          max*=.5;
 
-            min*=.5;
-            max*=.5;
+          if(max>fetch_ret.ymax)fetch_ret.ymax=max;
 
-            if(max>*ymax)*ymax=max;
+          /* link non-overlapping bins into contiguous lines */
+          if(i>0){
+            float midpoint = (prevy+firsty)*.25;
 
-            /* link non-overlapping bins into contiguous lines */
-            if(i>0){
-              float midpoint = (prevy+firsty)*.25;
+            if(midpoint<min)min=midpoint;
+            if(midpoint>max)max=midpoint;
 
-              if(midpoint<min)min=midpoint;
-              if(midpoint>max)max=midpoint;
+            if(midpoint<y[i*2-2])y[i*2-2]=midpoint;
+            if(midpoint>y[i*2-1])y[i*2-1]=midpoint;
+          }
 
-              if(midpoint<y[i*2-2])y[i*2-2]=midpoint;
-              if(midpoint>y[i*2-1])y[i*2-1]=midpoint;
-            }
+          y[i*2]=min;
+          y[i*2+1]=max;
 
-            y[i*2]=min;
-            y[i*2+1]=max;
-
-            prevy=lasty;
-          }
+          prevy=lasty;
         }
       }
       break;
     case LINK_SUB_REF:
+
       {
-        float *y = plot_data[ch];
+        float *r = data[ch];
+        float *y = fetch_ret.data[ch];
         for(i=0;i<width*2+2;i++)
           y[i]=-300;
-      }
-      {
-        float *r = data[ch];
+
+        /* first channel in each display group not shown; used as a
+           reference */
+        fetch_ret.active[ch]=0;
+
+        /* process 1->n */
         for(ci=1;ci<channels[fi];ci++){
-          if(active[ch+ci]){
-            float *y = plot_data[ci+ch];
+          if(process[ch+ci]){
+            float *y = fetch_ret.data[ci+ch];
             float *m = data[ci+ch];
             int prevbin;
             float prevy;
@@ -694,7 +819,7 @@
 
               max*=.5;
               min*=.5;
-              if(max>*ymax)*ymax=max;
+              if(max>fetch_ret.ymax)fetch_ret.ymax=max;
 
               /* link non-overlapping bins into contiguous lines */
               if(i>0){
@@ -719,9 +844,12 @@
 
     case LINK_PHASE: /* response/phase */
 
+      for(i=ch+2;i<ch+channels[fi];i++)
+        fetch_ret.active[i]=0;
+
       if(channels[fi]>=2){
-	float *om = plot_data[ch];
-	float *op = plot_data[ch+1];
+	float *om = fetch_ret.data[ch];
+	float *op = fetch_ret.data[ch+1];
 
 	float *r = data[ch];
 	float *m = data[ch+1];
@@ -734,7 +862,7 @@
 	  /* two vectors only; response and phase */
 	  /* response is a standard minmax vector */
           /* phase is averaged to screen resolution */
-	  if(active[ch] || active[ch+1]){
+	  if(process[ch] || process[ch+1]){
 
             int prevbin;
             float prevy;
@@ -756,7 +884,7 @@
                 float b = todB(m[mid+1]/r[mid+1]);
                 firsty=lasty=min=max=(a+(b-a)*del);
 
-                if(active[ch+1]){
+                if(process[ch+1]){
                   float aP = (isnan(a) ? NAN : atan2f(p[mid*2+1],p[mid*2]));
                   float bP = (isnan(b) ? NAN : atan2f(p[mid*2+3],p[mid*2+2]));
                   P=(aP+(bP-aP)*del)*57.29;
@@ -780,17 +908,17 @@
                 min=todB(min);
                 max=todB(max);
 
-                if(active[ch+1])
+                if(process[ch+1])
                   P = atan2f(I,R)*57.29;
               }
 
               max*=.5;
               min*=.5;
-              if(max>*ymax)*ymax=max;
-              if(P>*pmax)*pmax = P;
-	      if(P<*pmin)*pmin = P;
+              if(max>fetch_ret.ymax)fetch_ret.ymax=max;
+              if(P>fetch_ret.pmax)fetch_ret.pmax = P;
+	      if(P<fetch_ret.pmin)fetch_ret.pmin = P;
 
-              if(active[ch+1] && min>-70){
+              if(process[ch+1] && min>-70){
                 float midpoint = (prevP+P)*.5;
                 op[i*2]=P;
                 op[i*2+1]=P;
@@ -830,7 +958,7 @@
     }
     ch+=channels[fi];
   }
-  
-  return plot_data;
+
+  pthread_mutex_unlock(&feedback_mutex);
+  return &fetch_ret;
 }
-

Modified: trunk/spectrum/version.h
===================================================================
--- trunk/spectrum/version.h	2012-06-02 16:38:29 UTC (rev 18348)
+++ trunk/spectrum/version.h	2012-06-03 01:22:50 UTC (rev 18349)
@@ -1,2 +1,2 @@
 #define VERSION "$Id$ "
-/* DO NOT EDIT: Automated versioning hack [Thu May 31 20:32:33 EDT 2012] */
+/* DO NOT EDIT: Automated versioning hack [Sat Jun  2 21:20:35 EDT 2012] */



More information about the commits mailing list