[xiph-commits] r18405 - trunk/spectrum

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Thu Jun 14 00:44:56 PDT 2012


Author: xiphmont
Date: 2012-06-14 00:44:56 -0700 (Thu, 14 Jun 2012)
New Revision: 18405

Modified:
   trunk/spectrum/Makefile
   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/spectrum.c
   trunk/spectrum/version.h
   trunk/spectrum/wave_panel.c
   trunk/spectrum/wave_plot.h
   trunk/spectrum/wave_process.c
   trunk/spectrum/waveform.c
Log:
Numerous fixes from previous round of conversions; several serious
plot errors in spectrum

Another round of locking changes to allow serialized access to the
blockbuffers without blocking UI thread on IO reads



Modified: trunk/spectrum/Makefile
===================================================================
--- trunk/spectrum/Makefile	2012-06-14 03:25:10 UTC (rev 18404)
+++ trunk/spectrum/Makefile	2012-06-14 07:44:56 UTC (rev 18405)
@@ -68,7 +68,7 @@
 	./touch-version
 	$(LD) $(WAVEFORM_OBJ) -o waveform $(LIBS) $(CFLAGS) `pkg-config --libs gtk+-2.0` -lpthread -lm 
 
-target:  spectrum waveform
+target:  waveform spectrum
 
 install: target
 	$(INSTALL) -d -m 0755 $(BINDIR)

Modified: trunk/spectrum/analyzer.h
===================================================================
--- trunk/spectrum/analyzer.h	2012-06-14 03:25:10 UTC (rev 18404)
+++ trunk/spectrum/analyzer.h	2012-06-14 07:44:56 UTC (rev 18405)
@@ -69,6 +69,42 @@
 
 #endif
 
+/* atan2f approximation, max error: < +/- .0004 degrees */
+/* return value is degrees, not radians */
+#define cA 0.43157974f
+#define cB 0.67848403f
+#define cC 0.08595542f
+#define cD 57.2957795f
+#define cE 90.f
+
+static inline float fast_atan2f_deg(float y, float x) {
+  float x2 = x*x;
+  float y2 = y*y;
+  if(x2<y2){
+    return -cD * x*y*(y2 + cA*x2) / ((y2 + cB*x2) * (y2 + cC*x2)) +
+      copysignf(cE,y);
+  }else{
+    return  cD * x*y*(x2 + cA*y2) / ((x2 + cB*y2) * (x2 + cC*y2)) +
+      copysignf(cE,y) - copysignf(cE,x*y);
+  }
+}
+
+
+static inline float invSqrt(float x){
+  float xhalf = 0.5f*x;
+  union
+  {
+    float x;
+    int i;
+  } u;
+  u.x = x;
+  u.i = 0x5f375a86f - (u.i >> 1);
+  u.x *= 1.5f - xhalf * u.x * u.x;
+  u.x *= 1.5f - xhalf * u.x * u.x;
+  return u.x;
+}
+
+
 #ifndef max
 #define max(x,y) ((x)>(y)?(x):(y))
 #endif
@@ -85,13 +121,17 @@
 extern void process_dump(int mode);
 extern void rundata_clear();
 extern fetchdata *process_fetch(int scale, int mode, int link,
-                                 int *process, int height, int width);
+                                float bw, int bwmode,
+                                int *process, Plot *plot);
 
 extern sig_atomic_t acc_rewind;
 extern sig_atomic_t acc_loop;
 extern sig_atomic_t process_active;
 extern sig_atomic_t process_exit;
 
+extern char *bw_entries[];
+extern float bw_values[];
+
 #define LINKS 5
 #define LINK_INDEPENDENT  0
 #define LINK_SUMMED       1

Modified: trunk/spectrum/io.c
===================================================================
--- trunk/spectrum/io.c	2012-06-14 03:25:10 UTC (rev 18404)
+++ trunk/spectrum/io.c	2012-06-14 07:44:56 UTC (rev 18405)
@@ -26,26 +26,37 @@
 #include <unistd.h>
 #include "io.h"
 
-static pthread_mutex_t ioparam_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+#define readsize 512
+
+/* locks access to file metadata and blockbuffer data */
+pthread_mutex_t blockbuffer_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+
 int bits[MAX_FILES] = {-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1};
 int bigendian[MAX_FILES] = {-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1};
 int channels[MAX_FILES] = {-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1};
 int rate[MAX_FILES] = {-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1};
 int signedp[MAX_FILES] = {-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1};
 
+int total_ch=0;
+
+float **blockbuffer=0;
+int blockbufferfill[MAX_FILES]={0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
+int blockbuffernew[MAX_FILES]={0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
+/* end list of locked buffers */
+
 int bits_force[MAX_FILES] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
 int bigendian_force[MAX_FILES] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
 int channels_force[MAX_FILES] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
 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 int blocksize;
-int blockslice[MAX_FILES]= {-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1};
+extern int blocksize; /* set only at startup */
+sig_atomic_t blockslice_frac;
+static int blockslice_count=0;
+static int blockslice_started=0;
+static int blockslices[MAX_FILES]={0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
 
-float **blockbuffer=0;
-int blockbufferfill[MAX_FILES]={0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
-
-static unsigned char readbuffer[MAX_FILES][readbuffersize];
+static unsigned char readbuffer[MAX_FILES][readsize];
 static int readbufferfill[MAX_FILES]={0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
 static int readbufferptr[MAX_FILES]={0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
 
@@ -56,10 +67,7 @@
 int seekable[MAX_FILES]={0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
 int isapipe[MAX_FILES]={0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
 int global_seekable=0;
-int total_ch=0;
 
-static void (*lc)(void)=NULL;
-
 static int host_is_big_endian() {
   int32_t pattern = 0xfeedface; /* deadbeef */
   unsigned char *bytewise = (unsigned char *)&pattern;
@@ -131,14 +139,13 @@
   }
 }
 
-/* used to load or reload an input */
-static int load_one_input(int fi){
+static void close_one_input(int fi){
   int i;
-
   if(f[fi]){
     fclose(f[fi]);
     f[fi]=NULL;
     blockbufferfill[fi]=0;
+    blockbuffernew[fi]=0;
     readbufferptr[fi]=0;
     readbufferfill[fi]=0;
     if(blockbuffer){
@@ -148,8 +155,14 @@
       blockbuffer=NULL;
     }
     total_ch -= channels[fi];
+    channels[fi]=0;
   }
+}
 
+/* used to load or reload an input */
+static int load_one_input(int fi){
+  int i;
+
   if(!strcmp(inputname[fi],"/dev/stdin") && fi==0){
     int newfd=dup(STDIN_FILENO);
     f[fi]=fdopen(newfd,"rb");
@@ -176,7 +189,10 @@
       global_seekable=1;
     }
 
-    fread(headerid,1,12,f[fi]);
+    if(fread(headerid,1,12,f[fi])==0 && feof(f[fi])){
+      close_one_input(fi);
+      return 1;
+    }
     if(!strncmp(headerid,"RIFF",4) && !strncmp(headerid+8,"WAVE",4)){
       unsigned int chunklen;
 
@@ -402,15 +418,14 @@
   return 0;
 }
 
-int input_load(void (*load_callback)(void)){
+int input_load(void){
   int fi;
   if(inputs==0){
     /* look at stdin... is it a file, pipe, tty...? */
     if(isatty(STDIN_FILENO)){
       fprintf(stderr,
-	      "Spectrum requires either an input file on the command line\n"
-	      "or stream data piped|redirected to stdin. spectrum -h will\n"
-	      "give more details.\n");
+	      "Input file on the command line or stream data\n"
+              "piped|redirected to stdin. -h will give more details.\n");
       return 1;
     }
     inputname[0]=strdup("/dev/stdin");
@@ -427,34 +442,27 @@
       exit(1);
   }
 
-  if(load_callback){
-    lc = load_callback;
-    load_callback();
-  }
-
   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. */
+/* attempts to reopen a pipe at EOF.  Ignores non-fifo inputs.
+   Returns nonzero if a pipe reopens, 0 otherwise */
 
 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");
+    if(!seekable[fi] && f[fi]==NULL && isapipe[fi] &&
+       !load_one_input(fi)){
+      fprintf(stderr,"reopened input %d\n",fi);
       ret=1;
     }
-
-  if(ret && lc)lc();
   return ret;
 }
 
 /* Convert new data from readbuffer into the blockbuffers until the
-   blockbuffer is full */
-static void LBEconvert(int *localslice){
+   blockbuffer is full or the readbuffer is empty */
+static void LBEconvert(void){
   float scale=1./2147483648.;
   int ch=0,fi;
 
@@ -467,7 +475,7 @@
       channels[fi]/bytes*channels[fi]*bytes+readbufferptr[fi];
 
     int bfill = blockbufferfill[fi];
-    int tosize = blocksize + localslice[fi];
+    int tosize = blocksize + blockslices[fi];
     int rptr = readbufferptr[fi];
     unsigned char *rbuf = readbuffer[fi];
 
@@ -558,30 +566,51 @@
   }
 }
 
-void set_blockslice(int slice, int fi){
-  pthread_mutex_lock(&ioparam_mutex);
-  blockslice[fi]=slice;
-  pthread_mutex_unlock(&ioparam_mutex);
+/* blockslices are tracked/locked over a one second period */
+static void blockslice_advance(void){
+  int fi;
+  int frac = blockslice_frac;
+  int count;
+
+  /* strict determinism is nice */
+  if(!blockslice_started)blockslice_count=0;
+
+  count = blockslice_count + (1000000/frac);
+  for(fi=0;fi<inputs;fi++){
+    int prevsample = rint((double)rate[fi]*blockslice_count/1000000);
+    int thissample = rint((double)rate[fi]*count/1000000);
+
+    blockslices[fi] = thissample - prevsample;
+    if(blockslices[fi]<1)blockslices[fi]=1;
+    if(blockslices[fi]>blocksize)blockslices[fi]=blocksize;
+
+  }
+
+  blockslice_count = count;
+  if(blockslice_count>=1000000)blockslice_count-=1000000;
+  blockslice_started = 1;
 }
 
-/* when we return, the blockbuffer is full or we're at EOF */
-/* EOF cases:
-     loop set: return EOF if all seekable streams have hit EOF
-     loop unset: return EOF if all streams have hit EOF
-   pad individual EOF streams out with zeroes until global EOF is hit  */
+/* input_read returns:
+   -1 if a pipe hits EOF
+    0 if all at EOF and nothing to process
+    1 if new data ready to process
 
+   All access to blockbuffer[0,blocksize) is locked, as is the
+   blockbuffer metadata
+*/
+
 int input_read(int loop, int partialok){
-  int i,j,fi,ch=0;
-  int eof=1;
+  int i,j,fi,ch;
   int notdone=1;
+  int ret=0;
   int rewound[total_ch];
-  int localslice[MAX_FILES];
   memset(rewound,0,sizeof(rewound));
 
-  pthread_mutex_lock(&ioparam_mutex);
-  memcpy(localslice,blockslice,sizeof(localslice));
-  pthread_mutex_unlock(&ioparam_mutex);
+  /* also handles initialization */
+  if(!blockslice_started)blockslice_advance();
 
+  pthread_mutex_lock(&blockbuffer_mutex);
   if(blockbuffer==0){
     blockbuffer=malloc(total_ch*sizeof(*blockbuffer));
 
@@ -592,7 +621,8 @@
 
   /* if this is first frame, do we allow a single slice or fully
      fill the buffer */
-  for(fi=0;fi<inputs;fi++){
+  ch=0;
+  for(fi=0,ch=0;fi<inputs;fi++){
     if(blockbufferfill[fi]==0){
       for(i=ch;i<channels[fi]+ch;i++)
         for(j=0;j<blocksize;j++)
@@ -600,107 +630,111 @@
       if(partialok){
         blockbufferfill[fi]=blocksize;
       }else{
-        blockbufferfill[fi]=localslice[fi];
+        blockbufferfill[fi]=blockslices[fi];
       }
     }
   }
+  pthread_mutex_unlock(&blockbuffer_mutex);
 
-  /* try to fill buffer to blocksize+slice before performing shift */
-
   while(notdone){
     notdone=0;
 
-    /* if there's data left to be pulled out of a readbuffer, do that */
-    LBEconvert(localslice);
+    /* if there's data left to be pulled out of a readbuffer, do
+       that */
+    /* not locked: new data is either fed into a yet-inactive
+       buffer or to the end (past the blocksize) of an active
+       buffer */
+    LBEconvert();
 
-    ch=0;
+    /* fill readbuffers */
     for(fi=0;fi<inputs;fi++){
-      if(blockbufferfill[fi]!=blocksize+localslice[fi]){
 
-	/* shift the read buffer before fill if there's a fractional
-	   frame in it */
-	if(readbufferptr[fi]!=readbufferfill[fi] && readbufferptr[fi]>0){
-	  memmove(readbuffer[fi],readbuffer[fi]+readbufferptr[fi],
-		  (readbufferfill[fi]-readbufferptr[fi])*sizeof(**readbuffer));
-	  readbufferfill[fi]-=readbufferptr[fi];
-	  readbufferptr[fi]=0;
-	}else{
-	  readbufferfill[fi]=0;
-	  readbufferptr[fi]=0;
-	}
+      /* drain what's already been processed before fill */
+      if(readbufferptr[fi]>0){
+        if(readbufferptr[fi]!=readbufferfill[fi]){
+          /* partial frame; shift it */
+          memmove(readbuffer[fi],readbuffer[fi]+readbufferptr[fi],
+                  (readbufferfill[fi]-readbufferptr[fi]));
+          readbufferfill[fi]-=readbufferptr[fi];
+          readbufferptr[fi]=0;
+        }else{
+          /* all processed, just empty */
+          readbufferfill[fi]=0;
+          readbufferptr[fi]=0;
+        }
+      }
 
-	/* attempt to top off the readbuffer */
-	{
-	  long actually_readbytes=0,readbytes=readbuffersize-readbufferfill[fi];
+      /* attempt to top off the readbuffer if the given blockbuffer
+         isn't full */
+      if(readbufferfill[fi]<readsize &&
+         blockbufferfill[fi]<blocksize+blockslices[fi]){
+        int readbytes=readsize-readbufferfill[fi];
+        int actually_readbytes =
+          fread(readbuffer[fi]+readbufferfill[fi],1,readbytes,f[fi]);
 
-	  if(readbytes>0)
-	    actually_readbytes=fread(readbuffer[fi]+readbufferfill[fi],1,readbytes,f[fi]);
-
-	  if(actually_readbytes<=0 && ferror(f[fi])){
-	    fprintf(stderr,"Input read error from %s: %s\n",
-                    inputname[fi],strerror(ferror(f[fi])));
-	  }else if (actually_readbytes==0){
+        if(actually_readbytes<=0 && ferror(f[fi])){
+          fprintf(stderr,"Input read error from %s: %s\n",
+                  inputname[fi],strerror(ferror(f[fi])));
+        }else if (actually_readbytes==0){
+          if(isapipe[fi] && !seekable[fi]){
+            /* attempt to reopen a pipe immediately; kick out */
+            close_one_input(fi);
+            return -1;
+          }
+          if(loop && seekable[fi] && (!rewound[fi] || readbufferfill[fi])){
             /* real, hard EOF/error in a partially filled block */
-            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;
-              rewound[fi]=1;
-            }
-	  }else{
-            /* got a read */
-	    bytesleft[fi]-=actually_readbytes;
-	    readbufferfill[fi]+=actually_readbytes;
+            /* 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{
-        eof=0;
+            rewound[fi]=1;
+          }
+        }else{
+          /* got a read */
+          bytesleft[fi]-=actually_readbytes;
+          readbufferfill[fi]+=actually_readbytes;
+          notdone=1;
+        }
       }
-      ch += channels[fi];
     }
   }
 
-  /* shift */
+  /* at this point, all buffers are fully topped off or at eof */
+  pthread_mutex_lock(&blockbuffer_mutex);
+
+  /* shift any updated blockbuffers and mark them new */
   for(fi=0,ch=0;fi<inputs;fi++){
-    if(blockbufferfill[fi]>blocksize){
+    if(blockbufferfill[fi]>=blocksize+(partialok?1:blockslices[fi])){
       for(i=ch;i<channels[fi]+ch;i++)
-        memmove(blockbuffer[i],blockbuffer[i]+(blockbufferfill[fi]-blocksize),
+        memmove(blockbuffer[i],blockbuffer[i]+
+                (blockbufferfill[fi]-blocksize),
                 blocksize*sizeof(**blockbuffer));
       blockbufferfill[fi]=blocksize;
+      blockbuffernew[fi]=1;
+      ret=1;
     }
-    for(i=ch;i<channels[fi]+ch;i++)
-      for(j=blockbufferfill[fi];j<blocksize;j++)
-        blockbuffer[i][j]=NAN;
-    ch+=channels[fi];
   }
+  blockslice_advance();
+  pthread_mutex_unlock(&blockbuffer_mutex);
 
-  return eof;
+  return ret;
 }
 
 int rewind_files(){
   int fi;
+
   for(fi=0;fi<inputs;fi++){
-    if(!seekable[fi])
-      return 1;
+    if(seekable[fi]){
+      blockbufferfill[fi]=0;
+      blockbuffernew[fi]=0;
+      readbufferptr[fi]=0;
+      readbufferfill[fi]=0;
+      fseek(f[fi],offset[fi],SEEK_SET);
+      if(length[fi]!=-1)bytesleft[fi]=length[fi]*channels[fi]*((bits[fi]+7)/8);
+    }
   }
 
-  for(fi=0;fi<inputs;fi++){
-    blockbufferfill[fi]=0;
-    readbufferptr[fi]=0;
-    readbufferfill[fi]=0;
-    fseek(f[fi],offset[fi],SEEK_SET);
-    if(length[fi]!=-1)bytesleft[fi]=length[fi]*channels[fi]*((bits[fi]+7)/8);
-  }
+  blockslice_started=0;
   return 0;
 }

Modified: trunk/spectrum/io.h
===================================================================
--- trunk/spectrum/io.h	2012-06-14 03:25:10 UTC (rev 18404)
+++ trunk/spectrum/io.h	2012-06-14 07:44:56 UTC (rev 18405)
@@ -44,10 +44,9 @@
 #include <fcntl.h>
 
 #define MAX_FILES 16
-#define readbuffersize 512
+extern pthread_mutex_t blockbuffer_mutex;
 
-extern int input_load(void (*load_callback)(void));
-extern void set_blockslice(int slice, int fi);
+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);
@@ -70,8 +69,9 @@
 extern int seekable[MAX_FILES];
 extern int global_seekable;
 
-extern int blockslice[MAX_FILES];
+extern sig_atomic_t blockslice_frac;
 extern int blockbufferfill[MAX_FILES];
+extern int blockbuffernew[MAX_FILES];
 extern float **blockbuffer;
 #endif
 

Modified: trunk/spectrum/spec_panel.c
===================================================================
--- trunk/spectrum/spec_panel.c	2012-06-14 03:25:10 UTC (rev 18404)
+++ trunk/spectrum/spec_panel.c	2012-06-14 07:44:56 UTC (rev 18405)
@@ -58,7 +58,7 @@
 int plot_lock_y=0;
 int plot_depth=90;
 int plot_noise=0;
-int plot_bw=0;
+int plot_bwchoice=0;
 int plot_bwmode=0;
 int plot_bold=0;
 
@@ -192,7 +192,7 @@
 
   pmax+=10;
   pmin-=10;
-  if(pmax<5)pmax=5;
+  if(pmax<10)pmax=10;
   if(pmax>190)pmax=190;
   if(pmin>-20)pmin=-20;
   if(pmin<-190)pmin=-190;
@@ -505,10 +505,7 @@
 
 static void linkchange(GtkWidget *widget,gpointer in){
   plot_link=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
-  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);
+  chlabels(widget,NULL);
 }
 
 static void runchange(GtkWidget *widget,gpointer in){
@@ -557,8 +554,8 @@
 }
 
 static void bwchange(GtkWidget *widget,gpointer in){
-  plot_bw=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
-  if(plot_bw==0){
+  plot_bwchoice=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
+  if(plot_bwchoice==0){
     gtk_widget_set_sensitive(GTK_WIDGET(bwmodebutton),0);
   }else{
     gtk_widget_set_sensitive(GTK_WIDGET(bwmodebutton),1);
@@ -650,8 +647,11 @@
   /* update the spectral display; send new data */
   fetchdata *f = process_fetch
     (plot_scale, plot_mode, plot_link,
-     process, plot_height(PLOT(plot)), plot_width(PLOT(plot)));
+     bw_values[plot_bwchoice],plot_bwmode,
+     process, PLOT(plot));
 
+  if(!f)return;
+
   /* the fetched data may indicate the underlying file data has
      changed... */
   if(f->reload){
@@ -716,6 +716,7 @@
   GdkWindow *root=gdk_get_default_root_window();
   GtkWidget *topbox=gtk_hbox_new(0,0);
   GtkWidget *rightframe=gtk_frame_new (NULL);
+  GtkWidget *righttopal=gtk_alignment_new(.5,.5,1.,1.);
   GtkWidget *righttopbox=gtk_vbox_new(0,0);
   GtkWidget *rightframebox=gtk_event_box_new();
   GtkWidget *lefttable=gtk_table_new(4,2,0);
@@ -738,7 +739,8 @@
 
   /* underlying boxes/frames */
   gtk_box_pack_start(GTK_BOX(topbox),lefttable,1,1,0);
-  gtk_box_pack_start(GTK_BOX(topbox),righttopbox,0,0,0);
+  gtk_box_pack_start(GTK_BOX(topbox),righttopal,0,0,0);
+  gtk_container_add(GTK_CONTAINER(righttopal),righttopbox);
 
   /* plot control checkboxes */
   {
@@ -804,10 +806,11 @@
   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);
+  //gtk_table_set_col_spacing (GTK_TABLE (lefttable), 0, 2);
 
   /* right control frame */
-  gtk_container_set_border_width (GTK_CONTAINER (righttopbox), 6);
+  gtk_alignment_set_padding(GTK_ALIGNMENT(righttopal),6,6,2,6);
+  //gtk_container_set_border_width (GTK_CONTAINER (righttopbox), 6);
   gtk_container_set_border_width (GTK_CONTAINER (rightbox), 6);
   gtk_frame_set_shadow_type(GTK_FRAME(rightframe),GTK_SHADOW_ETCHED_IN);
   gtk_widget_set_name(rightframebox,"controlpanel");
@@ -863,25 +866,22 @@
     GtkWidget *tbox=bwtable=gtk_table_new(2,2,0);
 
     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"};
+    for(i=0;bw_entries[i];i++)
+      gtk_combo_box_append_text (GTK_COMBO_BOX (menu), bw_entries[i]);
 
-    for(i=0;i<2;i++)
-      gtk_combo_box_append_text (GTK_COMBO_BOX (menu), entries[i]);
-    //gtk_combo_box_set_active(GTK_COMBO_BOX(menu),0);
-    
     g_signal_connect (G_OBJECT (menu), "changed",
     		      G_CALLBACK (bwchange), NULL);
 
     GtkWidget *menu2=bwmodebutton=gtk_combo_box_new_text();
-    char *entries2[]={"RBW","VBW"};
-    for(i=0;i<2;i++)
+    char *entries2[]={"ampl","power","psd","video",NULL};
+    for(i=0;entries2[i];i++)
       gtk_combo_box_append_text (GTK_COMBO_BOX (menu2), entries2[i]);
-    
+
     g_signal_connect (G_OBJECT (menu2), "changed",
     		      G_CALLBACK (bwmodechange), NULL);
+
     gtk_combo_box_set_active(GTK_COMBO_BOX(menu2),0);
+    gtk_combo_box_set_active(GTK_COMBO_BOX(menu),0);
 
     gtk_table_attach_defaults(GTK_TABLE(tbox),menu,0,1,0,1);
     gtk_table_attach_defaults(GTK_TABLE(tbox),menu2,1,2,0,1);
@@ -894,7 +894,7 @@
     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);
-    
+
     g_signal_connect (G_OBJECT (menu3), "changed",
 		      G_CALLBACK (scalechange), NULL);
 
@@ -902,7 +902,7 @@
     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), NULL);
     gtk_combo_box_set_active(GTK_COMBO_BOX(menu4),4);
@@ -913,39 +913,40 @@
     gtk_box_pack_start(GTK_BOX(bbox),tbox,0,0,0);
 
   }
-  
+
   /* mode */
   {
     GtkWidget *menu=gtk_combo_box_new_text();
-    char *entries[]={"current frame","maximum","accumulate","average"};
-    for(i=0;i<4;i++)
+    char *entries[]={"instantaneous","maximum","accumulate","average",NULL};
+    for(i=0;entries[i];i++)
       gtk_combo_box_append_text (GTK_COMBO_BOX (menu), entries[i]);
     gtk_combo_box_set_active(GTK_COMBO_BOX(menu),plot_mode);
     gtk_box_pack_start(GTK_BOX(bbox),menu,0,0,0);
-    
+
     g_signal_connect (G_OBJECT (menu), "changed",
 		      G_CALLBACK (modechange), NULL);
   }
-  
+
   /* link */
   {
     GtkWidget *menu=gtk_combo_box_new_text();
-    char *entries[LINKS]={"independent",
-                          "sum",
-                          "subtract ref",
-                          "subtract from",
-                          "response/phase"};
+    char *entries[]={"independent",
+                     "sum",
+                     "subtract ref",
+                     "subtract from",
+                     "response/phase",
+                     NULL};
 
-    for(i=0;i<LINKS;i++)
+    for(i=0;entries[i];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), NULL);
   }
-  
 
+
   {
     GtkWidget *sep=gtk_hseparator_new();
     gtk_box_pack_start(GTK_BOX(bbox),sep,0,0,4);
@@ -960,7 +961,7 @@
     gtk_box_pack_start(GTK_BOX(bbox),button,0,0,0);
     run=button;
   }
-  
+
   /* loop */
   /* rewind */
   {
@@ -970,17 +971,17 @@
     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", 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);
-    
+
     gtk_box_pack_start(GTK_BOX(bbox),box,0,0,0);
   }
-  
+
   /* clear */
   /* dump */
   {
@@ -989,8 +990,8 @@
     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", group, GDK_d, 0, 0);
     g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (dump), NULL);
@@ -1143,4 +1144,3 @@
   gtk_main ();
 
 }
-

Modified: trunk/spectrum/spec_plot.c
===================================================================
--- trunk/spectrum/spec_plot.c	2012-06-14 03:25:10 UTC (rev 18404)
+++ trunk/spectrum/spec_plot.c	2012-06-14 07:44:56 UTC (rev 18405)
@@ -45,10 +45,15 @@
 
 static GtkDrawingAreaClass *parent_class = NULL;
 
+#define PHAX_MIN 6
+
 static void compute_xgrid(Plot *p, fetchdata *f){
-  if(p->maxrate!=f->maxrate || p->scale!=f->scale || p->width != f->width){
+  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 width = widget->allocation.width-p->padx-
+      (f->phase_active?p->phax:PHAX_MIN);
     int nyq=f->maxrate/2.;
     int i,j;
 
@@ -204,7 +209,7 @@
 
   int phase = f->phase_active;
   int padx = p->padx;
-  int phax = phase ? p->phax : 0;
+  int phax = phase ? p->phax : PHAX_MIN;
   int pwidth = width - padx - phax;
 
   /* lazy GC init */
@@ -253,8 +258,7 @@
     GdkGC *gc=parent->style->bg_gc[0];
     gdk_draw_rectangle(p->backing,gc,1,0,0,padx,height);
     gdk_draw_rectangle(p->backing,gc,1,0,height-p->pady,width,p->pady);
-    if(phase)
-      gdk_draw_rectangle(p->backing,gc,1,width-phax,0,phax,height);
+    gdk_draw_rectangle(p->backing,gc,1,width-phax,0,phax,height);
 
     gc=parent->style->white_gc;
     gdk_draw_rectangle(p->backing,gc,1,padx,0,pwidth,height-p->pady);
@@ -263,8 +267,8 @@
   compute_xgrid(p,f);
   p->maxrate=f->maxrate;
   p->scale=f->scale;
+  p->width=f->width;
   p->phase_active=f->phase_active;
-  p->width=f->width;
 
   /* draw the light x grid */
   {
@@ -569,11 +573,11 @@
       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){
+      if(ymid>=0 && pv>=-18 && pv<=18 && ((pv&1)==0 || del>2)){
         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,
+                         width-phax+2, ymid-py/2,
                          p->phase_layout[pv+18]);
       }
     }
@@ -585,8 +589,8 @@
                       (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);
+          gdk_draw_line(p->backing,p->phasegc,width-phax-(i%5==0?15:10),
+                        ymid,width-phax-(i%5==0?5:7),ymid);
       }
     }else if(del>5){
       for(i=0;;i++){
@@ -595,8 +599,8 @@
                       (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);
+          gdk_draw_line(p->backing,p->phasegc,width-phax-12,ymid,
+                        width-phax-7,ymid);
       }
     } else if(del>2){
       for(i=0;;i++){
@@ -605,8 +609,8 @@
                       (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);
+          gdk_draw_line(p->backing,p->phasegc,width-phax-15,ymid,
+                        width-phax-5,ymid);
       }
     }
 
@@ -617,12 +621,12 @@
                       (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);
+          gdk_draw_line(p->backing,p->phasegc,width-phax-5,ymid-1,
+                        width-phax-1,ymid-1);
+          gdk_draw_line(p->backing,p->phasegc,width-phax-25,ymid,
+                        width-phax-1,ymid);
+          gdk_draw_line(p->backing,p->phasegc,width-phax-5,ymid+1,
+                        width-phax-1,ymid+1);
         }
       }
     }else{
@@ -633,8 +637,8 @@
                       (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);
+          gdk_draw_line(p->backing,p->phasegc,width-phax-15,ymid,
+                        width-phax-5,ymid);
       }
 
       for(i=0;;i++){
@@ -643,12 +647,12 @@
                        (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);
+          gdk_draw_line(p->backing,p->phasegc,width-phax-5,ymid-1,
+                        width-phax-1,ymid-1);
+          gdk_draw_line(p->backing,p->phasegc,width-phax-25,ymid,
+                        width-phax-1,ymid);
+          gdk_draw_line(p->backing,p->phasegc,width-phax-5,ymid+1,
+                        width-phax-1,ymid+1);
         }
       }
     }
@@ -761,8 +765,13 @@
 			      widget->allocation.width,
 			      widget->allocation.height,
 			      -1);
-  p->configured=1;
-  replot(0,0,0);
+
+  if(!p->configured){
+    p->configured=1;
+    replot(1,0,0);
+  }else{
+    replot(0,0,0);
+  }
   return TRUE;
 }
 
@@ -832,9 +841,9 @@
 
   /* log X scale */
   {
-    char *labels[16]={"10Hz","20","30","50","100Hz",
+    char *labels[16]={"10","20","30","50","100",
                      "200","300","500","1kHz",
-                     "2k","3k","5k","10kHz",
+                     "2kHz","3kHz","5k","10kHz",
                       "20k","30k","50k"};
     p->log_layout=calloc(17,sizeof(*p->log_layout));
     for(i=0;i<16;i++)
@@ -843,7 +852,7 @@
 
   /* ISO log X scale */
   {
-    char *labels[12]={"31Hz","63Hz","125Hz","250Hz","500Hz","1kHz","2kHz",
+    char *labels[12]={"31","63","125","250","500","1kHz","2kHz",
 		      "4kHz","8kHz","16kHz","32kHz","64kHz"};
     p->iso_layout=calloc(13,sizeof(*p->iso_layout));
     for(i=0;i<12;i++)
@@ -896,7 +905,6 @@
   /* dB Y scale (-) */
   p->db_layoutN=gtk_widget_create_pango_layout(ret,"-");
 
-  p->phase_active=0;
   return ret;
 }
 
@@ -905,13 +913,13 @@
 }
 
 int plot_get_right_pad (Plot *m){
-  return (m->phase_active ? m->phax : 0);
+  return (m->phase_active ? m->phax : PHAX_MIN);
 }
 
-int plot_width (Plot *m){
-  return GTK_WIDGET(m)->allocation.width;
+int plot_width (Plot *m,int ph){
+  return GTK_WIDGET(m)->allocation.width-m->padx-(ph?m->phax:PHAX_MIN);
 }
 
 int plot_height (Plot *m){
-  return GTK_WIDGET(m)->allocation.height;
+  return GTK_WIDGET(m)->allocation.height-m->pady;
 }

Modified: trunk/spectrum/spec_plot.h
===================================================================
--- trunk/spectrum/spec_plot.h	2012-06-14 03:25:10 UTC (rev 18404)
+++ trunk/spectrum/spec_plot.h	2012-06-14 07:44:56 UTC (rev 18405)
@@ -49,7 +49,6 @@
   float pmin;
   int height;
   int width;
-  int increment;
 } fetchdata;
 
 typedef struct {
@@ -133,7 +132,7 @@
 int            plot_get_left_pad    (Plot *m);
 int            plot_get_right_pad   (Plot *m);
 int            plot_height          (Plot *m);
-int            plot_width           (Plot *m);
+int            plot_width           (Plot *m,int ph);
 
 GdkColor chcolor(int ch);
 extern void replot(int scale_reset, int inactive_reset, int scale_damp);

Modified: trunk/spectrum/spec_process.c
===================================================================
--- trunk/spectrum/spec_process.c	2012-06-14 03:25:10 UTC (rev 18404)
+++ trunk/spectrum/spec_process.c	2012-06-14 07:44:56 UTC (rev 18405)
@@ -30,18 +30,21 @@
 static int prev_total_ch=-1;
 
 static pthread_mutex_t feedback_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
-static int feedback_increment=0;
+static pthread_mutex_t bw_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 
 static float *feedback_count=NULL;
 static float *process_work=NULL;
 
-static float **feedback_acc=NULL;
-static float **feedback_max=NULL;
-static float **feedback_instant=NULL;
+static float **mag_acc=NULL;
+static float **mag_max=NULL;
+static float **mag_instant=NULL;
 
-static float **ph_acc=NULL;
-static float **ph_max=NULL;
-static float **ph_instant=NULL;
+static float **phI_acc=NULL;
+static float **phQ_acc=NULL;
+static float **phI_max=NULL;
+static float **phQ_max=NULL;
+static float **phI_instant=NULL;
+static float **phQ_instant=NULL;
 
 static float **xmappingL=NULL;
 static float **xmappingM=NULL;
@@ -63,36 +66,52 @@
 
     if(plan)fftwf_destroy_plan(plan);
 
-    if(feedback_acc){
+    if(mag_acc){
       for(i=0;i<prev_total_ch;i++)
-        if(feedback_acc[i])free(feedback_acc[i]);
-      free(feedback_acc);
+        if(mag_acc[i])free(mag_acc[i]);
+      free(mag_acc);
     }
-    if(feedback_max){
+    if(mag_max){
       for(i=0;i<prev_total_ch;i++)
-        if(feedback_max[i])free(feedback_max[i]);
-      free(feedback_max);
+        if(mag_max[i])free(mag_max[i]);
+      free(mag_max);
     }
-    if(feedback_instant){
+    if(mag_instant){
       for(i=0;i<prev_total_ch;i++)
-        if(feedback_instant[i])free(feedback_instant[i]);
-      free(feedback_instant);
+        if(mag_instant[i])free(mag_instant[i]);
+      free(mag_instant);
     }
-    if(ph_acc){
+
+    if(phI_acc){
       for(i=0;i<prev_total_ch;i++)
-        if(ph_acc[i])free(ph_acc[i]);
-      free(ph_acc);
+        if(phI_acc[i])free(phI_acc[i]);
+      free(phI_acc);
     }
-    if(ph_max){
+    if(phQ_acc){
       for(i=0;i<prev_total_ch;i++)
-        if(ph_max[i])free(ph_max[i]);
-      free(ph_max);
+        if(phQ_acc[i])free(phQ_acc[i]);
+      free(phQ_acc);
     }
-    if(ph_instant){
+    if(phI_max){
       for(i=0;i<prev_total_ch;i++)
-        if(ph_instant[i])free(ph_instant[i]);
-      free(ph_instant);
+        if(phI_max[i])free(phI_max[i]);
+      free(phI_max);
     }
+    if(phQ_max){
+      for(i=0;i<prev_total_ch;i++)
+        if(phQ_max[i])free(phQ_max[i]);
+      free(phQ_max);
+    }
+    if(phI_instant){
+      for(i=0;i<prev_total_ch;i++)
+        if(phI_instant[i])free(phI_instant[i]);
+      free(phI_instant);
+    }
+    if(phQ_instant){
+      for(i=0;i<prev_total_ch;i++)
+        if(phQ_instant[i])free(phQ_instant[i]);
+      free(phQ_instant);
+    }
 
     if(process_work)free(process_work);
     if(feedback_count)free(feedback_count);
@@ -103,24 +122,32 @@
     process_work=calloc(blocksize+2,sizeof(*process_work));
     feedback_count=calloc(total_ch,sizeof(*feedback_count));
 
-    feedback_acc=malloc(total_ch*sizeof(*feedback_acc));
-    feedback_max=malloc(total_ch*sizeof(*feedback_max));
-    feedback_instant=malloc(total_ch*sizeof(*feedback_instant));
+    mag_acc=calloc(total_ch,sizeof(*mag_acc));
+    mag_max=calloc(total_ch,sizeof(*mag_max));
+    mag_instant=calloc(total_ch,sizeof(*mag_instant));
 
-    ph_acc=malloc(total_ch*sizeof(*ph_acc));
-    ph_max=malloc(total_ch*sizeof(*ph_max));
-    ph_instant=malloc(total_ch*sizeof(*ph_instant));
+    phI_acc=calloc(total_ch,sizeof(*phI_acc));
+    phQ_acc=calloc(total_ch,sizeof(*phQ_acc));
+    phI_max=calloc(total_ch,sizeof(*phI_max));
+    phQ_max=calloc(total_ch,sizeof(*phQ_max));
+    phI_instant=calloc(total_ch,sizeof(*phI_instant));
+    phQ_instant=calloc(total_ch,sizeof(*phQ_instant));
 
     freqbuffer=fftwf_malloc((blocksize+2)*sizeof(*freqbuffer));
     for(i=0;i<total_ch;i++){
 
-      feedback_acc[i]=calloc(blocksize/2+1,sizeof(**feedback_acc));
-      feedback_max[i]=calloc(blocksize/2+1,sizeof(**feedback_max));
-      feedback_instant[i]=calloc(blocksize/2+1,sizeof(**feedback_instant));
+      mag_acc[i]=calloc(blocksize/2+1,sizeof(**mag_acc));
+      mag_max[i]=calloc(blocksize/2+1,sizeof(**mag_max));
+      mag_instant[i]=calloc(blocksize/2+1,sizeof(**mag_instant));
 
-      ph_acc[i]=calloc(blocksize+2,sizeof(**ph_acc));
-      ph_max[i]=calloc(blocksize+2,sizeof(**ph_max));
-      ph_instant[i]=calloc(blocksize+2,sizeof(**ph_instant));
+      if(i>0){
+        phI_acc[i]=calloc(blocksize/2+1,sizeof(**phI_acc));
+        phI_max[i]=calloc(blocksize/2+1,sizeof(**phI_max));
+        phI_instant[i]=calloc(blocksize/2+1,sizeof(**phI_instant));
+        phQ_acc[i]=calloc(blocksize/2+1,sizeof(**phQ_acc));
+        phQ_max[i]=calloc(blocksize/2+1,sizeof(**phQ_max));
+        phQ_instant[i]=calloc(blocksize/2+1,sizeof(**phQ_instant));
+      }
     }
 
     prev_total_ch = total_ch;
@@ -139,50 +166,73 @@
 }
 
 void rundata_clear(){
-  int i,j;
+  int i;
   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));
-    memset(feedback_max[i],0,(blocksize/2+1)*sizeof(**feedback_max));
-    memset(feedback_instant[i],0,(blocksize/2+1)*sizeof(**feedback_instant));
+    memset(mag_acc[i],0,(blocksize/2+1)*sizeof(**mag_acc));
+    memset(mag_max[i],0,(blocksize/2+1)*sizeof(**mag_max));
+    memset(mag_instant[i],0,(blocksize/2+1)*sizeof(**mag_instant));
 
-    for(j=0;j<blocksize+2;j++){
-      ph_acc[i][j]=0;
-      ph_max[i][j]=0;
-      ph_instant[i][j]=0;
+    if(i>0){
+      memset(phI_acc[i],0,(blocksize/2+1)*sizeof(**phI_acc));
+      memset(phQ_acc[i],0,(blocksize/2+1)*sizeof(**phQ_acc));
+      memset(phI_max[i],0,(blocksize/2+1)*sizeof(**phI_max));
+      memset(phQ_max[i],0,(blocksize/2+1)*sizeof(**phQ_max));
+      memset(phI_instant[i],0,(blocksize/2+1)*sizeof(**phI_instant));
+      memset(phQ_instant[i],0,(blocksize/2+1)*sizeof(**phQ_instant));
     }
   }
   pthread_mutex_unlock(&feedback_mutex);
 }
 
-/* return 0 on EOF, 1 otherwise */
-static int process(){
-  int fi,i,j,ch;
+char *bw_entries[]=
+  {"native","display",
+   ".1Hz",".3Hz","1Hz","3Hz","10Hz","30Hz","100Hz",NULL};
+float bw_values[]=
+  {0., 0., .1, .3, 1, 3, 10, 30, 100};
 
-  if(acc_rewind)
-    rewind_files();
-  acc_rewind=0;
+//static int bandwidth_choice=0;
+//static float bandwidth=-1;
+//static int detector_mode=0;
 
-  if(input_read(acc_loop,0))
-    return 0;
+void set_bandwidth_detector(int bw, int det){
+#if 0
+  pthread_mutex_lock(&bw_mutex);
+  bandwidth_choice=bw;
+  detector_mode=det;
+  compute_bandwidth();
+  pthread_mutex_unlock(&bw_mutex);
 
+  pthread_mutex_lock(&feedback_mutex);
+  rundata_clear();
+  accumulate_feedback();
+  pthread_mutex_unlock(&feedback_mutex);
+#endif
+}
+
+static void process(void){
   /* by channel */
-  ch=0;
+  int i,j,fi,ch=0;
   for(fi=0;fi<inputs;fi++){
-    if(blockbufferfill[fi]){
+    if(blockbuffernew[fi]){
+      blockbuffernew[fi]=0;
       for(i=ch;i<ch+channels[fi];i++){
 
+        pthread_mutex_lock(&bw_mutex);
 	float *data=blockbuffer[i];
 
-	/* window the blockbuffer into the FFT buffer */
+	/* window the blockbuffer into the FFT buffer, save a copy of
+           current frame for BW changes */
 	for(j=0;j<blocksize;j++){
-	  freqbuffer[j]=data[j]*window[j];
+	  freqbuffer[j]=window[j]*data[j];
 	}
 
 	/* transform */
 	fftwf_execute(plan);
 
+        pthread_mutex_unlock(&bw_mutex);
+
 	pthread_mutex_lock(&feedback_mutex);
 
 	/* perform desired accumulations */
@@ -192,6 +242,7 @@
 	  float sqR = R*R;
 	  float sqI = I*I;
 	  float sqM = sqR+sqI;
+          //float M = sqrtf(sqM);
 
 	  /* deal with phase accumulate/rotate */
 	  if(i==ch){
@@ -208,23 +259,23 @@
 	    pR = (rR*R - rI*I);
 	    pI = (rR*I + rI*R);
 
-	    ph_instant[i][j]=pR;
-	    ph_instant[i][j+1]=pI;
+	    phI_instant[i][j>>1]=pR;
+	    phQ_instant[i][j>>1]=pI;
 
-	    ph_acc[i][j]+=pR;
-	    ph_acc[i][j+1]+=pI;
+	    phI_acc[i][j>>1]+=pR;
+	    phQ_acc[i][j>>1]+=pI;
 
-	    if(feedback_max[i][j>>1]<sqM){
-	      ph_max[i][j]=pR;
-	      ph_max[i][j+1]=pI;
+	    if(mag_max[i][j>>1]<sqM){
+	      phI_max[i][j>>1]=pR;
+	      phQ_max[i][j>>1]=pI;
 	    }
 	  }
 
-	  feedback_instant[i][j>>1]=sqM;
-	  feedback_acc[i][j>>1]+=sqM;
+	  mag_instant[i][j>>1]=sqM;
+	  mag_acc[i][j>>1]+=sqM;
 
-	  if(feedback_max[i][j>>1]<sqM)
-	    feedback_max[i][j>>1]=sqM;
+	  if(mag_max[i][j>>1]<sqM)
+	    mag_max[i][j>>1]=sqM;
 
 	}
 	feedback_count[i]++;
@@ -234,32 +285,42 @@
     }
     ch+=channels[fi];
   }
-
-  feedback_increment++;
-  write(eventpipe[1],"",1);
-  return 1;
 }
 
 void *process_thread(void *dummy){
+  int ret;
   pthread_mutex_lock(&feedback_mutex);
   init_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();
-      rundata_clear();
-      metareload=1;
-      pthread_mutex_unlock(&feedback_mutex);
-      write(eventpipe[1],"",1);
-    }else{
-      pthread_mutex_unlock(&feedback_mutex);
-      break;
+  while(!process_exit){
+
+    if(acc_rewind) rewind_files();
+    acc_rewind=0;
+
+    ret=input_read(acc_loop,0);
+    if(ret==0) break;
+    if(ret==-1){
+      /* a pipe returned EOF; attempt reopen */
+      pthread_mutex_lock(&feedback_mutex);
+      if(pipe_reload()){
+        init_process();
+        rundata_clear();
+        metareload=1;
+        pthread_mutex_unlock(&feedback_mutex);
+        write(eventpipe[1],"",1);
+        continue;
+      }else{
+        pthread_mutex_unlock(&feedback_mutex);
+        break;
+      }
     }
+
+    process();
+    write(eventpipe[1],"",1);
   }
+
+  /* eof on all inputs */
   process_active=0;
   write(eventpipe[1],"",1);
   return NULL;
@@ -278,7 +339,7 @@
       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,"%f ",todB(mag_acc[j][i])*.5);
       fprintf(out,"\n");
     }
     fprintf(out,"\n");
@@ -293,7 +354,7 @@
       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,"%f ",todB(mag_max[j][i])*.5);
       fprintf(out,"\n");
     }
     fprintf(out,"\n");
@@ -308,7 +369,7 @@
       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,"%f ",todB(mag_instant[j][i])*.5);
       fprintf(out,"\n");
     }
     fprintf(out,"\n");
@@ -323,7 +384,7 @@
     /* 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,"%f ",atan2(phQ_acc[ch+1][i>>1],phI_acc[ch+1][i>>1])*57.29);
       fprintf(out,"\n");
     }
     fprintf(out,"\n");
@@ -343,17 +404,21 @@
 /* the data returned is now 2 vals per bin; a min and a max.  The spec
    plot merely draws a vertical line between. */
 fetchdata *process_fetch(int scale, int mode, int link,
-                         int *process_in, int height, int width){
+                         float bw, int bwmode,
+                         int *process_in, Plot *plot){
   int ch,ci,i,j,fi;
   float **data;
-  float **ph;
+  float **phI;
+  float **phQ;
   float *normptr;
   float maxrate=-1.;
   float nyq;
-  int process[total_ch];
+  int *process;
+  int width=-1;
 
   pthread_mutex_lock(&feedback_mutex);
   init_process();
+  process = alloca(total_ch*sizeof(*process));
 
   if(total_ch!=fetch_ret.total_ch){
     if(fetch_ret.data){
@@ -388,18 +453,29 @@
       ch_now+=channels[i];
       ch_in+=fetch_ret.channels[i];
     }
+
     memcpy(fetch_ret.active,process,total_ch*sizeof(*process));
   }
 
+  fetch_ret.phase_active=0;
+  if(link == LINK_PHASE){
+    int cho=0;
+    int gi;
+    for(gi=0;gi<inputs;gi++)
+      if(channels[gi]>1 && fetch_ret.active[cho+1]){
+        fetch_ret.phase_active=1;
+        break;
+      }
+  }
+
   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.height=plot_height(plot);
+  fetch_ret.width=width=plot_width(plot,fetch_ret.phase_active);
   fetch_ret.total_ch=total_ch;
-  fetch_ret.increment=feedback_increment;
 
   for(fi=0;fi<inputs;fi++)
     if(rate[fi]>maxrate)maxrate=rate[fi];
@@ -413,17 +489,6 @@
   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 || fetch_ret.reload){
     if(!xmappingL) xmappingL = calloc(inputs, sizeof(*xmappingL));
@@ -459,7 +524,6 @@
 	float hoff=1.;
 	float lfreq,mfreq,hfreq;
 
-        /* awaiting new RBW/ VBW code */
         off=.5;
 
 	switch(scale){
@@ -522,20 +586,24 @@
   normptr=NULL;
   switch(mode){
   case 0: /* independent / instant */
-    data=feedback_instant;
-    ph=ph_instant;
+    data=mag_instant;
+    phI=phI_instant;
+    phQ=phQ_instant;
     break;
   case 1: /* independent / max */
-    data=feedback_max;
-    ph=ph_max;
+    data=mag_max;
+    phI=phI_max;
+    phQ=phQ_max;
     break;
   case 2: /* independent / accumulate */
-    data=feedback_acc;
-    ph=ph_acc;
+    data=mag_acc;
+    phI=phI_acc;
+    phQ=phQ_acc;
     break;
   case 3: /* independent / average */
-    data=feedback_acc;
-    ph=ph_acc;
+    data=mag_acc;
+    phI=phI_acc;
+    phQ=phQ_acc;
     normptr=feedback_count;
     break;
   }
@@ -544,6 +612,7 @@
   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];
@@ -555,6 +624,7 @@
 
       for(ci=0;ci<channels[fi];ci++){
 	if(process[ch+ci]){
+
           float *y = fetch_ret.data[ci+ch];
           float *m = data[ci+ch];
           int prevbin;
@@ -866,7 +936,8 @@
 
 	float *r = data[ch];
 	float *m = data[ch+1];
-	float *p = ph[ch+1];
+	float *pI = phI[ch+1];
+	float *pQ = phQ[ch+1];
 
 	if(feedback_count[ch]==0){
 	  memset(om,0,width*2*sizeof(*om));
@@ -898,22 +969,22 @@
                 firsty=lasty=min=max=(a+(b-a)*del);
 
                 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]));
+                  float aP = (isnan(a) ? NAN : atan2f(pQ[mid],pI[mid]));
+                  float bP = (isnan(b) ? NAN : atan2f(pQ[mid+1],pI[mid+1]));
                   P=(aP+(bP-aP)*del)*57.29;
                 }
 
               }else{
                 firsty=min=max=m[first]/r[first];
-                R = p[first*2];
-                I = p[first*2+1];
+                R = pI[first];
+                I = pQ[first];
 
                 for(j=first+1;j<last;j++){
                   float a = m[j]/r[j];
                   if(a<min)min=a;
                   if(a>max)max=a;
-                  R += p[j*2];
-                  I += p[j*2+1];
+                  R += pI[j];
+                  I += pQ[j];
                 }
 
                 lasty=todB(m[j-1]/r[j-1]);

Modified: trunk/spectrum/spectrum.c
===================================================================
--- trunk/spectrum/spectrum.c	2012-06-14 03:25:10 UTC (rev 18404)
+++ trunk/spectrum/spectrum.c	2012-06-14 07:44:56 UTC (rev 18405)
@@ -214,15 +214,6 @@
   if(sig==SIGILL)sigill=1;
 }
 
-void blockslice_callback(void){
-  int fi;
-  /* select the full-block slice size: ~10fps */
-  for(fi=0;fi<inputs;fi++){
-    blockslice[fi]=rate[fi]/10;
-    while(blockslice[fi]>blocksize/2)blockslice[fi]/=2;
-  }
-}
-
 int main(int argc, char **argv){
 
   version=strstr(VERSION,"version.h");
@@ -302,7 +293,8 @@
   //signal(SIGINT,handler);
   signal(SIGSEGV,handler);
 
-  if(input_load(blockslice_callback))exit(1);
+  blockslice_frac=10;
+  if(input_load())exit(1);
 
   /* go */
   panel_go(argc,argv);

Modified: trunk/spectrum/version.h
===================================================================
--- trunk/spectrum/version.h	2012-06-14 03:25:10 UTC (rev 18404)
+++ trunk/spectrum/version.h	2012-06-14 07:44:56 UTC (rev 18405)
@@ -1,2 +1,2 @@
 #define VERSION "$Id$ "
-/* DO NOT EDIT: Automated versioning hack [Sun Jun  3 23:19:05 EDT 2012] */
+/* DO NOT EDIT: Automated versioning hack [Thu Jun 14 03:43:07 EDT 2012] */

Modified: trunk/spectrum/wave_panel.c
===================================================================
--- trunk/spectrum/wave_panel.c	2012-06-14 03:25:10 UTC (rev 18404)
+++ trunk/spectrum/wave_panel.c	2012-06-14 07:44:56 UTC (rev 18405)
@@ -60,7 +60,6 @@
 int plot_hold=0;
 int plot_bold=0;
 int plot_sep=0;
-int plot_rate[MAX_FILES] = {-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1};
 
 /* first up... the Fucking Fish */
 sig_atomic_t increment_fish=0;
@@ -121,14 +120,6 @@
   }
 }
 
-static void set_slices(int interval, int span){
-  int fi;
-  /* update interval limited to < 25fps */
-  //int temp = (interval < 50000 ? 50000:interval),fi;
-  for(fi=0;fi<plot_inputs;fi++)
-    set_blockslice(rint(plot_rate[fi]/1000000.*interval),fi);
-}
-
 static void override_base(GtkWidget *w, int active){
   gtk_widget_modify_base
     (w, GTK_STATE_NORMAL,
@@ -287,7 +278,6 @@
     break;
   }
 
-  set_slices(plot_interval,plot_span);
   replot();
 }
 
@@ -295,48 +285,48 @@
   int choice=gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
   switch(choice){
   case 0:
-    plot_interval=1000000;
+    plot_interval=1;
     break;
   case 1:
-    plot_interval=500000;
+    plot_interval=2;
     break;
   case 2:
-    plot_interval=200000;
+    plot_interval=5;
     break;
   case 3:
-    plot_interval=100000;
+    plot_interval=10;
     break;
   case 4:
-    plot_interval=50000; // 20/sec
+    plot_interval=20;
     break;
   case 5:
-    plot_interval=20000; // 50/sec
+    plot_interval=50;
     break;
   case 6:
-    plot_interval=10000;
+    plot_interval=100;
     break;
   case 7:
-    plot_interval=5000;
+    plot_interval=200;
     break;
   case 8:
-    plot_interval=2000;
+    plot_interval=500;
     break;
   case 9:
     plot_interval=1000;
     break;
   case 10:
-    plot_interval=500;
+    plot_interval=2000;
     break;
   case 11:
-    plot_interval=200;
+    plot_interval=5000;
     break;
   case 12:
-    plot_interval=100;
+    plot_interval=10000;
     break;
   }
 
-  set_slices(plot_interval,plot_span);
-  replot();
+  blockslice_frac = plot_interval;
+  //replot();
 }
 
 static void triggerchange(GtkWidget *widget,gpointer in){
@@ -466,10 +456,6 @@
      changed... */
   if(f->reload){
 
-    /* update group block slices */
-    memcpy(plot_rate,f->rate,sizeof(plot_rate));
-    set_slices(plot_interval,plot_span);
-
     /* remove old group labels and channel buttons */
     destroy_chbuttons();
 
@@ -875,7 +861,6 @@
 
   plot_ch = total_ch; /* true now, won't necessarily be true later */
   plot_inputs = inputs; /* true now, won't necessarily be true later */
-  memcpy(plot_rate,rate,sizeof(plot_rate));
 
   panel_create();
   animate_fish();

Modified: trunk/spectrum/wave_plot.h
===================================================================
--- trunk/spectrum/wave_plot.h	2012-06-14 03:25:10 UTC (rev 18404)
+++ trunk/spectrum/wave_plot.h	2012-06-14 07:44:56 UTC (rev 18405)
@@ -44,7 +44,6 @@
 
   float **data;
   int *active;
-  int increment;
 } fetchdata;
 
 typedef struct {

Modified: trunk/spectrum/wave_process.c
===================================================================
--- trunk/spectrum/wave_process.c	2012-06-14 03:25:10 UTC (rev 18404)
+++ trunk/spectrum/wave_process.c	2012-06-14 07:44:56 UTC (rev 18405)
@@ -24,9 +24,6 @@
 #include "waveform.h"
 #include "io.h"
 
-static pthread_mutex_t feedback_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
-static int feedback_increment=0;
-
 sig_atomic_t process_active=0;
 sig_atomic_t process_exit=0;
 
@@ -35,42 +32,49 @@
 
 static int metareload = 0;
 
-static void init_process(void){
+static void process_init(){
+  if(blocksize==0){
+    int fi;
+    /* set block size equal to maximum input rate + epsilon */
+    /* (maximum display width: 1s, maximum update interval 1s) */
+    for(fi=0;fi<inputs;fi++)
+      if(rate[fi]>blocksize)blocksize=rate[fi]+16;
+  }
 }
 
 /* return 0 on EOF, 1 otherwise */
-static int process(){
-  if(acc_rewind)
-    rewind_files();
-  acc_rewind=0;
+void *process_thread(void *dummy){
+  int ret;
 
-  if(input_read(acc_loop,1))
-    return 0;
+  while(!process_exit){
 
-  feedback_increment++;
-  write(eventpipe[1],"",1);
-  return 1;
-}
+    process_init();
 
-void *process_thread(void *dummy){
-  pthread_mutex_lock(&feedback_mutex);
-  init_process();
-  pthread_mutex_unlock(&feedback_mutex);
+    if(acc_rewind) rewind_files();
+    acc_rewind=0;
 
-  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);
-      write(eventpipe[1],"",1);
-    }else{
-      pthread_mutex_unlock(&feedback_mutex);
-      break;
+    ret=input_read(acc_loop,1);
+    if(ret==0) break;
+    if(ret==-1){
+      /* a pipe returned EOF; attempt reopen */
+      pthread_mutex_lock(&blockbuffer_mutex);
+      if(pipe_reload()){
+        blocksize=0;
+        metareload=1;
+        pthread_mutex_unlock(&blockbuffer_mutex);
+        write(eventpipe[1],"",1);
+        continue;
+      }else{
+        pthread_mutex_unlock(&blockbuffer_mutex);
+        break;
+      }
     }
+
+    write(eventpipe[1],"",1);
+
   }
+
+  /* eof on all inputs */
   process_active=0;
   write(eventpipe[1],"",1);
   return NULL;
@@ -82,14 +86,12 @@
   int fi,i,k,ch;
   int process[total_ch];
 
-  pthread_mutex_lock(&feedback_mutex);
+  pthread_mutex_lock(&blockbuffer_mutex);
   if(!blockbuffer){
-    pthread_mutex_unlock(&feedback_mutex);
+    pthread_mutex_unlock(&blockbuffer_mutex);
     return NULL;
   }
 
-  init_process();
-
   if(metareload){
     if(fetch_ret.data){
       for(i=0;i<fetch_ret.total_ch;i++)
@@ -134,7 +136,6 @@
   fetch_ret.span=span;
   fetch_ret.range=range;
   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));
@@ -173,6 +174,6 @@
     ch+=channels[fi];
   }
 
-  pthread_mutex_unlock(&feedback_mutex);
+  pthread_mutex_unlock(&blockbuffer_mutex);
   return &fetch_ret;
 }

Modified: trunk/spectrum/waveform.c
===================================================================
--- trunk/spectrum/waveform.c	2012-06-14 03:25:10 UTC (rev 18404)
+++ trunk/spectrum/waveform.c	2012-06-14 07:44:56 UTC (rev 18405)
@@ -33,7 +33,7 @@
 char *version;
 char *inputname[MAX_FILES];
 int inputs=0;
-int blocksize = 131072; /* starting default */
+int blocksize=0;
 extern int plot_bold;
 
 void handler(int sig){
@@ -202,15 +202,6 @@
   if(sig==SIGILL)sigill=1;
 }
 
-void blocksize_callback(void){
-  int fi;
-  /* set block size equal to maximum input rate + epsilon*/
-  /* (maximum display width: 1s, maximum update interval 1s) */
-  blocksize=0;
-  for(fi=0;fi<inputs;fi++)
-    if(rate[fi]>blocksize)blocksize=rate[fi]+16;
-}
-
 int main(int argc, char **argv){
   int fi;
 
@@ -291,12 +282,17 @@
   //signal(SIGINT,handler);
   signal(SIGSEGV,handler);
 
-  if(input_load(blocksize_callback))exit(1);
+  if(input_load())exit(1);
 
+  /* set block size equal to maximum input rate + epsilon*/
+  /* (maximum display width: 1s, maximum update interval 1s) */
+  blocksize=0;
+  for(fi=0;fi<inputs;fi++)
+    if(rate[fi]>blocksize)blocksize=rate[fi]+16;
+
   /* begin with a display width of 1s */
   /* begin with an update interval (blockslice) of 100ms */
-  for(fi=0;fi<inputs;fi++)
-    blockslice[fi]=rate[fi]/10;
+  blockslice_frac = 10;
 
   panel_go(argc,argv);
 



More information about the commits mailing list