[xiph-cvs] r6712 - trunk/postfish

xiphmont at xiph.org xiphmont at xiph.org
Mon May 17 01:16:58 PDT 2004



Author: xiphmont
Date: 2004-05-17 04:16:56 -0400 (Mon, 17 May 2004)
New Revision: 6712

Added:
   trunk/postfish/mix.c
   trunk/postfish/mix.h
   trunk/postfish/mixpanel.c
   trunk/postfish/mixpanel.h
   trunk/postfish/reverb.c
   trunk/postfish/reverb.h
Removed:
   trunk/postfish/mutedummy.c
Modified:
   trunk/postfish/Makefile
   trunk/postfish/bessel.c
   trunk/postfish/bessel.h
   trunk/postfish/clippanel.c
   trunk/postfish/compandpanel.c
   trunk/postfish/declip.c
   trunk/postfish/eq.c
   trunk/postfish/eq.h
   trunk/postfish/eqpanel.c
   trunk/postfish/freq.c
   trunk/postfish/freq.h
   trunk/postfish/input.c
   trunk/postfish/limit.c
   trunk/postfish/limit.h
   trunk/postfish/limitpanel.c
   trunk/postfish/main.c
   trunk/postfish/mainpanel.c
   trunk/postfish/mainpanel.h
   trunk/postfish/multibar.c
   trunk/postfish/multicompand.c
   trunk/postfish/multicompand.h
   trunk/postfish/mute.c
   trunk/postfish/output.c
   trunk/postfish/postfish.h
   trunk/postfish/singlecomp.c
   trunk/postfish/singlecomp.h
   trunk/postfish/singlepanel.c
   trunk/postfish/subband.c
   trunk/postfish/subband.h
   trunk/postfish/suppress.c
   trunk/postfish/suppresspanel.c
   trunk/postfish/version.h
Log:
Weekend dabbling in postfish

fromdB_a approximation guarding fix
bounds fix in subband filter setup
Altivec underflow exception disabling
mixdown block implementation
reverberation driver (untested)

<p><p>Modified: trunk/postfish/Makefile
===================================================================
--- trunk/postfish/Makefile	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/Makefile	2004-05-17 08:16:56 UTC (rev 6712)
@@ -2,26 +2,34 @@
 # Fuck the horse it rode in on
 # and Fuck its little dog Libtool too
 
-ADD_DEF= -DUGLY_IEEE754_FLOAT32_HACK=1
+
+ADD_DEF= -DUGLY_IEEE754_FLOAT32_HACK=1 -maltivec
+
+# use for PPC with altivec.  IF YOU HAVE ALTIVEC, YOU MUST USE THIS
+# LINE, otherwise FFTW3 will randomly crash whenever it uses Altivec
+# and any math denormalizes.
+
+#ADD_DEF= -DUGLY_IEEE754_FLOAT32_HACK=1 -maltivec
+
 CC=gcc 
 LD=gcc
 INSTALL=install
 PREFIX=/usr/local
 BINDIR=$PREFIX/bin
-ETCDIR=/etc
+ETCDIR=/etc/postfish
 MANDIR=$PREFIX/man
 
 SRC = main.c mainpanel.c multibar.c readout.c input.c output.c clippanel.c \
         declip.c reconstruct.c multicompand.c windowbutton.c subpanel.c \
         feedback.c freq.c eq.c eqpanel.c compandpanel.c subband.c lpc.c \
         bessel.c suppresspanel.c suppress.c singlecomp.c singlepanel.c \
-	limit.c limitpanel.c mute.c mutedummy.c
+	limit.c limitpanel.c mute.c mixpanel.c mix.c reverb.c
 OBJ = main.o mainpanel.o multibar.o readout.o input.o output.o clippanel.o \
         declip.o reconstruct.o multicompand.o windowbutton.o subpanel.o \
         feedback.o freq.o eq.o eqpanel.o compandpanel.o subband.o lpc.o \
         bessel.o suppresspanel.o suppress.o singlecomp.o singlepanel.o \
-	limit.o limitpanel.o mute.o mutedummy.o
-GCF = `pkg-config --cflags gtk+-2.0` -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED
+	limit.o limitpanel.o mute.o mixpanel.o mix.o reverb.o
+GCF = -DETCDIR=\\\"$(ETCDIR)\\\" `pkg-config --cflags gtk+-2.0` -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED
 
 all:	
         $(MAKE) target CFLAGS="-O3 -ffast-math -fomit-frame-pointer $(GCF) $(ADD_DEF)"
@@ -30,27 +38,44 @@
         $(MAKE) target CFLAGS="-g -Wall -W -Wno-unused-parameter -D__NO_MATH_INLINES $(GCF) $(ADD_DEF)"
 
 profile:
-	$(MAKE) target CFLAGS="-pg -g -O3 -ffast-math $(GCF) $(ADD_DEF)" LIBS="-lgprof-helper"
+	$(MAKE) target CFLAGS="-pg -g -O3 -ffast-math $(GCF) $(ADD_DEF)" LIBS="-lgprof-helper "
 
 clean:
-	rm -f $(OBJ) *.d *.d.* gmon.out
+	rm -f $(OBJ) *.d *.d.* gmon.out postfish
 
+distclean: clean
+	rm -f postfish-wisdomrc
+
 %.d: %.c
-	$(CC) -M $(GCF) $< > $@.$$$$; sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; rm -f $@.$$$$
+	$(CC) -M $(CFLAGS) $< > $@.$$$$; sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; rm -f $@.$$$$
 
-ifneq ($(MAKECMDGOALS),clean)
+postfish-wisdomrc:
+	fftwf-wisdom -v -o postfish-wisdomrc \
+	rif32 rof32 rib32 rob32 \
+	rif64 rof64 rib64 rob64 \
+	rif128 rof128 rib128 rob128 \
+	rif256 rof256 rib256 rob256 \
+	rif512 rof512 rib512 rob512 \
+	rif1024 rof1024 rib1024 rob1024 \
+	rif2048 rof2048 rib2048 rob2048 \
+	rif4096 rof4096 rib4096 rob4096 \
+	rif8192 rof8192 rib8192 rob8192 \
+	rif16384 rof16384 rib16384 rob16384
+
+ifeq ($(MAKECMDGOALS),target)
 include $(SRC:.c=.d)
 endif
 
-target: $(OBJ) 
+target:  $(OBJ) postfish-wisdomrc
         ./touch-version
-	$(LD) $(OBJ) $(CFLAGS) -o postfish $(LIBS) `pkg-config --libs gtk+-2.0` -lpthread -lfftw3f -lm
+	$(LD) $(OBJ) $(CFLAGS) -o postfish $(LIBS) `pkg-config --libs gtk+-2.0` -lpthread -lfftw3f -lm 
 
-install:
+install: target
         $(INSTALL) -d -m 0755 $(BINDIR)
         $(INSTALL) -m 0755 postfish $(BINDIR)
         $(INSTALL) -d -m 0755 $(ETCDIR)
         $(INSTALL) -m 0644 postfish-gtkrc $(ETCDIR)
+	$(INSTALL) -m 0644 postfish-wisdomrc $(ETCDIR)
 #	$(INSTALL) -d -m 0755 $(MANDIR)
 #	$(INSTALL) -d -m 0755 $(MANDIR)/man1
 #	$(INSTALL) -m 0644 postfish.1 $(MANDIR)/man1

Modified: trunk/postfish/bessel.c
===================================================================
--- trunk/postfish/bessel.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/bessel.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -302,6 +302,39 @@
   
 }
 
+void compute_iir_decayonly2(float *x, int n, iir_state *is, 
+			    iir_filter *decay){
+  double d_c0=decay->c[0];
+  double d_c1=decay->c[1];
+  double d_g=decay->g;
+  
+  double x0=is->x[0];
+  double x1=is->x[1];
+  double y0=is->y[0];
+  double y1=is->y[1];
+  int i=0;
+
+  while(i<n){
+    double yd;
+
+    if(y1<y0)y1=y0; // slope fixup
+
+    yd = (x[i]+x0*2.+x1)/d_g + y0*d_c0+y1*d_c1;
+    
+    if(x[i]>yd)yd=x[i];
+    
+    x1=x0;x0=x[i];
+    y1=y0;x[i]=y0=yd;
+    i++;
+  }
+  
+  is->x[0]=x0;
+  is->x[1]=x1;
+  is->y[0]=y0;
+  is->y[1]=y1;
+  
+}
+
 void compute_iir_freefall3(float *x, int n, iir_state *is, 
                           iir_filter *decay){
   double d_c0=decay->c[0];

Modified: trunk/postfish/bessel.h
===================================================================
--- trunk/postfish/bessel.h	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/bessel.h	2004-05-17 08:16:56 UTC (rev 6712)
@@ -33,6 +33,7 @@
   float alpha; 
   float Hz; 
   float ms; 
+  int   samples;
 } iir_filter;
 
 static inline long impulse_ahead2(float alpha){
@@ -84,6 +85,8 @@
                                  iir_filter *decay);
 extern void compute_iir_freefall2(float *x, int n, iir_state *is, 
                                  iir_filter *decay);
+extern void compute_iir_decayonly2(float *x, int n, iir_state *is, 
+				 iir_filter *decay);
 extern void compute_iir_freefall3(float *x, int n, iir_state *is, 
                                  iir_filter *decay);
 extern void compute_iir_freefall4(float *x, int n, iir_state *is, 

Modified: trunk/postfish/clippanel.c
===================================================================
--- trunk/postfish/clippanel.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/clippanel.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -116,7 +116,7 @@
                       GtkWidget **windowbutton,
                       GtkWidget **activebutton){
   int i;
-  char *labels[2]={"10%","100%"};
+  char *labels[3]={"","10%","100%"};
   float levels[3]={0.,10.,100.};
   int block_choices=0;
 
@@ -151,13 +151,13 @@
   for(i=64;i<=input_size*2;i*=2)block_choices++;
   {
     float levels[9]={0,1,2,3,4,5,6,7,8};
-    char *labels[8]={"128","256","512","1024","2048","4096","8192","16384"};
+    char *labels[9]={"","128","256","512","1024","2048","4096","8192","16384"};
 
     GtkWidget *table=gtk_table_new(4,2,0);
     GtkWidget *sliderbox=gtk_hbox_new(0,0);
     GtkWidget *fastlabel=gtk_label_new("fastest");
     GtkWidget *qualitylabel=gtk_label_new("best");
-    GtkWidget *slider=multibar_slider_new(block_choices-1,labels,levels,1);
+    GtkWidget *slider=multibar_slider_new(block_choices,labels,levels,1);
     GtkWidget *samplelabel=gtk_label_new("window sample width");
     GtkWidget *mslabel=gtk_label_new("window time width");
     GtkWidget *hzlabel=gtk_label_new("approximate lowest response");
@@ -193,12 +193,12 @@
   /* set up convergence config */
   {
     float levels[7]={20,40,60,80,100,120,140};
-    char *labels[6]={"40","60","80","100","120","140"};
+    char *labels[7]={"","40","60","80","100","120","140"};
     GtkWidget *table=gtk_table_new(2,2,0);
     GtkWidget *sliderbox=gtk_hbox_new(0,0);
     GtkWidget *fastlabel=gtk_label_new("fastest");
     GtkWidget *qualitylabel=gtk_label_new("best");
-    GtkWidget *slider=multibar_slider_new(6,labels,levels,1);
+    GtkWidget *slider=multibar_slider_new(7,labels,levels,1);
     GtkWidget *label=gtk_label_new("solution depth");
     depth_readout=readout_new("000dB");
 
@@ -223,12 +223,12 @@
   /* set up limit config */
   {
     float levels[7]={1,5,10,20,40,60,100};
-    char *labels[6]={"5","10","20","40","60","100"};
+    char *labels[7]={"","5","10","20","40","60","100"};
     GtkWidget *table=gtk_table_new(2,2,0);
     GtkWidget *sliderbox=gtk_hbox_new(0,0);
     GtkWidget *fastlabel=gtk_label_new("fastest");
     GtkWidget *qualitylabel=gtk_label_new("best");
-    GtkWidget *slider=multibar_slider_new(6,labels,levels,1);
+    GtkWidget *slider=multibar_slider_new(7,labels,levels,1);
     GtkWidget *label=gtk_label_new("hard iteration limit");
     limit_readout=readout_new("000%");
 
@@ -250,7 +250,7 @@
   }
 
   for(i=0;i<input_ch;i++){
-    char *slabels[8]={".05",".1",".2",".3",".4",
+    char *slabels[9]={"",".05",".1",".2",".3",".4",
                       ".6",".8","1."};
     float slevels[9]={.01,.05,.1,.2,.3,.4,.6,
                        .8,1.};
@@ -258,11 +258,11 @@
     char buffer[80];
     clipslider *cs=calloc(1,sizeof(*cs));
     GtkWidget *label;
-    GtkWidget *slider=multibar_new(8,slabels,slevels,1,
+    GtkWidget *slider=multibar_new(9,slabels,slevels,1,
                                    HI_DECAY|ZERO_DAMP);
     GtkWidget *readout=readout_new("0.00");
     GtkWidget *readoutdB=readout_new("-40dB");
-    GtkWidget *bar=multibar_new(2,labels,levels,0,
+    GtkWidget *bar=multibar_new(3,labels,levels,0,
                                 HI_DECAY|ZERO_DAMP);
 
     cs->slider=slider;

Modified: trunk/postfish/compandpanel.c
===================================================================
--- trunk/postfish/compandpanel.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/compandpanel.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -495,19 +495,19 @@
                                               subpanel_generic *panel,
                                               multicompand_settings *ms){
   int i;
-  char *labels[14]={"130","120","110","100","90","80","70",
+  char *labels[15]={"","130","120","110","100","90","80","70",
                     "60","50","40","30","20","10","0"};
   float levels[15]={-140,-130,-120,-110,-100,-90,-80,-70,-60,-50,-40,
                      -30,-20,-10,0};
 
   float compand_levels[9]={.1,.25,.5,.6667,1,1.5,2,4,10};
-  char  *compand_labels[8]={"4:1","2:1","1:1.5","1:1","1:1.5","1:2","1:4","1:10"};
+  char  *compand_labels[89]={"","4:1","2:1","1:1.5","1:1","1:1.5","1:2","1:4","1:10"};
 
   float timing_levels[6]={.5,1,10,100,1000,10000};
-  char  *timing_labels[5]={"1ms","10ms","100ms","1s","10s"};
+  char  *timing_labels[6]={"","1ms","10ms","100ms","1s","10s"};
 
   float per_levels[9]={0,12.5,25,37.5,50,62.5,75,87.5,100};
-  char  *per_labels[8]={"","25%","","50%","","75%","","100%"};
+  char  *per_labels[9]={"0%","","25%","","50%","","75%","","100%"};
 
   multi_panel_state *ps=calloc(1,sizeof(multi_panel_state));
   ps->inactive_updatep=1;
@@ -644,7 +644,7 @@
 
     GtkWidget *label=gtk_label_new("compand ratio:");
     GtkWidget *readout=readout_new("1.55:1");
-    GtkWidget *slider=multibar_slider_new(8,compand_labels,compand_levels,1);
+    GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1);
    
     ps->under_compand.r=READOUT(readout);
     ps->under_compand.v=&ps->ms->under_ratio;
@@ -667,7 +667,7 @@
     GtkWidget *label=gtk_label_new("attack/decay:");
     GtkWidget *readout0=readout_new(" 100ms");
     GtkWidget *readout1=readout_new(" 100ms");
-    GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2);
+    GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2);
 
     ps->under_timing.r0=READOUT(readout0);
     ps->under_timing.r1=READOUT(readout1);
@@ -693,7 +693,7 @@
 
     GtkWidget *label=gtk_label_new("lookahead:");
     GtkWidget *readout=readout_new("100%");
-    GtkWidget *slider=multibar_slider_new(8,per_labels,per_levels,1);
+    GtkWidget *slider=multibar_slider_new(9,per_labels,per_levels,1);
 
     ps->under_lookahead.r=READOUT(readout);
     ps->under_lookahead.v=&ps->ms->under_lookahead;
@@ -740,7 +740,7 @@
 
     GtkWidget *label=gtk_label_new("compand ratio:");
     GtkWidget *readout=readout_new("1.55:1");
-    GtkWidget *slider=multibar_slider_new(8,compand_labels,compand_levels,1);
+    GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1);
    
     ps->over_compand.r=READOUT(readout);
     ps->over_compand.v=&ps->ms->over_ratio;
@@ -763,7 +763,7 @@
     GtkWidget *label=gtk_label_new("attack/decay:");
     GtkWidget *readout0=readout_new(" 100ms");
     GtkWidget *readout1=readout_new(" 100ms");
-    GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2);
+    GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2);
    
     ps->over_timing.r0=READOUT(readout0);
     ps->over_timing.r1=READOUT(readout1);
@@ -789,7 +789,7 @@
 
     GtkWidget *label=gtk_label_new("lookahead:");
     GtkWidget *readout=readout_new("100%");
-    GtkWidget *slider=multibar_slider_new(8,per_labels,per_levels,1);
+    GtkWidget *slider=multibar_slider_new(9,per_labels,per_levels,1);
    
     ps->over_lookahead.r=READOUT(readout);
     ps->over_lookahead.v=&ps->ms->over_lookahead;
@@ -832,7 +832,7 @@
 
     GtkWidget *label=gtk_label_new("compand ratio:");
     GtkWidget *readout=readout_new("1.55:1");
-    GtkWidget *slider=multibar_slider_new(8,compand_labels,compand_levels,1);
+    GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1);
    
     ps->base_compand.r=READOUT(readout);
     ps->base_compand.v=&ps->ms->base_ratio;
@@ -855,7 +855,7 @@
     GtkWidget *label=gtk_label_new("attack/decay:");
     GtkWidget *readout0=readout_new(" 100ms");
     GtkWidget *readout1=readout_new(" 100ms");
-    GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2);
+    GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2);
 
     ps->base_timing.r0=READOUT(readout0);
     ps->base_timing.r1=READOUT(readout1);
@@ -884,7 +884,7 @@
     
     ps->bars[i].readoutu=readout_new("  +0");
     ps->bars[i].readouto=readout_new("  +0");
-    ps->bars[i].slider=multibar_new(14,labels,levels,2,HI_DECAY|LO_DECAY|LO_ATTACK);
+    ps->bars[i].slider=multibar_new(15,labels,levels,2,HI_DECAY|LO_DECAY|LO_ATTACK);
     ps->bars[i].number=i;
     ps->bars[i].mp=ps;
     ps->bars[i].label=label;
@@ -911,7 +911,7 @@
   {
     GtkWidget *label=gtk_label_new("average");
     
-    ps->bars[multicomp_freqs_max].slider=multibar_slider_new(14,labels,levels,2);
+    ps->bars[multicomp_freqs_max].slider=multibar_slider_new(15,labels,levels,2);
 
     multibar_callback(MULTIBAR(ps->bars[multicomp_freqs_max].slider),average_change,ps);
 
@@ -982,15 +982,15 @@
     rmsfeed=malloc(sizeof(*rmsfeed)*multicomp_freqs_max);
 
     for(i=0;i<multicomp_freqs_max;i++){
-      peakfeed[i]=malloc(sizeof(**peakfeed)*input_ch);
-      rmsfeed[i]=malloc(sizeof(**rmsfeed)*input_ch);
+      peakfeed[i]=malloc(sizeof(**peakfeed)*max(input_ch,OUTPUT_CHANNELS));
+      rmsfeed[i]=malloc(sizeof(**rmsfeed)*max(input_ch,OUTPUT_CHANNELS));
     }
   }
 
   if(pull_multicompand_feedback_master(peakfeed,rmsfeed,&bands)==1)
     for(i=0;i<bands;i++)
       multibar_set(MULTIBAR(master_panel->bars[i].slider),rmsfeed[i],peakfeed[i],
-		   input_ch,(displayit && multi_master_set.panel_visible));
+		   OUTPUT_CHANNELS,(displayit && multi_master_set.panel_visible));
 
   /* channel panels are a bit different; we want each in its native color */
   if(pull_multicompand_feedback_channel(peakfeed,rmsfeed,&bands)==1){

Modified: trunk/postfish/declip.c
===================================================================
--- trunk/postfish/declip.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/declip.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -156,9 +156,7 @@
   for(i=0;i<input_ch;i++)
     chtrigger[i]=1.;
   
-  out.size=input_size;
   out.channels=input_ch;
-  out.rate=input_rate;
   out.data=malloc(input_ch*sizeof(*out.data));
   for(i=0;i<input_ch;i++)
     out.data[i]=malloc(input_size*sizeof(**out.data));
@@ -363,7 +361,7 @@
         memcpy(lap[i],work+blocksize,sizeof(*work)*blocksize/2);
 
         /* now iterate the pieces purely within in */
-	for(j=0;j+blocksize<=in->size;j+=blocksize/2){
+	for(j=0;j+blocksize<=input_size;j+=blocksize/2){
           memset(work,0,sizeof(*work)*blocksize);
           memcpy(work+blocksize/2,in->data[i]+j,sizeof(*work)*blocksize);
           memset(work+blocksize+blocksize/2,0,sizeof(*work)*blocksize/2);
@@ -394,10 +392,10 @@
     cache_active=in->active;
     fillstate=1;
     out.samples=0;
-    if(in->samples==in->size)break;
+    if(in->samples==input_size)break;
     
     for(i=0;i<input_ch;i++)
-      memset(in->data[i],0,sizeof(**in->data)*in->size);
+      memset(in->data[i],0,sizeof(**in->data)*input_size);
     in->samples=0;
     /* fall through */
 
@@ -589,7 +587,7 @@
         /* declip */
         if(declip_prev_active[i]){
           
-	  for(j=0;j+blocksize<=in->size;j+=blocksize/2){
+	  for(j=0;j+blocksize<=input_size;j+=blocksize/2){
             memset(work,0,sizeof(*work)*blocksize);
             memcpy(work+blocksize/2,cache[i]+j,sizeof(*work)*blocksize);
             memset(work+blocksize+blocksize/2,0,sizeof(*work)*blocksize/2);
@@ -607,7 +605,7 @@
         }
       }
     }
-    if(out.samples<out.size)fillstate=2;
+    if(out.samples<input_size)fillstate=2;
     break;
   case 2: /* we've pushed out EOF already */
     out.samples=0;
@@ -622,7 +620,7 @@
                                              comes in */
 
   {
-    int tozero=out.size-out.samples;
+    int tozero=input_size-out.samples;
     if(tozero)
       for(i=0;i<out.channels;i++)
         memset(out.data[i]+out.samples,0,sizeof(**out.data)*tozero);

Modified: trunk/postfish/eq.c
===================================================================
--- trunk/postfish/eq.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/eq.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -32,6 +32,7 @@
 typedef struct{
 
   freq_state eq;
+  int ch;
 
 } eq_state;
 
@@ -42,7 +43,6 @@
 static eq_state master_state;
 static eq_state channel_state;
 
-
 /* accessed only in playback thread/setup */
 int pull_eq_feedback_master(float **peak,float **rms){
   return pull_freq_feedback(&master_state.eq,peak,rms);
@@ -53,15 +53,17 @@
 }
 
 /* called only by initial setup */
-int eq_load(void){
+int eq_load(int outch){
   int i;
 
   eq_channel_set=calloc(input_ch,sizeof(*eq_channel_set));
 
   freq_class_load(&fc,eq_freq_list,eq_freqs);
 
-  freq_load(&master_state.eq,&fc);
-  freq_load(&channel_state.eq,&fc);
+  freq_load(&master_state.eq,&fc,outch);
+  master_state.ch=outch;
+  freq_load(&channel_state.eq,&fc,input_ch);
+  channel_state.ch=input_ch;
 
   eq_master_set.curve_dirty=1;
 
@@ -118,11 +120,12 @@
 
 /* called only by playback thread */
 time_linkage *eq_read_master(time_linkage *in){
-  int active[input_ch];
-  int visible[input_ch];
+  eq_state *eq=&master_state;
+  int active[eq->ch];
+  int visible[eq->ch];
   int i;
   
-  for(i=0;i<input_ch;i++){
+  for(i=0;i<eq->ch;i++){
     active[i]=eq_master_set.panel_active;
     visible[i]=eq_master_set.panel_visible;
   }
@@ -131,11 +134,12 @@
 }
 
 time_linkage *eq_read_channel(time_linkage *in){
-  int active[input_ch];
-  int visible[input_ch];
+  eq_state *eq=&channel_state;
+  int active[eq->ch];
+  int visible[eq->ch];
   int i;
   
-  for(i=0;i<input_ch;i++){
+  for(i=0;i<eq->ch;i++){
     active[i]=eq_channel_set[i].panel_active;
     visible[i]=eq_channel_set[i].panel_visible;
   }

Modified: trunk/postfish/eq.h
===================================================================
--- trunk/postfish/eq.h	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/eq.h	2004-05-17 08:16:56 UTC (rev 6712)
@@ -51,7 +51,7 @@
 
 extern int pull_eq_feedback_master(float **peak,float **rms);
 extern int pull_eq_feedback_channel(float **peak,float **rms);
-extern int eq_load(void);
+extern int eq_load(int ch);
 extern int eq_reset();
 extern void eq_set(eq_settings *eq,int freq, float value);
 extern time_linkage *eq_read_master(time_linkage *in);

Modified: trunk/postfish/eqpanel.c
===================================================================
--- trunk/postfish/eqpanel.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/eqpanel.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -66,7 +66,7 @@
                            eq_settings *es){
 
   int i;
-  char *labels[15]={"110","100","90","80","70","60","50","40",
+  char *labels[16]={"","110","100","90","80","70","60","50","40",
                     "30","20","10","0","+10","+20","+30"};
   float levels[16]={-120,-110,-100,-90,-80,-70,-60,-50,-40,
                      -30,-20,-10,0,10,20,30};
@@ -81,7 +81,7 @@
     gtk_widget_set_name(label,"smallmarker");
 
     bars[i].readout=readout_new("+00dB");
-    bars[i].slider=multibar_new(15,labels,levels,1,
+    bars[i].slider=multibar_new(16,labels,levels,1,
                                 LO_DECAY|HI_DECAY|LO_ATTACK|HI_ATTACK);
     bars[i].number=i;
     bars[i].s=es;
@@ -125,7 +125,7 @@
                                  GtkWidget **windowbutton,
                                  GtkWidget **activebutton){
   int i;
-  c_bars=malloc(input_ch*sizeof(*m_bars));
+  c_bars=malloc(input_ch*sizeof(*c_bars));
 
   /* a panel for each channel */
   for(i=0;i<input_ch;i++){
@@ -154,15 +154,15 @@
     rmsfeed=malloc(sizeof(*rmsfeed)*eq_freqs);
 
     for(i=0;i<eq_freqs;i++){
-      peakfeed[i]=malloc(sizeof(**peakfeed)*input_ch);
-      rmsfeed[i]=malloc(sizeof(**rmsfeed)*input_ch);
+      peakfeed[i]=malloc(sizeof(**peakfeed)*max(input_ch,OUTPUT_CHANNELS));
+      rmsfeed[i]=malloc(sizeof(**rmsfeed)*max(input_ch,OUTPUT_CHANNELS));
     }
   }
   
   if(pull_eq_feedback_master(peakfeed,rmsfeed)==1)
     for(i=0;i<eq_freqs;i++)
       multibar_set(MULTIBAR(m_bars[i].slider),rmsfeed[i],peakfeed[i],
-		   input_ch,(displayit && eq_master_set.panel_visible));
+		   OUTPUT_CHANNELS,(displayit && eq_master_set.panel_visible));
   
 
   if(pull_eq_feedback_channel(peakfeed,rmsfeed)==1){

Modified: trunk/postfish/freq.c
===================================================================
--- trunk/postfish/freq.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/freq.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -29,7 +29,6 @@
 #include "lpc.h"
 
 extern int input_rate;
-extern int input_ch;
 extern int input_size;
 
 /* feedback! */
@@ -49,7 +48,7 @@
 
 int pull_freq_feedback(freq_state *ff,float **peak,float **rms){
   freq_feedback *f=(freq_feedback *)feedback_pull(&ff->feedpool);
-  int i;
+  int i,ch=ff->out.channels;
   
   if(!f)return 0;
   
@@ -59,10 +58,10 @@
   }else{
     if(peak)
       for(i=0;i<ff->fc->bands;i++)
-	memcpy(peak[i],f->peak[i],sizeof(**peak)*input_ch);
+	memcpy(peak[i],f->peak[i],sizeof(**peak)*ch);
     if(rms)
       for(i=0;i<ff->fc->bands;i++)
-	memcpy(rms[i],f->rms[i],sizeof(**rms)*input_ch);
+	memcpy(rms[i],f->rms[i],sizeof(**rms)*ch);
     feedback_old(&ff->feedpool,(feedback_generic *)f);
     return 1;
   }
@@ -101,91 +100,101 @@
   /* I'm too lazy to figure out the integral symbolically, use this
      fancy CPU thingy for something */
   
+  f->ho_area=calloc(bands,sizeof(*f->ho_area));
   f->ho_window=malloc(bands*sizeof(*f->ho_window));
-  f->ho_area=calloc(bands,sizeof(*f->ho_area));
-  {
-    float working[f->qblocksize*4+2];
-    
+  for(i=0;i<bands;i++)
+    f->ho_window[i]=calloc((f->qblocksize*2+1),sizeof(**f->ho_window));
+
+  /* first, build the first-pass desired, supersampled response */
+  for(j=0;j<(((f->qblocksize*2+1)/10)<<5);j++){
+    float localf= .5*j*input_rate/(f->qblocksize<<6);
+    int localbin= j>>5;
+
     for(i=0;i<bands;i++){
       float lastf=(i>0?frequencies[i-1]:0);
       float thisf=frequencies[i];
       float nextf=frequencies[i+1];
-      memset(working,0,sizeof(working));
 
-      for(j=0;j<((f->qblocksize*2+1)<<5);j++){
-        float localf= .5*j*input_rate/(f->qblocksize<<6);
-        int localbin= j>>5;
-        float localwin;
+      if(localf>=lastf && localf<nextf){
+	float localwin=1.;
+	if(localf<thisf){
+	  if(i!=0)localwin= sin((localf-lastf)/(thisf-lastf)*M_PIl*.5);
+	}else{
+	  if(i+1!=bands)localwin= sin((nextf-localf)/(nextf-thisf)*M_PIl*.5);
+	}
 
-        if(localf>=lastf && localf<thisf){
-          if(i==0)
-            localwin=1.;
-          else
-            localwin= sin((localf-lastf)/(thisf-lastf)*M_PIl*.5);
-          localwin*=localwin;
-	  working[localbin]+=localwin*(1./32);
-
-        }else if(localf>=thisf && localf<nextf){
-          if(i+1==bands)
-            localwin=1.;
-          else
-            localwin= sin((nextf-localf)/(nextf-thisf)*M_PIl*.5);
-          
-          localwin*=localwin;
-          working[localbin]+=localwin*(1./32);
-          
-        }
+	localwin*=localwin;
+	f->ho_window[i][localbin]+=localwin*(1./32);
       }
+    }
+  }
+  j>>=5;
+  for(;j<f->qblocksize*2+1;j++){
+    float localf= .5*j*input_rate/(f->qblocksize<<1);
 
-      /* window this desired response in the time domain so that our
-         convolution is properly padded against being circular */
-      memset(f->fftwf_buffer,0,sizeof(*f->fftwf_buffer)*
-	     (f->qblocksize*4+2));
-      for(j=0;j<f->qblocksize*2;j++)
-	f->fftwf_buffer[j*2]=working[j];
-      
-      fftwf_execute(f->fftwf_backward);
+    for(i=0;i<bands;i++){
+      float lastf=(i>0?frequencies[i-1]:0);
+      float thisf=frequencies[i];
+      float nextf=frequencies[i+1];
 
-      /* window response in time */
-      for(j=0;j<f->qblocksize;j++){
-	float val=cos(j*M_PI/(f->qblocksize*2));
-	val=sin(val*val*M_PIl*.5);
-	f->fftwf_buffer[j]*= sin(val*val*M_PIl*.5);
-      }
+      if(localf>=lastf && localf<nextf){
+	float localwin=1.;
+	if(localf<thisf){
+	  if(i!=0)localwin= sin((localf-lastf)/(thisf-lastf)*M_PIl*.5);
+	}else{
+	  if(i+1!=bands)localwin= sin((nextf-localf)/(nextf-thisf)*M_PIl*.5);
+	}
 
-      for(;j<f->qblocksize*3;j++)
-	f->fftwf_buffer[j]=0.;
-      
-      for(;j<f->qblocksize*4;j++){
-	float val=sin((j-f->qblocksize*3)*M_PI/(f->qblocksize*2));
-	val=sin(val*val*M_PIl*.5);
-	f->fftwf_buffer[j]*=sin(val*val*M_PIl*.5);
+	f->ho_window[i][j]+=localwin*localwin;
       }
+    }
+  }
 
-      /* back to frequency; this is all-real data still */
-      fftwf_execute(f->fftwf_forward);
-      for(j=0;j<f->qblocksize*4+2;j++)
-	f->fftwf_buffer[j]/=f->qblocksize*4;
-      
-      /* now take what we learned and distill it a bit */
-      f->ho_window[i]=calloc((f->qblocksize*2+1),sizeof(**f->ho_window));
-      for(j=0;j<f->qblocksize*2+1;j++){
-	f->ho_window[i][j]=f->fftwf_buffer[j*2];
-	f->ho_area[i]+=fabs(f->ho_window[i][j]);
-      }
-      f->ho_area[i]=1./f->ho_area[i];
-
-      lastf=thisf;
-      
+  for(i=0;i<bands;i++){
+    
+    /* window each desired response in the time domain so that our
+       convolution is properly padded against being circular */
+    memset(f->fftwf_buffer,0,sizeof(*f->fftwf_buffer)*
+	   (f->qblocksize*4+2));
+    for(j=0;j<f->qblocksize*2;j++)
+      f->fftwf_buffer[j*2]=f->ho_window[i][j];
+    
+    fftwf_execute(f->fftwf_backward);
+    
+    /* window response in time */
+    for(j=0;j<f->qblocksize;j++){
+      float val=cos(j*M_PI/(f->qblocksize*2));
+      val=sin(val*val*M_PIl*.5);
+      f->fftwf_buffer[j]*= sin(val*val*M_PIl*.5);
     }
+    
+    for(;j<f->qblocksize*3;j++)
+      f->fftwf_buffer[j]=0.;
+    
+    for(;j<f->qblocksize*4;j++){
+      float val=sin((j-f->qblocksize*3)*M_PI/(f->qblocksize*2));
+      val=sin(val*val*M_PIl*.5);
+      f->fftwf_buffer[j]*=sin(val*val*M_PIl*.5);
+    }
+    
+    /* back to frequency; this is all-real data still */
+    fftwf_execute(f->fftwf_forward);
+    for(j=0;j<f->qblocksize*4+2;j++)
+      f->fftwf_buffer[j]/=f->qblocksize*4;
+    
+    /* now take what we learned and distill it a bit */
+    for(j=0;j<f->qblocksize*2+1;j++){
+      f->ho_window[i][j]=f->fftwf_buffer[j*2];
+      f->ho_area[i]+=fabs(f->ho_window[i][j]);
+    }
+    f->ho_area[i]=1./f->ho_area[i];
   }
-
+  
   return 0;
-
 }
 
 /* called only by initial setup */
-int freq_load(freq_state *f,freq_class_setup *fc){
+int freq_load(freq_state *f,freq_class_setup *fc,int ch){
   int i;
   memset(f,0,sizeof(*f));
 
@@ -193,22 +202,22 @@
 
   f->fillstate=0;
   f->cache_samples=0;
-  f->cache1=malloc(input_ch*sizeof(*f->cache1));
-  f->cache0=malloc(input_ch*sizeof(*f->cache0));
-  for(i=0;i<input_ch;i++){
+  f->cache1=malloc(ch*sizeof(*f->cache1));
+  f->cache0=malloc(ch*sizeof(*f->cache0));
+  for(i=0;i<ch;i++){
     f->cache1[i]=calloc(input_size,sizeof(**f->cache1));
     f->cache0[i]=calloc(input_size,sizeof(**f->cache0));
   }
 
-  f->activeP=malloc(input_ch*sizeof(*f->activeP));
-  f->active1=malloc(input_ch*sizeof(*f->active1));
-  f->active0=malloc(input_ch*sizeof(*f->active0));
+  f->activeP=malloc(ch*sizeof(*f->activeP));
+  f->active1=malloc(ch*sizeof(*f->active1));
+  f->active0=malloc(ch*sizeof(*f->active0));
 
 
-  f->lap1=malloc(input_ch*sizeof(*f->lap1));
-  f->lap0=malloc(input_ch*sizeof(*f->lap0));
-  f->lapC=malloc(input_ch*sizeof(*f->lapC));
-  for(i=0;i<input_ch;i++){
+  f->lap1=malloc(ch*sizeof(*f->lap1));
+  f->lap0=malloc(ch*sizeof(*f->lap0));
+  f->lapC=malloc(ch*sizeof(*f->lapC));
+  for(i=0;i<ch;i++){
     f->lap1[i]=calloc(fc->qblocksize,sizeof(**f->lap1));
     f->lap0[i]=calloc(fc->qblocksize,sizeof(**f->lap0));
     f->lapC[i]=calloc(fc->qblocksize,sizeof(**f->lapC));
@@ -217,15 +226,13 @@
   f->peak=malloc(fc->bands*sizeof(*f->peak));
   f->rms=malloc(fc->bands*sizeof(*f->rms));
   for(i=0;i<fc->bands;i++){
-    f->peak[i]=malloc(input_ch*sizeof(**f->peak));
-    f->rms[i]=malloc(input_ch*sizeof(**f->rms));
+    f->peak[i]=malloc(ch*sizeof(**f->peak));
+    f->rms[i]=malloc(ch*sizeof(**f->rms));
   }
 
-  f->out.size=input_size;
-  f->out.channels=input_ch;
-  f->out.rate=input_rate;
-  f->out.data=malloc(input_ch*sizeof(*f->out.data));
-  for(i=0;i<input_ch;i++)
+  f->out.channels=ch;
+  f->out.data=malloc(ch*sizeof(*f->out.data));
+  for(i=0;i<ch;i++)
     f->out.data[i]=malloc(input_size*sizeof(**f->out.data));
   
   return(0);
@@ -298,12 +305,12 @@
                       int      *active,
                       void (*func)(float *,int)){
   
-  int i,j;
+  int i,j,ch=f->out.channels;
   int have_feedback=0;
   
   f->cache_samples+=in->samples;
 
-  for(i=0;i<input_ch;i++){
+  for(i=0;i<ch;i++){
     int mutedC=mute_channel_muted(in->active,i);
     int muted0=mute_channel_muted(f->mutemask0,i);
 
@@ -333,14 +340,14 @@
                               f->cache0[i],input_size);
       }
     
-      if(in->samples<in->size){
+      if(in->samples<input_size){
         if(mutedC)memset(in->data[i],0,sizeof(**in->data)*input_size);
         if(muted0)memset(f->cache0[i],0,sizeof(**f->cache0)*input_size);
 
         postextrapolate_helper(f->cache0[i],input_size,
                                in->data[i],in->samples,
                                in->data[i]+in->samples,
-			       in->size-in->samples);
+			       input_size-in->samples);
       }
 
       fill_freq_buffer_helper(fc->fftwf_buffer,
@@ -448,17 +455,17 @@
     if(!ff->peak){
       ff->peak=calloc(fc->bands,sizeof(*ff->peak));
       for(i=0;i<fc->bands;i++)
-	ff->peak[i]=malloc(input_ch*sizeof(**ff->peak));
+	ff->peak[i]=malloc(ch*sizeof(**ff->peak));
     }
     if(!ff->rms){
       ff->rms=calloc(fc->bands,sizeof(*ff->rms));
       for(i=0;i<fc->bands;i++)
-	ff->rms[i]=malloc(input_ch*sizeof(**ff->rms));
+	ff->rms[i]=malloc(ch*sizeof(**ff->rms));
     }
 
     for(i=0;i<fc->bands;i++){
-      memcpy(ff->peak[i],f->peak[i],input_ch*sizeof(**f->peak));
-      memcpy(ff->rms[i],f->rms[i],input_ch*sizeof(**f->rms));
+      memcpy(ff->peak[i],f->peak[i],ch*sizeof(**f->peak));
+      memcpy(ff->rms[i],f->rms[i],ch*sizeof(**f->rms));
     } 
     ff->bypass=0;
     feedback_push(&f->feedpool,(feedback_generic *)ff);
@@ -485,7 +492,7 @@
 time_linkage *freq_read(time_linkage *in, freq_state *f,
                         int *visible, int *active,
                         void (*func)(float *,int i)){
-  int i;
+  int i,ch=f->out.channels;
   freq_class_setup *fc=f->fc;
 
   switch(f->fillstate){
@@ -496,7 +503,7 @@
     }
 
     /* zero out lapping and cache state */
-    for(i=0;i<input_ch;i++){
+    for(i=0;i<ch;i++){
       memset(f->lap1[i],0,sizeof(**f->lap1)*fc->qblocksize);
       memset(f->lap0[i],0,sizeof(**f->lap0)*fc->qblocksize);
       memset(f->cache0[i],0,sizeof(**f->cache0)*input_size);
@@ -513,10 +520,10 @@
 
     f->fillstate=1;
     f->out.samples=0;
-    if(in->samples==in->size)goto tidy_up;
+    if(in->samples==input_size)goto tidy_up;
     
-    for(i=0;i<input_ch;i++)
-      memset(in->data[i],0,sizeof(**in->data)*in->size);
+    for(i=0;i<ch;i++)
+      memset(in->data[i],0,sizeof(**in->data)*input_size);
     in->samples=0;
     /* fall through */
     
@@ -526,10 +533,10 @@
     
     f->fillstate=2;
     f->out.samples=0;
-    if(in->samples==in->size)goto tidy_up;
+    if(in->samples==input_size)goto tidy_up;
     
-    for(i=0;i<input_ch;i++)
-      memset(in->data[i],0,sizeof(**in->data)*in->size);
+    for(i=0;i<ch;i++)
+      memset(in->data[i],0,sizeof(**in->data)*input_size);
     in->samples=0;
     /* fall through */
     
@@ -537,7 +544,7 @@
 
     freq_work(fc,f,in,&f->out,visible,active,func);
 
-    if(f->out.samples<f->out.size)f->fillstate=3;
+    if(f->out.samples<input_size)f->fillstate=3;
     break;
   case 3: /* we've pushed out EOF already */
     f->out.samples=0;
@@ -545,7 +552,7 @@
   
  tidy_up:
   {
-    int tozero=f->out.size-f->out.samples;
+    int tozero=input_size-f->out.samples;
     if(tozero)
       for(i=0;i<f->out.channels;i++)
         memset(f->out.data[i]+f->out.samples,0,sizeof(**f->out.data)*tozero);

Modified: trunk/postfish/freq.h
===================================================================
--- trunk/postfish/freq.h	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/freq.h	2004-05-17 08:16:56 UTC (rev 6712)
@@ -71,7 +71,7 @@
 
 extern int pull_freq_feedback(freq_state *ff,float **peak,float **rms);
 extern int freq_class_load(freq_class_setup *f,const float *frequencies, int bands);
-extern int freq_load(freq_state *f,freq_class_setup *fc);
+extern int freq_load(freq_state *f,freq_class_setup *fc,int ch);
 
 extern int freq_reset(freq_state *f);
 extern time_linkage *freq_read(time_linkage *in, 

Modified: trunk/postfish/input.c
===================================================================
--- trunk/postfish/input.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/input.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -327,23 +327,23 @@
        4000:  256 */
 
   if(rate<6000){
-    input_size=out.size=256;
+    input_size=256;
   }else if(rate<15000){
-    input_size=out.size=512;
+    input_size=512;
   }else if(rate<25000){
-    input_size=out.size=1024;
+    input_size=1024;
   }else if(rate<50000){
-    input_size=out.size=2048;
+    input_size=2048;
   }else if(rate<100000){
-    input_size=out.size=4096;
+    input_size=4096;
   }else
-    input_size=out.size=8192;
+    input_size=8192;
 
   input_ch=out.channels=ch;
-  input_rate=out.rate=rate;
+  input_rate=rate;
   out.data=malloc(sizeof(*out.data)*ch);
   for(i=0;i<ch;i++)
-    out.data[i]=malloc(sizeof(*out.data[0])*out.size);
+    out.data[i]=malloc(sizeof(*out.data[0])*input_size);
   
   return 0;
 }
@@ -423,7 +423,7 @@
 
 time_linkage *input_read(void){
   int read_b=0,i,j,k;
-  int toread_b=out.size*out.channels*inbytes;
+  int toread_b=input_size*out.channels*inbytes;
   unsigned char *readbuf;
   float *rms=alloca(sizeof(*rms)*(out.channels+2));
   float *peak=alloca(sizeof(*peak)*(out.channels+2));
@@ -551,7 +551,7 @@
 
  tidy_up:
   {
-    int tozero=out.size-out.samples;
+    int tozero=input_size-out.samples;
     if(tozero)
       for(j=0;j<out.channels;j++)
         memset(out.data[j]+out.samples,0,sizeof(**out.data)*tozero);

Modified: trunk/postfish/limit.c
===================================================================
--- trunk/postfish/limit.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/limit.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -28,7 +28,6 @@
 
 extern int input_size;
 extern int input_rate;
-extern int input_ch;
 
 sig_atomic_t limit_active;
 sig_atomic_t limit_visible;
@@ -67,24 +66,22 @@
   if(!f)return 0;
   
   if(peak)
-    memcpy(peak,f->peak,sizeof(*peak)*input_ch);
+    memcpy(peak,f->peak,sizeof(*peak)*limitstate.out.channels);
   if(att)
-    memcpy(att,f->att,sizeof(*att)*input_ch);
+    memcpy(att,f->att,sizeof(*att)*limitstate.out.channels);
   feedback_old(&limitstate.feedpool,(feedback_generic *)f);
   return 1;
 }
 
 /* called only by initial setup */
-int limit_load(void){
+int limit_load(int ch){
   int i;
   memset(&limitstate,0,sizeof(limitstate));
 
-  limitstate.iir=calloc(input_ch,sizeof(*limitstate.iir));
-  limitstate.out.size=input_size;
-  limitstate.out.channels=input_ch;
-  limitstate.out.rate=input_rate;
-  limitstate.out.data=malloc(input_ch*sizeof(*limitstate.out.data));
-  for(i=0;i<input_ch;i++)
+  limitstate.iir=calloc(ch,sizeof(*limitstate.iir));
+  limitstate.out.channels=ch;
+  limitstate.out.data=malloc(ch*sizeof(*limitstate.out.data));
+  for(i=0;i<ch;i++)
     limitstate.out.data[i]=malloc(input_size*sizeof(**limitstate.out.data));
 
   window=malloc(input_size*sizeof(*window));
@@ -109,10 +106,10 @@
 }
 
 /* called only in playback thread */
-int limit_reset(void ){
+int limit_reset(void){
   /* reset cached pipe state */
   while(pull_limit_feedback(NULL,NULL));
-  memset(limitstate.iir,0,input_ch*sizeof(&limitstate.iir));
+  memset(limitstate.iir,0,limitstate.out.channels*sizeof(&limitstate.iir));
   limitstate.initted=0;
   return 0;
 }
@@ -123,8 +120,9 @@
 
 
 time_linkage *limit_read(time_linkage *in){
-  float peakfeed[input_ch];
-  float attfeed[input_ch];
+  int ch=limitstate.out.channels;
+  float peakfeed[ch];
+  float attfeed[ch];
 
   int activeC=limit_active;
   int activeP=limitstate.prev_active;
@@ -154,7 +152,7 @@
   depth=depth*.2;
   depth*=depth;
 
-  for(i=0;i<input_ch;i++){
+  for(i=0;i<ch;i++){
     localpeak=0.;
     localatt=0.;
 
@@ -176,10 +174,9 @@
         x[k]=att;
       }
         
+      compute_iir_decayonly2(x,input_size,limitstate.iir+i,&limitstate.decay);
       
-      compute_iir_freefall2(x,input_size,limitstate.iir+i,&limitstate.decay);
       
-      
       for(k=0;k<in->samples;k++)
         x[k]=inx[k]*fromdB(-x[k]);
       
@@ -225,10 +222,10 @@
       (limit_feedback *)feedback_new(&limitstate.feedpool,new_limit_feedback);
     
     if(!ff->peak)
-      ff->peak=malloc(input_ch*sizeof(*ff->peak));
+      ff->peak=malloc(ch*sizeof(*ff->peak));
     
     if(!ff->att)
-      ff->att=malloc(input_ch*sizeof(*ff->att));
+      ff->att=malloc(ch*sizeof(*ff->att));
     
     memcpy(ff->peak,peakfeed,sizeof(peakfeed));
     memcpy(ff->att,attfeed,sizeof(attfeed));
@@ -237,7 +234,7 @@
   }
    
   {
-    int tozero=limitstate.out.size-limitstate.out.samples;
+    int tozero=input_size-limitstate.out.samples;
     if(tozero)
       for(i=0;i<limitstate.out.channels;i++)
         memset(limitstate.out.data[i]+limitstate.out.samples,0,sizeof(**limitstate.out.data)*tozero);

Modified: trunk/postfish/limit.h
===================================================================
--- trunk/postfish/limit.h	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/limit.h	2004-05-17 08:16:56 UTC (rev 6712)
@@ -28,6 +28,6 @@
 } limit_settings;
 
 extern int pull_limit_feedback(float *peak,float *att);
-extern int limit_load(void);
+extern int limit_load(int ch);
 extern int limit_reset(void);
 extern time_linkage *limit_read(time_linkage *in);

Modified: trunk/postfish/limitpanel.c
===================================================================
--- trunk/postfish/limitpanel.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/limitpanel.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -34,7 +34,6 @@
 
 extern sig_atomic_t limit_active;
 extern sig_atomic_t limit_visible;
-extern int input_ch;
 extern int input_size;
 extern int input_rate;
 
@@ -93,17 +92,17 @@
                        GtkWidget *activebutton){
 
 
-  char *labels[8]={"-80","-60","-40","-20","-10","-6","-3","+0"};
+  char *labels[9]={"","-80","-60","-40","-20","-10","-6","-3","+0"};
   float levels[9]={-80,-60,-50,-40,-30,-10,-6,-3,0};
 
-  char *labels2[4]={"-20","-10","-3","0"};
+  char *labels2[5]={"","-20","-10","-3","0"};
   float levels2[5]={-30,-20,-10,-3,0};
   
-  char *rlabels[3]={"6","   20","40"};
+  char *rlabels[4]={"","6","   20","40"};
   float rlevels[4]={0,3,10,20};
 
   float timing_levels[6]={.1,1,10,100,1000,10000};
-  char  *timing_labels[5]={"1ms","10ms","100ms","1s","10s"};
+  char  *timing_labels[6]={"","1ms","10ms","100ms","1s","10s"};
 
   char *shortcut[]={" l "};
 
@@ -124,11 +123,11 @@
   GtkWidget *readout2=readout_new("+XXXXdB");
   GtkWidget *readout3=readout_new("+XXXXms");
 
-  GtkWidget *slider2=multibar_slider_new(4,labels2,levels2,1);
-  GtkWidget *slider3=multibar_slider_new(5,timing_labels,timing_levels,1);
+  GtkWidget *slider2=multibar_slider_new(5,labels2,levels2,1);
+  GtkWidget *slider3=multibar_slider_new(6,timing_labels,timing_levels,1);
 
-  t_slider=multibar_new(8,labels,levels,1,HI_DECAY);
-  a_slider=multibar_new(3,rlabels,rlevels,0,0);
+  t_slider=multibar_new(9,labels,levels,1,HI_DECAY);
+  a_slider=multibar_new(4,rlabels,rlevels,0,0);
 
   gtk_misc_set_alignment(GTK_MISC(label1),1,.5);
   gtk_misc_set_alignment(GTK_MISC(label2),1,.5);
@@ -170,17 +169,17 @@
 void limitpanel_feedback(int displayit){
   if(!peakfeed){
     int i;
-    peakfeed=malloc(sizeof(*peakfeed)*input_ch);
-    attfeed=malloc(sizeof(*attfeed)*input_ch);
-    zerofeed=malloc(sizeof(*zerofeed)*input_ch);
-    for(i=0;i<input_ch;i++)zerofeed[i]=-150.;
+    peakfeed=malloc(sizeof(*peakfeed)*OUTPUT_CHANNELS);
+    attfeed=malloc(sizeof(*attfeed)*OUTPUT_CHANNELS);
+    zerofeed=malloc(sizeof(*zerofeed)*OUTPUT_CHANNELS);
+    for(i=0;i<OUTPUT_CHANNELS;i++)zerofeed[i]=-150.;
   }
   
   if(pull_limit_feedback(peakfeed,attfeed)==1){
     multibar_set(MULTIBAR(t_slider),zerofeed,peakfeed,
-		 input_ch,(displayit && limit_visible));
+		 OUTPUT_CHANNELS,(displayit && limit_visible));
     multibar_set(MULTIBAR(a_slider),zerofeed,attfeed,
-		 input_ch,(displayit && limit_visible));
+		 OUTPUT_CHANNELS,(displayit && limit_visible));
   }
 }
 

Modified: trunk/postfish/main.c
===================================================================
--- trunk/postfish/main.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/main.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -28,6 +28,7 @@
 
 /* sound playback code is OSS-specific for now */
 #include "postfish.h"
+#include <fenv.h>  // Thank you C99!
 #include <fftw3.h>
 #include "input.h"
 #include "output.h"
@@ -38,25 +39,116 @@
 #include "singlecomp.h"
 #include "limit.h"
 #include "mute.h"
+#include "mix.h"
 
 pthread_mutex_t master_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 
 int outfileno=-1;
 int eventpipe[2];
 
+int look_for_wisdom(char *filename){
+  int ret;
+  FILE *f=fopen(filename,"r");
+  if(!f)return 0;
+  ret=fftwf_import_wisdom_from_file(f);
+  fclose(f);
+
+  if(ret)
+    fprintf(stderr,"Found valid postfish-wisdomrc file at %s\n",filename);
+  else
+    fprintf(stderr,"WARNING: corrupt, invalid or obsolete postfish-wisdomrc file at %s\n",filename);
+  return(ret);
+}
+
 int main(int argc, char **argv){
   int configfd=-1;
+  int wisdom=0;
 
+  /* We do not care about FPEs; rather, underflow is nominal case, and
+     its better to ignore other traps in production than to crash the
+     app.  Please inform the FPU of this. */
+  fedisableexcept(FE_INEXACT);
+  fedisableexcept(FE_UNDERFLOW);
+  fedisableexcept(FE_OVERFLOW);
+
+  /* Linux Altivec support has a very annoying problem; by default,
+     math on denormalized floats will simply crash the program.  FFTW3
+     uses Altivec, so boom.
+     
+     By the C99 spec, the above exception configuration is also
+     supposed to handle Altivec config, but doesn't.  So we use the
+     below ugliness. */
+
+#ifdef __PPC
+#include <altivec.h>
+#if (defined __GNUC__) && (__GNUC__ == 3) && ! (defined __APPLE_CC__)
+  __vector unsigned short noTrap = 
+    (__vector unsigned short){0,0,0,0,0,0,0x1,0};
+#else
+  vector unsigned short noTrap = 
+    (vector unsigned short)(0,0,0,0,0,0,0x1,0);
+#endif
+
+  vec_mtvscr(noTrap);
+#endif
+
+  /* check for fftw wisdom file in order:
+     ./postfish-wisdomrc
+     $(POSTFISHDIR)/postfish-wisdomrc
+     ~/.postfish/postfish-wisdomrc
+     ETCDIR/postfish-wisdomrc 
+     system wisdom */
+  
+
+  wisdom=look_for_wisdom("./postfish-wisdomrc");
+  if(!wisdom){
+    char *rcdir=getenv("POSTFISH_RCDIR");
+    if(rcdir){
+      char *rcfile="/postfish-wisdomrc";
+      char *homerc=calloc(1,strlen(rcdir)+strlen(rcfile)+1);
+      strcat(homerc,rcdir);
+      strcat(homerc,rcfile);
+      wisdom=look_for_wisdom(homerc);
+    }
+  }
+  if(!wisdom){
+    char *rcdir=getenv("HOME");
+    if(rcdir){
+      char *rcfile="/.postfish/postfish-wisdomrc";
+      char *homerc=calloc(1,strlen(rcdir)+strlen(rcfile)+1);
+      strcat(homerc,rcdir);
+      strcat(homerc,rcfile);
+      wisdom=look_for_wisdom(homerc);
+    }
+  }
+  if(!wisdom)wisdom=look_for_wisdom(ETCDIR"/postfish-wisdomrc");
+  if(!wisdom){
+    fftwf_import_system_wisdom(); 
+  
+    fprintf(stderr,"Postfish could not find the postfish-wisdom configuration file normally built\n"
+	    "or installed with Postfish and located in one of the following places:\n"
+
+	    "\t./postfish-wisdomrc\n"
+	    "\t$(POSTFISHDIR)/postfish-wisdomrc\n"
+	    "\t~/.postfish/postfish-wisdomrc\n\t"
+	    ETCDIR"/postfish-wisdomrc\n"
+	    "This configuration file is used to reduce the startup time Postfish uses to \n"
+	    "pre-calculate Fourier transform tables for the FFTW3 library. Postfish will start\n"
+	    "and operate normally, but it will take additional time before popping the main\n"
+	    "window because this information must be regenerated each time Postfish runs.\n");
+  }
+
   /* parse command line and open all the input files */
   if(input_load(argc-1,argv+1))exit(1);
   /* set up filter chains */
   if(declip_load())exit(1);
-  if(eq_load())exit(1);
+  if(eq_load(OUTPUT_CHANNELS))exit(1);
   if(suppress_load())exit(1);
-  if(multicompand_load())exit(1);
-  if(singlecomp_load())exit(1);
-  if(limit_load())exit(1);
+  if(multicompand_load(OUTPUT_CHANNELS))exit(1);
+  if(singlecomp_load(OUTPUT_CHANNELS))exit(1);
+  if(limit_load(OUTPUT_CHANNELS))exit(1);
   if(mute_load())exit(1);
+  if(mix_load(OUTPUT_CHANNELS))exit(1);
 
   /* look at stdout... do we have a file or device? */
   if(!isatty(STDOUT_FILENO)){

Modified: trunk/postfish/mainpanel.c
===================================================================
--- trunk/postfish/mainpanel.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/mainpanel.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -57,6 +57,7 @@
   compandpanel_reset();
   singlepanel_reset();
   limitpanel_reset();
+  mixpanel_reset();
   meterhold_reset(p);
 }
 
@@ -75,6 +76,7 @@
   compandpanel_reset();
   singlepanel_reset();
   limitpanel_reset();
+  mixpanel_reset();
   meterhold_reset(p);
 }
 
@@ -452,14 +454,15 @@
                               GtkWidget *table,
                               char *label,
                               int i,
-			      int masterwinp,
-			      int channelwinp,
-			      void (*panel_create)
+			      void (*single_create)
                               (postfish_mainpanel *,
+			       GtkWidget **, GtkWidget **),
+			      void (*multi_create)
+			      (postfish_mainpanel *,
                                GtkWidget **, GtkWidget **)){  
   
   int j;
-  GtkWidget *wm[input_ch];
+  GtkWidget *wm[input_ch+1];
   GtkWidget *wa[input_ch];
   
   for(j=0;j<input_ch;j++){
@@ -467,7 +470,7 @@
     sprintf(buffer,"  %d ",j+1);
     p->channel_wa[i][j]=wa[j]=gtk_toggle_button_new_with_label(buffer);
 
-    if(channelwinp){
+    if(multi_create){
       /* a panel button per channel, multiple accellerated labels */
       GtkWidget *l=gtk_label_new_with_mnemonic(label);
       GtkWidget *a=gtk_alignment_new(0,.5,0,0);
@@ -477,7 +480,7 @@
       gtk_container_add(GTK_CONTAINER(a),wm[j]);
       gtk_table_attach_defaults(GTK_TABLE(table),a,2+j*2,4+j*2,i+1,i+2);
       gtk_table_attach(GTK_TABLE(table),l,1,2,i+1,i+2,GTK_FILL,0,0,0);
-      if(j>0)gtk_widget_set_size_request(l,0,0);
+      if(j>0 || single_create)gtk_widget_set_size_request(l,0,0);
       gtk_label_set_mnemonic_widget(GTK_LABEL(l),wm[j]);
 
       {
@@ -494,28 +497,30 @@
     }
   }
 
-  if(masterwinp){
+  if(single_create){
     /* one master windowbutton, one label */
-    wm[0]=windowbutton_new(label);
-    gtk_table_attach_defaults(GTK_TABLE(table),wm[0],0,2,i+1,i+2);
+    wm[input_ch]=windowbutton_new(label);
+    gtk_table_attach_defaults(GTK_TABLE(table),wm[input_ch],0,2,i+1,i+2);
+
+    (*single_create)(p,wm+input_ch,wa);
   }else{
-    if (!channelwinp){  
-      GtkWidget *l=gtk_label_new(label);
+    GtkWidget *b=windowbutton_new(NULL);
     
-      gtk_widget_set_name(l,"windowbuttonlike");
-      gtk_misc_set_alignment(GTK_MISC(l),0,.5);
-      gtk_table_attach_defaults(GTK_TABLE(table),l,1,2,i+1,i+2);
-    }
-    {
-      GtkWidget *b=windowbutton_new(NULL);
-      
-      gtk_widget_set_sensitive(b,FALSE);
-      gtk_table_attach_defaults(GTK_TABLE(table),b,0,1,i+1,i+2);
-    }
+    gtk_widget_set_sensitive(b,FALSE);
+    gtk_table_attach_defaults(GTK_TABLE(table),b,0,1,i+1,i+2);
+  }
 
+  if(multi_create)
+    (*multi_create)(p,wm,wa);
+  
+  if (!single_create && !multi_create){  
+    GtkWidget *l=gtk_label_new(label);
+    
+    gtk_widget_set_name(l,"windowbuttonlike");
+    gtk_misc_set_alignment(GTK_MISC(l),0,.5);
+    gtk_table_attach_defaults(GTK_TABLE(table),l,1,2,i+1,i+2);
   }
 
-  if(panel_create)(*panel_create)(p,wm,wa);
 }
 
 static void mainpanel_masterentry(postfish_mainpanel *p,
@@ -687,7 +692,7 @@
 
   /* left side of main panel */
   {
-    char *labels[12]={"-96","-72","-60","-48","-36","-24",
+    char *labels[13]={"","-96","-72","-60","-48","-36","-24",
                       "-16","-8","-3","0","+3","+6"};
     float levels[13]={-140.,-96.,-72.,-60.,-48.,-36.,-24.,
                        -16.,-8.,-3.,0.,+3.,+6.};
@@ -700,9 +705,9 @@
     GtkWidget *inbox=gtk_hbox_new(0,0);
     GtkWidget *outbox=gtk_hbox_new(0,0);
 
-    panel->inbar=multibar_new(12,labels,levels, 0,
+    panel->inbar=multibar_new(13,labels,levels, 0,
                               LO_ATTACK|LO_DECAY|HI_DECAY|PEAK_FOLLOW );
-    panel->outbar=multibar_new(12,labels,levels, 0,
+    panel->outbar=multibar_new(13,labels,levels, 0,
                                LO_ATTACK|LO_DECAY|HI_DECAY|PEAK_FOLLOW );
     panel->inreadout=readout_new("------");
     panel->outreadout=readout_new("------");
@@ -748,7 +753,7 @@
 
     /* master dB slider */
     {
-      char *sliderlabels[10]={"-40","-30","-20","-10","0","+10","+20","+30","+40","+50"};
+      char *sliderlabels[11]={"","-40","-30","-20","-10","0","+10","+20","+30","+40","+50"};
       float sliderlevels[11]={-50,-40,-30,-20,-10,0,10,20,30,40,50};
       
       GtkWidget *box=gtk_hbox_new(0,0);
@@ -756,7 +761,7 @@
       GtkWidget *masterlabel=gtk_label_new("master:");
       panel->masterdB_a=gtk_toggle_button_new_with_label("a[t]ten");
       panel->masterdB_r=readout_new("  0.0dB");
-      panel->masterdB_s=multibar_slider_new(10,sliderlabels,sliderlevels,1);
+      panel->masterdB_s=multibar_slider_new(11,sliderlabels,sliderlevels,1);
       
       multibar_thumb_set(MULTIBAR(panel->masterdB_s),0.,0);
       multibar_thumb_increment(MULTIBAR(panel->masterdB_s),.1,1.);
@@ -952,13 +957,14 @@
     gtk_table_attach_defaults(GTK_TABLE(channeltable),temp,1,2+input_ch*2,0,1);
   }
 
-  mainpanel_chentry(panel,channeltable,"Mute ",0,0,0,mutedummy_create);
-  mainpanel_chentry(panel,channeltable,"_Declip ",1,1,0,clippanel_create);
-  mainpanel_chentry(panel,channeltable,"_Multicomp ",2,0,1,compandpanel_create_channel);
-  mainpanel_chentry(panel,channeltable,"_Singlecomp ",3,0,1,singlepanel_create_channel);
-  mainpanel_chentry(panel,channeltable,"De_verb ",4,1,0,suppresspanel_create_channel);
-  mainpanel_chentry(panel,channeltable,"_Reverb ",5,1,0,0);
-  mainpanel_chentry(panel,channeltable,"_EQ ",6,0,1,eqpanel_create_channel);
+  mainpanel_chentry(panel,channeltable,"_Declip ",0,clippanel_create,0);
+  mainpanel_chentry(panel,channeltable,"_Multicomp ",1,0,compandpanel_create_channel);
+  mainpanel_chentry(panel,channeltable,"_Singlecomp ",2,0,singlepanel_create_channel);
+  mainpanel_chentry(panel,channeltable,"De_verb ",3,suppresspanel_create_channel,0);
+  mainpanel_chentry(panel,channeltable,"_EQ ",4,0,eqpanel_create_channel);
+  mainpanel_chentry(panel,channeltable,"_Reverb ",5,0,0);
+  mainpanel_chentry(panel,channeltable,"Atten/Mi_x ",6,attenpanel_create,
+		    mixpanel_create_channel);
 
   /* master panel */
   {
@@ -981,14 +987,47 @@
     gtk_table_attach_defaults(GTK_TABLE(mastertable),temp,1,2,0,1);
   }
 
-  mainpanel_masterentry(panel,mastertable,"_Crossmix "," c ",GDK_c,0,0);
-  mainpanel_masterentry(panel,mastertable,"_Multicomp "," m ",GDK_m,1,compandpanel_create_master);
-  mainpanel_masterentry(panel,mastertable,"_Singlecomp "," s ",GDK_s,2,singlepanel_create_master);
-  mainpanel_masterentry(panel,mastertable,"_Reverb "," r ",GDK_r,3,0);
-  mainpanel_masterentry(panel,mastertable,"_EQ "," e ",GDK_e,4,eqpanel_create_master);
-  mainpanel_masterentry(panel,mastertable,"_Limit "," l ",GDK_l,5,limitpanel_create);
-  mainpanel_masterentry(panel,mastertable,"_Output ",NULL,GDK_l,6,0);
+  mainpanel_masterentry(panel,mastertable,"_Multicomp "," m ",GDK_m,0,compandpanel_create_master);
+  mainpanel_masterentry(panel,mastertable,"_Singlecomp "," s ",GDK_s,1,singlepanel_create_master);
+  mainpanel_masterentry(panel,mastertable,"_Reverb "," r ",GDK_r,2,0);
+  mainpanel_masterentry(panel,mastertable,"_EQ "," e ",GDK_e,3,eqpanel_create_master);
+  mainpanel_masterentry(panel,mastertable,"_Limit "," l ",GDK_l,4,limitpanel_create);
 
+  /* output has three activity buttons not in the main grid */
+  {
+    GtkWidget *ww=windowbutton_new("_Output ");
+
+    GtkWidget *std=gtk_toggle_button_new_with_label("o");
+    GtkWidget *ply=gtk_toggle_button_new_with_label("p");
+    GtkWidget *fil=gtk_toggle_button_new_with_label("f");
+    GtkWidget *box=gtk_hbox_new(0,0);
+    GtkWidget *box2=gtk_hbox_new(1,0);
+
+    GtkWidget *fw=windowbutton_new(NULL);
+    GtkWidget *fr=gtk_frame_new(NULL);
+  
+    gtk_frame_set_shadow_type(GTK_FRAME(fr),GTK_SHADOW_ETCHED_IN);
+    gtk_widget_set_sensitive(fw,FALSE);
+      
+    gtk_widget_add_accelerator (std, "activate", panel->group, GDK_o, 0, 0);
+    gtk_widget_add_accelerator (ply, "activate", panel->group, GDK_p, 0, 0);
+    gtk_widget_add_accelerator (fil, "activate", panel->group, GDK_f, 0, 0);
+      
+    gtk_box_pack_start(GTK_BOX(box),ww,0,0,0);
+    gtk_box_pack_start(GTK_BOX(box),box2,1,1,2);
+    gtk_box_pack_start(GTK_BOX(box2),ply,1,1,0);
+    gtk_box_pack_start(GTK_BOX(box2),fil,1,1,0);
+    
+
+    gtk_table_attach_defaults(GTK_TABLE(mastertable),fw,0,1,6,7);
+    gtk_table_attach_defaults(GTK_TABLE(mastertable),fr,1,2,6,7);
+
+    gtk_table_attach_defaults(GTK_TABLE(mastertable),box,0,1,7,8);
+    gtk_table_attach_defaults(GTK_TABLE(mastertable),std,1,2,7,8);
+
+    //if(panel_create)(*panel_create)(p,ww,(shortcut?wa:0));
+  }
+
   g_signal_connect (G_OBJECT (panel->toplevel), "delete_event",
                     G_CALLBACK (shutdown), NULL);
     
@@ -1074,6 +1113,7 @@
       compandpanel_feedback(current_p);
       singlepanel_feedback(current_p);
       limitpanel_feedback(current_p);
+      mixpanel_feedback(current_p);
       
     }
   }
@@ -1090,6 +1130,14 @@
   return TRUE;
 }
 
+static int look_for_gtkrc(char *filename){
+  FILE *f=fopen(filename,"r");
+  if(!f)return 0;
+  fprintf(stderr,"Loading postfish-gtkrc file found at %s\n",filename);
+  gtk_rc_add_default_file(filename);
+  return 1;
+}
+
 #include <stdlib.h>
 void mainpanel_go(int argc,char *argv[], int ch){
   postfish_mainpanel p;
@@ -1097,9 +1145,48 @@
   char *labels[11];
   char  buffer[20];
   int i;
+  int found=0;
+  memset(&p,0,sizeof(p));
 
-  memset(&p,0,sizeof(p));
-  gtk_rc_add_default_file("/etc/postfish/postfish-gtkrc");
+  found|=look_for_gtkrc(ETCDIR"/postfish-gtkrc");
+  {
+    char *rcdir=getenv("HOME");
+    if(rcdir){
+      char *rcfile="/.postfish/postfish-gtkrc";
+      char *homerc=calloc(1,strlen(rcdir)+strlen(rcfile)+1);
+      strcat(homerc,homedir);
+      strcat(homerc,rcfile);
+      found|=look_for_gtkrc(homerc);
+    }
+  }
+  {
+    char *rcdir=getenv("POSTFISH_RCDIR");
+    if(rcdir){
+      char *rcfile="/postfish-gtkrc";
+      char *homerc=calloc(1,strlen(rcdir)+strlen(rcfile)+1);
+      strcat(homerc,homedir);
+      strcat(homerc,rcfile);
+      found|=look_for_gtkrc(homerc);
+    }
+  }
+  found|=look_for_gtkrc("./postfish-gtkrc");
+
+  if(!found){
+  
+    fprintf(stderr,"Postfish could not find the postfish-gtkrc configuration file normally\n"
+	    "installed with Postfish and located in one of the following places:\n"
+
+	    "\t./postfish-gtkrc\n"
+	    "\t$(POSTFISHDIR)/postfish-gtkrc\n"
+	    "\t~/.postfish/postfish-gtkrc\n\t"
+	    ETCDIR"/postfish-gtkrc\n"
+	    "This configuration file is used to tune the color, font and other detail aspects\n"
+	    "of the Postfish user interface.  Although Postfish will work without it, the UI\n"
+	    "appearence will likely make the application harder to use due to missing visual\n"
+	    "cues.\n");
+  }
+
+  gtk_rc_add_default_file(ETCDIR"/postfish-gtkrc");
   if(homedir){
     char *rcfile="/.postfish-gtkrc";
     char *homerc=calloc(1,strlen(homedir)+strlen(rcfile)+1);
@@ -1114,13 +1201,13 @@
   memset(labels,0,sizeof(labels));
   switch(ch){
   case 1:
-    labels[0]="_0 mono";
+    labels[0]="_1 mono";
     break;
   case 2:
-    labels[0]="_0 left";
-    labels[1]="_1 right";
-    labels[2]="_2 mid";
-    labels[3]="_3 side";
+    labels[0]="_1 left";
+    labels[1]="_2 right";
+    labels[2]="_y mid";
+    labels[3]="_z side";
     break;
   case 3:
   case 4:
@@ -1136,14 +1223,17 @@
   case 14:
   case 15:
   case 16:
-    for(i=0;i<ch;i++){
-      sprintf(buffer,"_%d",i);
+    for(i=0;i<ch && i<9;i++){
+      sprintf(buffer,"_%d",i+1);
       labels[i]=strdup(buffer);
     }
-    sprintf(buffer,"_%d mid",i);
-    labels[i++]=strdup(buffer);
-    sprintf(buffer,"_%d div",i);
-    labels[i++]=strdup(buffer);
+    for(;i<ch;i++){
+      sprintf(buffer,"%d_%d",(i+1)/10,(i+1)%10);
+      labels[i]=strdup(buffer);
+    }
+    labels[i++]=strdup("_y mid");
+    labels[i++]=strdup("_z div");
+
     break;
   default:
     fprintf(stderr,"\nPostfish currently supports inputs of one to sixteen\n"

Modified: trunk/postfish/mainpanel.h
===================================================================
--- trunk/postfish/mainpanel.h	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/mainpanel.h	2004-05-17 08:16:56 UTC (rev 6712)
@@ -32,6 +32,7 @@
 #include "singlepanel.h"
 #include "suppresspanel.h"
 #include "limitpanel.h"
+#include "mixpanel.h"
 #include "mutedummy.h"
 
 struct postfish_mainpanel{

Added: trunk/postfish/mix.c
===================================================================
--- trunk/postfish/mix.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/mix.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -0,0 +1,608 @@
+/*
+ *
+ *  postfish
+ *    
+ *      Copyright (C) 2002-2004 Monty
+ *
+ *  Postfish 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.
+ *   
+ *  Postfish 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 "postfish.h"
+#include "feedback.h"
+#include "mix.h"
+
+extern int input_ch;
+extern int input_size;
+extern int input_rate;
+
+mix_settings *mix_set;
+
+sig_atomic_t atten_visible;
+sig_atomic_t *mixpanel_active;
+sig_atomic_t *mixpanel_visible;
+
+
+typedef struct{
+  time_linkage out;
+  feedback_generic_pool feedpool;
+
+  mix_settings *prev;
+  mix_settings *curr;
+
+  float **cacheP;
+  float **cachePP;
+
+  float **cachePA;
+  float **cachePPA;
+
+  float **cachePB;
+  float **cachePPB;
+
+  int fillstate;
+} mix_state;
+
+mix_state ms;
+
+/* this should be moved somewhere obvious/generic */
+float *frame_window;
+
+/* feedback! */
+typedef struct limit_feedback{
+  feedback_generic parent_class;
+  float **peak;
+  float **rms;
+  int bypass;
+} mix_feedback;
+
+static feedback_generic *new_mix_feedback(void){
+  mix_feedback *ret=calloc(1,sizeof(*ret));
+  return (feedback_generic *)ret;
+}
+
+/* peak, rms are pulled in array[mixblock][input_ch] order */
+int pull_mix_feedback(float **peak,float **rms){
+  mix_feedback *f=(mix_feedback *)feedback_pull(&ms.feedpool);
+  int i;
+  
+  if(!f)return 0;
+  
+  if(f->bypass){
+    feedback_old(&ms.feedpool,(feedback_generic *)f);
+    return 2;
+  }else{
+    if(peak)
+      for(i=0;i<MIX_BLOCKS+5;i++)
+        memcpy(peak[i],f->peak[i],sizeof(**peak)*input_ch);
+    if(rms)
+      for(i=0;i<MIX_BLOCKS+5;i++)
+        memcpy(rms[i],f->rms[i],sizeof(**rms)*input_ch);
+    feedback_old(&ms.feedpool,(feedback_generic *)f);
+    return 1;
+  }
+}
+
+/* called only by initial setup */
+int mix_load(int outch){
+  int i;
+
+  mix_set=calloc(input_ch,sizeof(*mix_set));
+  mixpanel_active=calloc(input_ch,sizeof(*mixpanel_active));
+  mixpanel_visible=calloc(input_ch,sizeof(*mixpanel_visible));
+
+  memset(&ms,0,sizeof(ms));
+  ms.prev=calloc(input_ch,sizeof(*ms.prev));
+  ms.curr=calloc(input_ch,sizeof(*ms.curr));
+  
+  ms.cacheP=malloc(input_ch*sizeof(*ms.cacheP));
+  ms.cachePP=malloc(input_ch*sizeof(*ms.cachePP));
+  ms.cachePA=malloc(input_ch*sizeof(*ms.cachePA));
+  ms.cachePPA=malloc(input_ch*sizeof(*ms.cachePPA));
+  ms.cachePB=malloc(input_ch*sizeof(*ms.cachePB));
+  ms.cachePPB=malloc(input_ch*sizeof(*ms.cachePPB));
+  for(i=0;i<input_ch;i++)
+    ms.cacheP[i]=malloc(input_size*sizeof(**ms.cacheP));
+  for(i=0;i<input_ch;i++)
+    ms.cachePP[i]=malloc(input_size*sizeof(**ms.cachePP));
+  for(i=0;i<input_ch;i++)
+    ms.cachePA[i]=malloc(input_size*sizeof(**ms.cachePA));
+  for(i=0;i<input_ch;i++)
+    ms.cachePPA[i]=malloc(input_size*sizeof(**ms.cachePPA));
+  for(i=0;i<input_ch;i++)
+    ms.cachePB[i]=malloc(input_size*sizeof(**ms.cachePB));
+  for(i=0;i<input_ch;i++)
+    ms.cachePPB[i]=malloc(input_size*sizeof(**ms.cachePPB));
+
+  ms.out.channels=outch;
+  ms.out.data=malloc(outch*sizeof(*ms.out.data));
+  for(i=0;i<outch;i++)
+    ms.out.data[i]=malloc(input_size*sizeof(**ms.out.data));
+
+  frame_window=malloc(input_size*sizeof(*frame_window));
+  for(i=0;i<input_size;i++){
+    frame_window[i]= sin( (i+.5)/input_size*M_PI*.5 );
+    frame_window[i]*=frame_window[i];
+  }
+
+  return 0;
+}
+
+/* called only in playback thread */
+int mix_reset(){
+  while(pull_mix_feedback(NULL,NULL));
+  ms.fillstate=0;
+  return 0;
+}
+
+static void mixwork(float *data,float *cacheP,float *cachePP,
+		    float *out,
+		    float att,int del,int inv,
+		    float attP,float delP,int invP){ 
+  int offset=0;
+  int i;
+
+  if(-del>input_size*2)del= -input_size*2;
+  if(-delP>input_size*2)delP= -input_size*2;
+  
+  if(inv)att*=-1.;
+  if(invP)attP*=-1.;
+
+  if(att==attP && del==delP){
+
+    /* straight copy from cache with attenuation */
+    i=input_size*2+del;
+    while(i<input_size && offset<input_size)
+      out[offset++]+=cachePP[i++]*att;
+    
+    i=input_size+del;
+    if(i<0)i=0;
+    while(i<input_size && offset<input_size)
+      out[offset++]+=cacheP[i++]*att;
+    
+    i=0;
+    while(offset<input_size)
+      out[offset++]+=data[i++]*att;
+
+  }else{
+    /* lapped dual copy from cache */
+    
+    /* current settings */
+    i=input_size*2+del;
+    while(i<input_size && offset<input_size){
+      out[offset]+=cachePP[i++]*att*frame_window[offset];
+      offset++;
+    }
+
+    i=input_size+del;
+    if(i<0)i=0;
+    while(i<input_size && offset<input_size){
+      out[offset]+=cacheP[i++]*att*frame_window[offset];
+      offset++;
+    }
+
+    i=0;
+    while(offset<input_size){
+      out[offset]+=data[i++]*att*frame_window[offset];
+      offset++;
+    }
+
+    /* ...lapped transition from old settings */
+    offset=0;
+    i=input_size*2+delP;
+    while(i<input_size && offset<input_size){
+      out[offset]+=cachePP[i++]*attP*frame_window[input_size-offset-1];
+      offset++;
+    }
+
+    i=input_size+delP;
+    if(i<0)i=0;
+    while(i<input_size && offset<input_size){
+      out[offset]+=cacheP[i++]*attP*frame_window[input_size-offset-1];
+      offset++;
+    }
+
+    i=0;
+    while(offset<input_size){
+      out[offset]+=data[i++]*attP*frame_window[input_size-offset-1];
+      offset++;
+    }
+  }
+}
+
+/* smooth active/inactive transitions while adding */
+static void mixadd(float *in,float *out,int active,int activeP){
+  int i;
+  if(!active && !activeP)return;
+  if(active && activeP){
+    for(i=0;i<input_size;i++)
+      out[i]+=in[i];
+    return;
+  }
+  if(active){
+    /* transitioning to active */
+    for(i=0;i<input_size;i++)
+      out[i]+=in[i]*frame_window[i];
+    return;
+  }
+  /* transitioning to inactive */
+  for(i=0;i<input_size;i++)
+    out[i]+=in[i]*frame_window[input_size-i-1];
+}
+
+/* called only by playback thread */
+time_linkage *mix_read(time_linkage *in, 
+		       time_linkage *inA,  // reverb channel 
+		       time_linkage *inB){ // reverb channel
+
+  int i,j,k,outch=ms.out.channels;  
+  int outactive[outch];
+
+  float peak[MIX_BLOCKS+5][input_ch];
+  float rms[MIX_BLOCKS+5][input_ch];
+  int bypass=1;
+
+  if(in->samples==0){
+    ms.out.samples=0;
+    return &ms.out;
+  }
+  memset(outactive,0,sizeof(outactive));
+  memset(peak,0,sizeof(peak));
+  memset(rms,0,sizeof(rms));
+
+  /* fillstate here is only used for lazy initialization/reset */
+  if(ms.fillstate==0){
+    /* zero the cache */
+    for(i=0;i<input_ch;i++){  
+      memset(ms.cacheP[i],0,sizeof(**ms.cacheP)*input_size);
+      memset(ms.cachePP[i],0,sizeof(**ms.cachePP)*input_size);
+    }
+    ms.fillstate=1;
+  }
+
+  /* zero the output block; we'll me mixing into it input-by-input */
+  for(i=0;i<outch;i++)
+    memset(ms.out.data[i],0,sizeof(**ms.out.data)*input_size);
+
+  /* eliminate asynch change possibility */
+  memcpy(ms.curr,mix_set,sizeof(*mix_set)*input_ch);
+
+  /* a bit of laziness that may actually save time by avoiding
+     special-cases later */
+  for(i=0;i<input_ch;i++)
+    if(mute_channel_muted(in->active,i))
+      memset(in->data[i],0,sizeof(**in->data)*input_size);
+    
+    /* input-by-input */
+  for(i=0;i<input_ch;i++){
+    int feedit=mixpanel_visible[i] && mixpanel_active[i];
+    int feeditM=atten_visible && mixpanel_active[i];
+
+    /* master feedback is a bit of a pain; the metrics we need aren't
+       produced by any of the mixdowns below. Do it by hand */
+    if(feeditM){
+      float mix[input_size];
+      float att=fromdB(ms.curr[i].master_att * .1);
+      int del=rint(ms.curr[i].master_delay*.00001*input_rate);
+      float acc=0.;
+
+      if(!mute_channel_muted(in->active,i)){
+	memset(mix,0,sizeof(mix));
+	mixwork(in->data[i],ms.cacheP[i],ms.cachePP[i],
+		mix,att,del,0,att,del,0);
+	
+	bypass=0;
+	for(j=0;j<input_size;j++){
+	  float val=mix[j]*mix[j];
+	  if(val>peak[0][i])peak[0][i]=val;
+	  acc+=val;
+	}
+	
+	peak[0][i]=peak[0][i];
+	rms[0][i]=acc/input_size;
+      }
+
+      if(inA && !mute_channel_muted(inA->active,i)){
+	memset(mix,0,sizeof(mix));
+	mixwork(inA->data[i],ms.cacheP[i],ms.cachePP[i],
+		mix,att,del,0,att,del,0);
+	
+	bypass=0;
+	for(j=0;j<input_size;j++){
+	  float val=mix[j]*mix[j];
+	  if(val>peak[0][i])peak[0][i]=val;
+	  acc+=val;
+	}
+	
+	peak[1][i]=peak[0][i];
+	rms[1][i]=acc/input_size;
+      }
+
+      if(inB && !mute_channel_muted(inB->active,i)){
+	memset(mix,0,sizeof(mix));
+	mixwork(inB->data[i],ms.cacheP[i],ms.cachePP[i],
+		mix,att,del,0,att,del,0);
+	
+	bypass=0;
+	for(j=0;j<input_size;j++){
+	  float val=mix[j]*mix[j];
+	  if(val>peak[0][i])peak[0][i]=val;
+	  acc+=val;
+	}
+	
+	peak[2][i]=peak[0][i];
+	rms[2][i]=acc/input_size;
+      }
+    }
+
+    /* placer settings; translate to final numbers */
+    int placer=ms.curr[i].placer_place;
+    int placerP=ms.prev[i].placer_place;
+
+    float relA=(placer>100 ? placer*.01-1. : 0.);
+    float relB=(placer<100 ? 1.-placer*.01 : 0.);
+    float relAP=(placerP>100 ? placerP*.01-1. : 0.);
+    float relBP=(placerP<100 ? 1.-placerP*.01 : 0.);
+
+    float attA=
+      fromdB((ms.curr[i].master_att +
+	      ms.curr[i].placer_att * relA)*.1);
+    
+    float attB=
+      fromdB((ms.curr[i].master_att +
+	      ms.curr[i].placer_att * relB)*.1);
+    
+    int delA=
+      rint((ms.curr[i].master_delay +
+	    ms.curr[i].placer_delay * relA)*.00001*input_rate);
+
+    int delB=
+      rint((ms.curr[i].master_delay +
+	    ms.curr[i].placer_delay * relB)*.00001*input_rate);
+
+    float attAP=
+      fromdB((ms.prev[i].master_att +
+	      ms.prev[i].placer_att * relAP)*.1);
+    
+    float attBP=
+      fromdB((ms.prev[i].master_att +
+	      ms.prev[i].placer_att * relBP)*.1);
+    
+    int delAP=
+      rint((ms.prev[i].master_delay +
+	    ms.prev[i].placer_delay * relAP)*.00001*input_rate);
+
+    int delBP=
+      rint((ms.prev[i].master_delay +
+	    ms.prev[i].placer_delay * relBP)*.00001*input_rate);
+
+    /* place mix */
+    {
+      int mixedA=0,mixedB=0;
+      float mixA[input_size],mixB[input_size];
+
+      for(j=0;j<OUTPUT_CHANNELS;j++){
+	int destA=ms.curr[i].placer_destA[j];
+	int destAP=ms.prev[i].placer_destA[j];
+	int destB=ms.curr[i].placer_destB[j];
+	int destBP=ms.prev[i].placer_destB[j];
+	
+	if(destA || destAP){
+	  outactive[j]=1;
+	  
+	  if(!mixedA){
+	    memset(mixA,0,sizeof(mixA));
+	    mixwork(in->data[i],ms.cacheP[i],ms.cachePP[i],
+		    mixA,attA,delA,0,attAP,delAP,0);
+	    mixedA=1;
+	  }
+	  mixadd(mixA,ms.out.data[j],destA,destAP);
+	}
+	if(destB || destBP){
+	  outactive[j]=1;
+	  
+	  if(!mixedB){
+	    memset(mixB,0,sizeof(mixB));
+	    mixwork(in->data[i],ms.cacheP[i],ms.cachePP[i],
+		    mixB,attB,delB,0,attBP,delBP,0);
+	    mixedB=1;
+	  }
+	  mixadd(mixB,ms.out.data[j],destB,destBP);
+	}
+      }
+      
+      /* feedback for A */
+      if(feedit){
+	float acc=0.;
+	bypass=0;
+	if(mixedA){
+	  for(j=0;j<input_size;j++){
+	    float val=mixA[j]*mixA[j];
+	    if(val>peak[3][i])peak[3][i]=val;
+	    acc+=val;
+	  }
+	  
+	  peak[3][i]=peak[3][i];
+	  rms[3][i]=acc/input_size;
+	}
+      }
+
+      /* feedback for B */
+      if(feedit){
+	float acc=0.;
+	bypass=0;
+	if(mixedB){
+	  for(j=0;j<input_size;j++){
+	    float val=mixB[j]*mixB[j];
+	    if(val>peak[4][i])peak[4][i]=val;
+	    acc+=val;
+	  }
+	  
+	  peak[4][i]=peak[4][i];
+	  rms[4][i]=acc/input_size;
+	}
+      }
+    }
+
+    /* direct block mix */
+    for(k=0;k<MIX_BLOCKS;k++){
+      float mix[input_size];
+
+      int sourceM=ms.curr[i].insert_source[k][0];
+      int sourceMP=ms.prev[i].insert_source[k][0];
+      int sourceA=ms.curr[i].insert_source[k][1];
+      int sourceAP=ms.prev[i].insert_source[k][1];
+      int sourceB=ms.curr[i].insert_source[k][2];
+      int sourceBP=ms.prev[i].insert_source[k][2];
+
+      float att=
+	fromdB((ms.curr[i].master_att +
+		ms.curr[i].insert_att[k])*.1);
+      
+      int del=
+	rint((ms.curr[i].master_delay +
+	      ms.curr[i].insert_delay[k])*.00001*input_rate);
+
+      float attP=
+	fromdB((ms.prev[i].master_att +
+		ms.prev[i].insert_att[k])*.1);
+      
+      int delP=
+	rint((ms.prev[i].master_delay +
+	      ms.prev[i].insert_delay[k])*.00001*input_rate);
+
+      if(sourceM || sourceMP || 
+	 sourceA || sourceAP ||
+	 sourceB || sourceBP){
+	memset(mix,0,sizeof(mix));
+
+	/* master */
+	if(sourceM || sourceMP)
+	  mixwork(in->data[i],ms.cacheP[i],ms.cachePP[i],
+		  mix,
+		  att,del,ms.curr[i].insert_invert[k],
+		  attP,delP,ms.prev[i].insert_invert[k]);
+
+	/* reverbA */
+	if(sourceA || sourceAP)
+	  if(inA)
+	    mixwork(inA->data[i],ms.cachePA[i],ms.cachePPA[i],
+		    mix,
+		    att,del,ms.curr[i].insert_invert[k],
+		    attP,delP,ms.prev[i].insert_invert[k]);
+
+	/* reverbB */
+	if(sourceB || sourceBP)
+	  if(inB)
+	    mixwork(inB->data[i],ms.cachePB[i],ms.cachePPB[i],
+		    mix,
+		    att,del,ms.curr[i].insert_invert[k],
+		    attP,delP,ms.prev[i].insert_invert[k]);
+
+	/* mix into output */
+	for(j=0;j<OUTPUT_CHANNELS;j++){
+	  int dest=ms.curr[i].insert_dest[k][j];
+	  int destP=ms.prev[i].insert_dest[k][j];
+	  
+	  if(dest || destP){
+	    outactive[j]=1;	    
+	    mixadd(mix,ms.out.data[j],dest,destP);
+	  }
+	}
+	
+	/* feedback */
+	if(feedit){
+	  float acc=0.;
+	  bypass=0;
+	  for(j=0;j<input_size;j++){
+	    float val=mix[j]*mix[j];
+	    if(val>peak[5+k][i])peak[5+k][i]=val;
+	    acc+=val;
+	  }
+	  
+	  peak[5+k][i]=peak[5+k][i];
+	  rms[5+k][i]=acc/input_size;
+
+	}
+      }
+    }
+    /* rotate data cache */
+    {
+      float *temp=ms.cachePP[i];
+      ms.cachePP[i]=ms.cacheP[i];
+      ms.cacheP[i]=in->data[i];
+      in->data[i]=temp;
+
+      if(inA){
+	temp=ms.cachePPA[i];
+	ms.cachePPA[i]=ms.cachePA[i];
+	ms.cachePA[i]=inA->data[i];
+	inA->data[i]=temp;
+      }
+
+      if(inB){
+	temp=ms.cachePPB[i];
+	ms.cachePPB[i]=ms.cachePB[i];
+	ms.cachePB[i]=inB->data[i];
+	inB->data[i]=temp;
+      }
+    }
+  }
+  
+  /* finish output data */
+  ms.out.samples=in->samples;
+  ms.out.active=0;
+  for(i=0;i<OUTPUT_CHANNELS;i++)
+    if(outactive[i])
+      ms.out.active|=(1<<i);
+  
+  /* rotate settings cache */
+  {
+    mix_settings *temp=ms.curr;
+    ms.curr=ms.prev;
+    ms.prev=temp;
+  }
+
+  /* push feedback */
+  if(bypass){
+    mix_feedback *mf=
+      (mix_feedback *)feedback_new(&ms.feedpool,new_mix_feedback);
+    mf->bypass=1;
+    feedback_push(&ms.feedpool,(feedback_generic *)mf);
+  }else{
+    mix_feedback *mf=
+      (mix_feedback *)feedback_new(&ms.feedpool,new_mix_feedback);
+    
+    if(!mf->peak){
+      mf->peak=malloc((MIX_BLOCKS+5)*sizeof(*mf->peak));
+      mf->rms=malloc((MIX_BLOCKS+5)*sizeof(*mf->rms));
+  
+      for(i=0;i<MIX_BLOCKS+5;i++)
+        mf->rms[i]=malloc(input_ch*sizeof(**mf->rms));
+      for(i=0;i<MIX_BLOCKS+5;i++)
+        mf->peak[i]=malloc(input_ch*sizeof(**mf->peak));
+    }
+    
+    for(i=0;i<MIX_BLOCKS+5;i++){
+      memcpy(mf->peak[i],peak[i],input_ch*sizeof(**peak));
+      memcpy(mf->rms[i],rms[i],input_ch*sizeof(**rms));
+    } 
+    mf->bypass=0;
+    feedback_push(&ms.feedpool,(feedback_generic *)mf);
+  }
+
+  return &ms.out;
+}
+

Added: trunk/postfish/mix.h
===================================================================
--- trunk/postfish/mix.h	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/mix.h	2004-05-17 08:16:56 UTC (rev 6712)
@@ -0,0 +1,51 @@
+/*
+ *
+ *  postfish
+ *    
+ *      Copyright (C) 2002-2004 Monty
+ *
+ *  Postfish 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.
+ *   
+ *  Postfish 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 "postfish.h"
+
+#define MIX_BLOCKS 4
+
+typedef struct {
+  sig_atomic_t master_att;  
+  sig_atomic_t master_delay;
+
+  sig_atomic_t placer_destA[OUTPUT_CHANNELS];
+  sig_atomic_t placer_destB[OUTPUT_CHANNELS];
+  sig_atomic_t placer_place;
+  sig_atomic_t placer_att;
+  sig_atomic_t placer_delay;
+
+  sig_atomic_t insert_source[MIX_BLOCKS][3];
+  sig_atomic_t insert_invert[MIX_BLOCKS];
+  sig_atomic_t insert_att[MIX_BLOCKS];
+  sig_atomic_t insert_delay[MIX_BLOCKS];
+  sig_atomic_t insert_dest[MIX_BLOCKS][OUTPUT_CHANNELS];
+} mix_settings;
+
+extern int mix_load(int outch);
+extern int mix_reset(void);
+extern time_linkage *mix_read(time_linkage *in, 
+			      time_linkage *inA,  // reverb channel 
+			      time_linkage *inB); // reverb channel
+extern int pull_mix_feedback(float **peak,float **rms);
+

Added: trunk/postfish/mixpanel.c
===================================================================
--- trunk/postfish/mixpanel.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/mixpanel.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -0,0 +1,545 @@
+/*
+ *
+ *  postfish
+ *    
+ *      Copyright (C) 2002-2004 Monty
+ *
+ *  Postfish 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.
+ *   
+ *  Postfish 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 "postfish.h"
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include "readout.h"
+#include "multibar.h"
+#include "mainpanel.h"
+#include "subpanel.h"
+#include "feedback.h"
+#include "mix.h"
+
+extern int input_ch;
+extern int input_size;
+extern int input_rate;
+
+extern mix_settings *mix_set;
+extern sig_atomic_t atten_visible;
+extern sig_atomic_t *mixpanel_active;
+extern sig_atomic_t *mixpanel_visible;
+
+typedef struct {
+  GtkWidget *s;
+  GtkWidget *r;
+  sig_atomic_t *val;
+} slider_readout_pair;
+
+/* only the sliders we need to save for feedback */
+typedef struct {
+  GtkWidget **master;
+} atten_panelsave;
+
+typedef struct {
+  GtkWidget *place[2];
+  GtkWidget *sub[MIX_BLOCKS];
+} mix_panelsave;
+
+static atten_panelsave atten_panel;
+static mix_panelsave **mix_panels;
+
+static void dB_slider_change(GtkWidget *w,gpointer in){
+  char buffer[80];
+  slider_readout_pair *p=(slider_readout_pair *)in;
+  float val=multibar_get_value(MULTIBAR(p->s),0);
+  
+  sprintf(buffer,"%+4.1fdB",val);
+  readout_set(READOUT(p->r),buffer);
+  
+  *p->val=rint(val*10);
+}
+
+static void ms_slider_change(GtkWidget *w,gpointer in){
+  char buffer[80];
+  slider_readout_pair *p=(slider_readout_pair *)in;
+  float val=multibar_get_value(MULTIBAR(p->s),0);
+
+  if(val>-1. && val<1.){
+    sprintf(buffer,"%+4.2fms",val);
+  }else{
+    sprintf(buffer,"%+4.1fms",val);
+  }
+  readout_set(READOUT(p->r),buffer);  
+  *p->val=rint(val*100);
+}
+
+static void AB_slider_change(GtkWidget *w,gpointer in){
+  char buffer[80];
+  slider_readout_pair *p=(slider_readout_pair *)in;
+  float val=multibar_get_value(MULTIBAR(p->s),0);
+  
+  if(val==100){
+    sprintf(buffer,"center");
+  }else if(val<100){
+    sprintf(buffer,"A+%d%%",(int)(100-val));
+  }else{
+    sprintf(buffer,"B+%d%%",(int)(val-100));
+  }
+  readout_set(READOUT(p->r),buffer);
+  
+  *p->val=rint(val);
+}
+
+static void toggle_callback(GtkWidget *w,gpointer in){
+  GtkToggleButton *b=GTK_TOGGLE_BUTTON(w);
+  sig_atomic_t *val=(sig_atomic_t *)in;
+  
+  *val=gtk_toggle_button_get_active(b);
+}
+
+static char *labels_dB[11]={"","  60","40","20","10","0","10","20","40","60","80"};
+static float levels_dB[11]={-80,-60,-40,-20,-10,0,10,20,40,60,80};
+
+static char *labels_dBn[6]={"","-40","-20","-10","0","+10"};
+static float levels_dBn[6]={-80,-40,-20,-10,0,10};
+  
+static char *labels_del[6]={"","-20","-10","-5","-1","-0"};
+static float levels_del[6]={-50,-20,-10,-5,-1,0};
+
+
+static mix_panelsave *mixpanel_create_helper(postfish_mainpanel *mp,
+					     subpanel_generic *panel,
+					     mix_settings *m){
+
+  int i,j;
+
+  char *labels_dBnn[6]={"","-40","-20","-10","-3","0"};
+  float levels_dBnn[6]={-80,-40,-20,-10,-3,0};
+  
+  char *labels_AB[3]={"A","center","B"};
+  float levels_AB[3]={0,100,200};
+
+  GtkWidget *table=gtk_table_new(12+MIX_BLOCKS*3,6,0);
+  mix_panelsave *ps=calloc(1,sizeof(*ps));
+
+  /* crossplace marker */
+  {
+    GtkWidget *box=gtk_hbox_new(0,0);
+    GtkWidget *l=gtk_label_new("Crossplace ");
+    GtkWidget *h=gtk_hseparator_new();
+
+    gtk_widget_set_name(l,"framelabel");
+
+    gtk_box_pack_start(GTK_BOX(box),l,0,0,0);
+    gtk_box_pack_start(GTK_BOX(box),h,1,1,0);
+    gtk_table_attach(GTK_TABLE(table),box,0,6,2,3,
+		     GTK_FILL,0,0,2);
+    gtk_table_set_row_spacing(GTK_TABLE(table),1,10);
+  }
+
+  /* crossplace controls */
+  {
+    slider_readout_pair *AB=calloc(1,sizeof(AB));
+    slider_readout_pair *att=calloc(1,sizeof(att));
+    slider_readout_pair *del=calloc(1,sizeof(del));
+    GtkWidget *boxA=gtk_hbox_new(1,0);
+    GtkWidget *boxB=gtk_hbox_new(1,0);
+
+    GtkWidget *lA=gtk_label_new("output A");
+    GtkWidget *lB=gtk_label_new("output B");
+
+    GtkWidget *latt=gtk_label_new("crossatten ");
+    GtkWidget *ldel=gtk_label_new("crossdelay ");
+    gtk_misc_set_alignment(GTK_MISC(latt),1,.5);
+    gtk_misc_set_alignment(GTK_MISC(ldel),1,.5);
+
+    AB->s=multibar_slider_new(3,labels_AB,levels_AB,1);
+    att->s=multibar_slider_new(6,labels_dBnn,levels_dBnn,1);
+    del->s=multibar_slider_new(6,labels_del,levels_del,1);
+    AB->r=readout_new("A+000");
+    att->r=readout_new("+00.0dB");
+    del->r=readout_new("+00.0ms");
+    AB->val=&m->placer_place;
+    att->val=&m->placer_att;
+    del->val=&m->placer_delay;
+
+    multibar_callback(MULTIBAR(AB->s),AB_slider_change,AB);
+    multibar_thumb_set(MULTIBAR(AB->s),100,0);
+    multibar_callback(MULTIBAR(att->s),dB_slider_change,att);
+    multibar_thumb_set(MULTIBAR(att->s),0,0);
+    multibar_callback(MULTIBAR(del->s),ms_slider_change,del);
+    multibar_thumb_set(MULTIBAR(del->s),0,0);
+
+    ps->place[0]=multibar_new(6,labels_dBn,levels_dBn,0,
+			      LO_ATTACK|LO_DECAY|HI_DECAY);
+    ps->place[1]=multibar_new(6,labels_dBn,levels_dBn,0,
+			      LO_ATTACK|LO_DECAY|HI_DECAY);
+
+    for(i=0;i<OUTPUT_CHANNELS;i++){
+      char buffer[80];
+      GtkWidget *bA,*bB;
+      
+      sprintf(buffer," %d ",i+1);
+
+      bA=gtk_toggle_button_new_with_label(buffer);
+      bB=gtk_toggle_button_new_with_label(buffer);
+
+      gtk_box_pack_start(GTK_BOX(boxA),bA,1,1,0);
+      gtk_box_pack_start(GTK_BOX(boxB),bB,1,1,0);
+
+      g_signal_connect (G_OBJECT (bA), "clicked",
+			G_CALLBACK (toggle_callback), 
+			(gpointer)&m->placer_destA[i]);
+      g_signal_connect (G_OBJECT (bB), "clicked",
+			G_CALLBACK (toggle_callback), 
+			(gpointer)&m->placer_destB[i]);
+
+    }
+    
+    gtk_table_attach(GTK_TABLE(table),lA,0,2,6,7,
+		     0,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),lB,5,6,6,7,
+		     0,0,0,0);
+
+    gtk_table_attach(GTK_TABLE(table),ps->place[0],0,2,4,5,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),ps->place[1],5,6,4,5,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+
+    gtk_table_attach(GTK_TABLE(table),boxA,0,2,5,6,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),boxB,5,6,5,6,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),AB->s,2,4,4,5,
+		     GTK_FILL|GTK_EXPAND,0,2,0);
+    gtk_table_attach(GTK_TABLE(table),att->s,3,4,5,6,
+		     GTK_FILL|GTK_EXPAND,0,2,0);
+    gtk_table_attach(GTK_TABLE(table),del->s,3,4,6,7,
+		     GTK_FILL|GTK_EXPAND,0,2,0);
+    gtk_table_attach(GTK_TABLE(table),AB->r,4,5,4,5,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),att->r,4,5,5,6,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),del->r,4,5,6,7,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+
+    gtk_table_attach(GTK_TABLE(table),latt,2,3,5,6,
+		     GTK_FILL,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),ldel,2,3,6,7,
+		     GTK_FILL,0,0,0);
+
+
+  }
+
+  /* Direct Mix marker */
+  {
+    GtkWidget *box=gtk_hbox_new(0,0);
+    GtkWidget *l=gtk_label_new("Direct Mixdown Blocks ");
+    GtkWidget *h=gtk_hseparator_new();
+
+    GtkWidget *ls=gtk_label_new("source");
+    GtkWidget *lo=gtk_label_new("output");
+
+    gtk_widget_set_name(l,"framelabel");
+
+    gtk_box_pack_start(GTK_BOX(box),l,0,0,0);
+    gtk_box_pack_start(GTK_BOX(box),h,1,1,0);
+
+    gtk_table_attach(GTK_TABLE(table),box,0,6,7,8,
+		     GTK_FILL,0,0,2);
+    gtk_table_attach(GTK_TABLE(table),ls,0,2,11+MIX_BLOCKS*3,12+MIX_BLOCKS*3,
+		     GTK_FILL,0,0,2);
+    gtk_table_attach(GTK_TABLE(table),lo,5,6,11+MIX_BLOCKS*3,12+MIX_BLOCKS*3,
+		     GTK_FILL,0,0,2);
+    gtk_table_set_row_spacing(GTK_TABLE(table),6,10);
+
+  }
+
+  for(i=0;i<MIX_BLOCKS;i++){
+    slider_readout_pair *att=calloc(1,sizeof(att));
+    slider_readout_pair *del=calloc(1,sizeof(del));
+
+    GtkWidget *boxA=gtk_hbox_new(0,0);
+    GtkWidget *boxB=gtk_hbox_new(1,0);
+
+    GtkWidget *bI=gtk_check_button_new_with_mnemonic("_invert source");
+
+    GtkWidget *bM=gtk_toggle_button_new_with_label("master");
+    GtkWidget *bA=gtk_toggle_button_new_with_label("revA");
+    GtkWidget *bB=gtk_toggle_button_new_with_label("revB");
+    GtkWidget *h=gtk_hseparator_new();
+
+    GtkWidget *latt=gtk_label_new("  attenuation ");
+    GtkWidget *ldel=gtk_label_new("  delay ");
+    gtk_misc_set_alignment(GTK_MISC(latt),1,.5);
+    gtk_misc_set_alignment(GTK_MISC(ldel),1,.5);
+
+    att->s=multibar_slider_new(11,labels_dB,levels_dB,1);
+    del->s=multibar_slider_new(6,labels_del,levels_del,1);
+    att->r=readout_new("+00.0dB");
+    del->r=readout_new("+00.0ms");
+    att->val=&m->insert_att[i];
+    del->val=&m->insert_delay[i];
+
+    ps->sub[i]=multibar_new(6,labels_dBn,levels_dBn,0,
+			    LO_ATTACK|LO_DECAY|HI_DECAY);
+    
+    multibar_callback(MULTIBAR(att->s),dB_slider_change,att);
+    multibar_callback(MULTIBAR(del->s),ms_slider_change,del);
+
+    gtk_box_pack_start(GTK_BOX(boxA),bM,1,1,0);
+    gtk_box_pack_start(GTK_BOX(boxA),bA,1,1,0);
+    gtk_box_pack_start(GTK_BOX(boxA),bB,1,1,0);
+
+    g_signal_connect (G_OBJECT (bI), "clicked",
+		      G_CALLBACK (toggle_callback), 
+		      (gpointer)&m->insert_invert[i]);
+
+    g_signal_connect (G_OBJECT (bM), "clicked",
+		      G_CALLBACK (toggle_callback), 
+		      (gpointer)&m->insert_source[i][0]);
+    g_signal_connect (G_OBJECT (bA), "clicked",
+		      G_CALLBACK (toggle_callback), 
+		      (gpointer)&m->insert_source[i][1]);
+    g_signal_connect (G_OBJECT (bB), "clicked",
+		      G_CALLBACK (toggle_callback), 
+		      (gpointer)&m->insert_source[i][2]);
+
+    
+
+    for(j=0;j<OUTPUT_CHANNELS;j++){
+      char buffer[80];
+      GtkWidget *b;
+      
+      sprintf(buffer," %d ",j+1);
+
+      b=gtk_toggle_button_new_with_label(buffer);
+      g_signal_connect (G_OBJECT (b), "clicked",
+			G_CALLBACK (toggle_callback), 
+			(gpointer)&m->insert_dest[i][j]);
+
+      gtk_box_pack_start(GTK_BOX(boxB),b,1,1,0);
+    }
+    
+    gtk_table_attach(GTK_TABLE(table),boxA,0,2,9+i*3,10+i*3,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),boxB,5,6,9+i*3,10+i*3,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),att->s,3,4,8+i*3,9+i*3,
+		     GTK_FILL|GTK_EXPAND,0,2,0);
+    gtk_table_attach(GTK_TABLE(table),del->s,3,4,9+i*3,10+i*3,
+		     GTK_FILL|GTK_EXPAND,0,2,0);
+    gtk_table_attach(GTK_TABLE(table),att->r,4,5,8+i*3,9+i*3,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),del->r,4,5,9+i*3,10+i*3,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+
+    gtk_table_attach(GTK_TABLE(table),bI,0,2,8+i*3,9+i*3,
+		     0,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),ps->sub[i],5,6,8+i*3,9+i*3,
+		     GTK_FILL,0,0,0);
+
+    gtk_table_attach(GTK_TABLE(table),latt,2,3,8+i*3,9+i*3,
+		     GTK_FILL,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),ldel,2,3,9+i*3,10+i*3,
+		     GTK_FILL,0,0,0);
+
+    gtk_table_attach(GTK_TABLE(table),h,0,6,10+i*3,11+i*3,
+		     GTK_FILL,0,0,2);
+
+
+  }
+
+  gtk_box_pack_start(GTK_BOX(panel->subpanel_box),table,1,1,4);
+  subpanel_show_all_but_toplevel(panel);
+
+  return ps;
+}
+
+void mixpanel_create_channel(postfish_mainpanel *mp,
+			    GtkWidget **windowbutton,
+			    GtkWidget **activebutton){
+  int i;
+  mix_panels=malloc(input_ch*sizeof(*mix_panels));
+  
+  /* a panel for each channel */
+  for(i=0;i<input_ch;i++){
+    subpanel_generic *panel;
+    char buffer[80];
+    
+    sprintf(buffer,"Mi_xdown block (channel %d)",i+1);
+    
+    panel=subpanel_create(mp,windowbutton[i],activebutton+i,
+			  &mixpanel_active[i],
+			  &mixpanel_visible[i],
+			  buffer,0,i,1);
+  
+    mix_panels[i]=mixpanel_create_helper(mp,panel,mix_set+i);
+  }
+}
+
+void attenpanel_create(postfish_mainpanel *mp,
+		       GtkWidget **windowbutton,
+		       GtkWidget **activebutton){
+  int i;
+  subpanel_generic *panel=subpanel_create(mp,windowbutton[0],activebutton,
+					  mixpanel_active,
+					  &atten_visible,
+					  "Mi_x Input Delay / Attenuation",
+					  0,0,input_ch);
+
+  GtkWidget *table=gtk_table_new(MIX_BLOCKS*3,5,0);
+  mix_panelsave *ps=calloc(1,sizeof(*ps));
+  atten_panel.master=calloc(input_ch,sizeof(*atten_panel.master));
+  
+  for(i=0;i<input_ch;i++){
+    char buffer[80];
+    GtkWidget *l1=gtk_label_new("attenuation ");
+    GtkWidget *l2=gtk_label_new("delay ");
+    GtkWidget *h=gtk_hseparator_new();
+
+    sprintf(buffer," %d ",i+1);
+    GtkWidget *lN=gtk_label_new(buffer);
+    gtk_widget_set_name(lN,"framelabel");
+
+    sprintf(buffer,"channel/reverb %d VU",i+1);
+    GtkWidget *lV=gtk_label_new(buffer);
+    
+    slider_readout_pair *att=calloc(1,sizeof(att));
+    slider_readout_pair *del=calloc(1,sizeof(del));
+    
+    atten_panel.master[i]=multibar_new(6,labels_dBn,levels_dBn,0,
+				       LO_ATTACK|LO_DECAY|HI_DECAY);
+
+    att->s=multibar_slider_new(11,labels_dB,levels_dB,1);
+    att->r=readout_new("+00.0dB");
+    att->val=&mix_set[i].master_att;
+    
+    del->s=multibar_slider_new(6,labels_del,levels_del,1);
+    del->r=readout_new("+00.0ms");
+    del->val=&mix_set[i].master_delay;
+    
+    multibar_callback(MULTIBAR(att->s),dB_slider_change,att);
+    multibar_callback(MULTIBAR(del->s),ms_slider_change,del);
+
+    multibar_thumb_set(MULTIBAR(att->s),0,0);
+    multibar_thumb_set(MULTIBAR(del->s),0,0);
+
+    gtk_misc_set_alignment(GTK_MISC(lN),1,.5);
+    gtk_misc_set_alignment(GTK_MISC(l1),1,.5);
+    gtk_misc_set_alignment(GTK_MISC(l2),1,.5);
+
+    gtk_table_attach(GTK_TABLE(table),lN,0,1,0+i*3,2+i*3,
+		     0,0,15,0);
+
+    gtk_table_attach(GTK_TABLE(table),h,0,5,2+i*3,3+i*3,
+    	     GTK_FILL|GTK_EXPAND,0,0,2);
+
+    gtk_table_attach(GTK_TABLE(table),l1,1,2,0+i*3,1+i*3,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),att->s,2,3,0+i*3,1+i*3,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),att->r,3,4,0+i*3,1+i*3,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),atten_panel.master[i],4,5,0+i*3,1+i*3,
+		     GTK_FILL,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),lV,4,5,1+i*3,2+i*3,
+		     GTK_FILL,0,0,0);
+    
+    gtk_table_attach(GTK_TABLE(table),l2,1,2,1+i*3,2+i*3,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),del->s,2,3,1+i*3,2+i*3,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+    gtk_table_attach(GTK_TABLE(table),del->r,3,4,1+i*3,2+i*3,
+		     GTK_FILL|GTK_EXPAND,0,0,0);
+  }
+
+  gtk_box_pack_start(GTK_BOX(panel->subpanel_box),table,1,1,4);
+  subpanel_show_all_but_toplevel(panel);
+}
+
+
+static float **peakfeed=0;
+static float **rmsfeed=0;
+
+void mixpanel_feedback(int displayit){
+  int i,j;
+  if(!peakfeed){
+    peakfeed=malloc(sizeof(*peakfeed)*(MIX_BLOCKS+5));
+    rmsfeed=malloc(sizeof(*rmsfeed)*(MIX_BLOCKS+5));
+
+    for(i=0;i<(MIX_BLOCKS+5);i++){
+      peakfeed[i]=malloc(sizeof(**peakfeed)*input_ch);
+      rmsfeed[i]=malloc(sizeof(**rmsfeed)*input_ch);
+    }
+  }
+  
+  if(pull_mix_feedback(peakfeed,rmsfeed)==1){
+    for(j=0;j<input_ch;j++){
+      for(i=0;i<(MIX_BLOCKS+3);i++){
+	float rms[input_ch];
+	float peak[input_ch];
+	
+	memset(rms,0,sizeof(rms));
+        memset(peak,0,sizeof(peak));
+	
+	switch(i){
+	case 0:
+
+	  /* master VU w/reverb display (3 channels) */
+	  rms[1]=todB(rmsfeed[0][j])*.5;
+	  peak[1]=todB(peakfeed[0][j])*.5;
+	  rms[2]=todB(rmsfeed[1][j])*.5;
+	  peak[2]=todB(peakfeed[1][j])*.5;
+	  rms[3]=todB(rmsfeed[2][j])*.5;
+	  peak[3]=todB(peakfeed[2][j])*.5;
+
+	  multibar_set(MULTIBAR(atten_panel.master[j]),rms,peak,
+		       3,(displayit && atten_visible));
+	  break;
+
+	case 2:
+	case 1:
+
+	  rms[j]=todB(rmsfeed[i+2][j])*.5;
+	  peak[j]=todB(peakfeed[i+2][j])*.5;
+	  multibar_set(MULTIBAR(mix_panels[j]->place[i-1]),rms,peak,
+		       input_ch,(displayit && mixpanel_visible[j]));
+	  break;
+	default:
+	  rms[j]=todB(rmsfeed[i+2][j])*.5;
+	  peak[j]=todB(peakfeed[i+2][j])*.5;
+	  multibar_set(MULTIBAR(mix_panels[j]->sub[i-3]),rms,peak,
+		       input_ch,(displayit && mixpanel_visible[j]));
+	  break;
+	}
+      }
+    }
+  }
+}
+
+void mixpanel_reset(void){
+  int i,j;
+  
+  for(j=0;j<input_ch;j++){
+    multibar_reset(MULTIBAR(atten_panel.master[j]));
+    multibar_reset(MULTIBAR(mix_panels[j]->place[0]));
+    multibar_reset(MULTIBAR(mix_panels[j]->place[1]));
+    
+    for(i=0;i<MIX_BLOCKS;i++)
+      multibar_reset(MULTIBAR(mix_panels[j]->sub[i]));
+  
+  }
+}
+

Added: trunk/postfish/mixpanel.h
===================================================================
--- trunk/postfish/mixpanel.h	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/mixpanel.h	2004-05-17 08:16:56 UTC (rev 6712)
@@ -0,0 +1,33 @@
+/*
+ *
+ *  postfish
+ *    
+ *      Copyright (C) 2002-2004 Monty
+ *
+ *  Postfish 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.
+ *   
+ *  Postfish 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 "postfish.h"
+
+extern void mixpanel_create_channel(postfish_mainpanel *mp,
+				   GtkWidget **windowbutton,
+				   GtkWidget **activebutton);
+extern void attenpanel_create(postfish_mainpanel *mp,
+			      GtkWidget **windowbutton,
+			      GtkWidget **activebutton);
+extern void mixpanel_feedback(int displayit);
+extern void mixpanel_reset(void);

Modified: trunk/postfish/multibar.c
===================================================================
--- trunk/postfish/multibar.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/multibar.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -350,7 +350,7 @@
 
   }
 
-  for(i=0;i<m->labels+1;i++){
+  for(i=0;i<=m->labels;i++){
     int x=rint(((float)i)/m->labels*(widget->allocation.width-xpad*2-1))+xpad;
     int y=widget->allocation.height-lpad-upad;
     int px,py;
@@ -367,17 +367,22 @@
                      widget->style->text_gc[gc],
                      x, y/4+upad, x, y+upad);
 
-    if(i>0){
-      pango_layout_get_pixel_size(m->layout[i-1],&px,&py);
+    pango_layout_get_pixel_size(m->layout[i],&px,&py);
+
+    if(i==0){
+      x+=2;
+      y-=py;
+      y/=2;
+    }else{
       x-=px+2;
       y-=py;
       y/=2;
-      
-      gdk_draw_layout (m->backing,
-		       widget->style->text_gc[gc],
-		       x, y+upad,
-		       m->layout[i-1]);
     }
+    gdk_draw_layout (m->backing,
+		     widget->style->text_gc[gc],
+		     x, y+upad,
+		     m->layout[i]);
+
   }
 
   /* draw frame */
@@ -1079,18 +1084,18 @@
 
   /* not the *proper* way to do it, but this is a one-shot */
   m->levels=calloc((n+1),sizeof(*m->levels));
-  m->labels=n;
-  memcpy(m->levels,levels,(n+1)*sizeof(*levels));
+  m->labels=n-1;
+  memcpy(m->levels,levels,n*sizeof(*levels));
 
-  m->layout=calloc(m->labels,sizeof(*m->layout));
-  for(i=0;i<m->labels;i++)
+  m->layout=calloc(n,sizeof(*m->layout));
+  for(i=0;i<n;i++)
     m->layout[i]=gtk_widget_create_pango_layout(ret,labels[i]);
 
   m->dampen_flags=flags;
   m->thumbfocus=-1;
   m->thumbgrab=-1;
   m->thumblo=levels[0];
-  m->thumbhi=levels[n];
+  m->thumbhi=levels[n-1];
   m->thumblo_x=val_to_pixel(m,m->thumblo);
   m->thumbhi_x=val_to_pixel(m,m->thumbhi);
 

Modified: trunk/postfish/multicompand.c
===================================================================
--- trunk/postfish/multicompand.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/multicompand.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -69,7 +69,7 @@
   
   float **peak;
   float **rms;
-
+  int ch;
 } multicompand_state;
 
 multicompand_settings multi_master_set;
@@ -81,17 +81,7 @@
 static subband_window sw[multicomp_banks];
 
 static feedback_generic *new_multicompand_feedback(void){
-  int i;
   multicompand_feedback *ret=calloc(1,sizeof(*ret));
-
-  ret->peak=malloc(multicomp_freqs_max*sizeof(*ret->peak));
-  for(i=0;i<multicomp_freqs_max;i++)
-    ret->peak[i]=malloc(input_ch*sizeof(**ret->peak));
-   
-  ret->rms=malloc(multicomp_freqs_max*sizeof(*ret->rms));
-  for(i=0;i<multicomp_freqs_max;i++)
-    ret->rms[i]=malloc(input_ch*sizeof(**ret->rms));
-  
   return (feedback_generic *)ret;
 }
 
@@ -109,10 +99,10 @@
   }else{
     if(peak)
       for(i=0;i<f->freq_bands;i++)
-	memcpy(peak[i],f->peak[i],sizeof(**peak)*input_ch);
+	memcpy(peak[i],f->peak[i],sizeof(**peak)*ms->ch);
     if(rms)
       for(i=0;i<f->freq_bands;i++)
-	memcpy(rms[i],f->rms[i],sizeof(**rms)*input_ch);
+	memcpy(rms[i],f->rms[i],sizeof(**rms)*ms->ch);
     if(b)*b=f->freq_bands;
     feedback_old(&ms->feedpool,(feedback_generic *)f);
     return 1;
@@ -130,7 +120,7 @@
 static void reset_filters(multicompand_state *ms){
   int i,j;
   for(i=0;i<multicomp_freqs_max;i++)
-    for(j=0;j<input_ch;j++){
+    for(j=0;j<ms->ch;j++){
       memset(&ms->over_peak[i][j],0,sizeof(peak_state));
       memset(&ms->under_peak[i][j],0,sizeof(peak_state));
       memset(&ms->base_peak[i][j],0,sizeof(peak_state));
@@ -151,44 +141,45 @@
 
 }
 
-static int multicompand_load_helper(multicompand_state *ms){
+static int multicompand_load_helper(multicompand_state *ms,int ch){
   int i;
   int qblocksize=input_size/8;
   memset(ms,0,sizeof(ms));
   
-  subband_load(&ms->ss,multicomp_freqs_max,qblocksize);
+  ms->ch=ch;
+  subband_load(&ms->ss,multicomp_freqs_max,qblocksize,ch);
 
-  ms->over_attack=calloc(input_ch,sizeof(*ms->over_attack));
-  ms->over_decay=calloc(input_ch,sizeof(*ms->over_decay));
+  ms->over_attack=calloc(ms->ch,sizeof(*ms->over_attack));
+  ms->over_decay=calloc(ms->ch,sizeof(*ms->over_decay));
 
-  ms->under_attack=calloc(input_ch,sizeof(*ms->under_attack));
-  ms->under_decay=calloc(input_ch,sizeof(*ms->under_decay));
+  ms->under_attack=calloc(ms->ch,sizeof(*ms->under_attack));
+  ms->under_decay=calloc(ms->ch,sizeof(*ms->under_decay));
 
-  ms->base_attack=calloc(input_ch,sizeof(*ms->base_attack));
-  ms->base_decay=calloc(input_ch,sizeof(*ms->base_decay));
+  ms->base_attack=calloc(ms->ch,sizeof(*ms->base_attack));
+  ms->base_decay=calloc(ms->ch,sizeof(*ms->base_decay));
 
   for(i=0;i<multicomp_freqs_max;i++){
-    ms->over_peak[i]=calloc(input_ch,sizeof(peak_state));
-    ms->under_peak[i]=calloc(input_ch,sizeof(peak_state));
-    ms->base_peak[i]=calloc(input_ch,sizeof(peak_state));
-    ms->over_iir[i]=calloc(input_ch,sizeof(iir_state));
-    ms->under_iir[i]=calloc(input_ch,sizeof(iir_state));
-    ms->base_iir[i]=calloc(input_ch,sizeof(iir_state));
+    ms->over_peak[i]=calloc(ms->ch,sizeof(peak_state));
+    ms->under_peak[i]=calloc(ms->ch,sizeof(peak_state));
+    ms->base_peak[i]=calloc(ms->ch,sizeof(peak_state));
+    ms->over_iir[i]=calloc(ms->ch,sizeof(iir_state));
+    ms->under_iir[i]=calloc(ms->ch,sizeof(iir_state));
+    ms->base_iir[i]=calloc(ms->ch,sizeof(iir_state));
   }
 
   ms->peak=calloc(multicomp_freqs_max,sizeof(*ms->peak));
   ms->rms=calloc(multicomp_freqs_max,sizeof(*ms->rms));
-  for(i=0;i<multicomp_freqs_max;i++)ms->peak[i]=malloc(input_ch*sizeof(**ms->peak));
-  for(i=0;i<multicomp_freqs_max;i++)ms->rms[i]=malloc(input_ch*sizeof(**ms->rms));
+  for(i=0;i<multicomp_freqs_max;i++)ms->peak[i]=malloc(ms->ch*sizeof(**ms->peak));
+  for(i=0;i<multicomp_freqs_max;i++)ms->rms[i]=malloc(ms->ch*sizeof(**ms->rms));
   
   return 0;
 }
 
-int multicompand_load(void){
+int multicompand_load(int outch){
   int i;
   multi_channel_set=calloc(input_ch,sizeof(*multi_channel_set));
-  multicompand_load_helper(&master_state);
-  multicompand_load_helper(&channel_state);
+  multicompand_load_helper(&master_state,outch);
+  multicompand_load_helper(&channel_state,input_ch);
 
   for(i=0;i<multicomp_banks;i++)
     subband_load_freqs(&master_state.ss,&sw[i],multicomp_freq_list[i],
@@ -221,7 +212,7 @@
                            iir_filter *filter,
                            int attackp){
   int i;
-  for(i=0;i<input_ch;i++)
+  for(i=0;i<ms->ch;i++)
     filter_set(ms,msec,filter+i,attackp);
 
 }
@@ -513,10 +504,20 @@
     multicompand_feedback *ff=
       (multicompand_feedback *)
       feedback_new(&ms->feedpool,new_multicompand_feedback);
+
+    if(!ff->peak){
+      ff->peak=malloc(multicomp_freqs_max*sizeof(*ff->peak));
+      ff->rms=malloc(multicomp_freqs_max*sizeof(*ff->rms));
+  
+      for(i=0;i<multicomp_freqs_max;i++)
+	ff->rms[i]=malloc(ms->ch*sizeof(**ff->rms));
+      for(i=0;i<multicomp_freqs_max;i++)
+	ff->peak[i]=malloc(ms->ch*sizeof(**ff->peak));
+    }
     
     for(i=0;i<maxmaxbands;i++){
-      memcpy(ff->peak[i],ms->peak[i],input_ch*sizeof(**ms->peak));
-      memcpy(ff->rms[i],ms->rms[i],input_ch*sizeof(**ms->rms));
+      memcpy(ff->peak[i],ms->peak[i],ms->ch*sizeof(**ms->peak));
+      memcpy(ff->rms[i],ms->rms[i],ms->ch*sizeof(**ms->rms));
     } 
     ff->bypass=0;
     ff->freq_bands=maxmaxbands;
@@ -530,13 +531,13 @@
   int maxmaxbands=0;
 
   for(i=0;i<multicomp_freqs_max;i++){
-    for(j=0;j<input_ch;j++){
+    for(j=0;j<ms->ch;j++){
       ms->peak[i][j]=-150.;
       ms->rms[i][j]=-150;
     }
   }
  
-  for(i=0;i<input_ch;i++){
+  for(i=0;i<ms->ch;i++){
     int maxbands=find_maxbands(&ms->ss,i);
     if(maxbands>maxmaxbands)maxmaxbands=maxbands;
     if(multicompand_work_perchannel(ms, ms->peak, ms->rms, maxbands, i, &multi_master_set))
@@ -552,13 +553,13 @@
   int maxmaxbands=0;
 
   for(i=0;i<multicomp_freqs_max;i++){
-    for(j=0;j<input_ch;j++){
+    for(j=0;j<ms->ch;j++){
       ms->peak[i][j]=-150.;
       ms->rms[i][j]=-150;
     }
   }
  
-  for(i=0;i<input_ch;i++){
+  for(i=0;i<ms->ch;i++){
     int maxbands=find_maxbands(&ms->ss,i);
     if(maxbands>maxmaxbands)maxmaxbands=maxbands;
     if(multicompand_work_perchannel(ms, ms->peak, ms->rms, maxbands, i, multi_channel_set+i))
@@ -569,12 +570,13 @@
 }
 
 time_linkage *multicompand_read_master(time_linkage *in){
-  int visible[input_ch];
-  int active[input_ch];
-  subband_window *w[input_ch];
+  multicompand_state *ms=&master_state;
+  int visible[ms->ch];
+  int active[ms->ch];
+  subband_window *w[ms->ch];
   int i,ab=multi_master_set.active_bank;
   
-  for(i=0;i<input_ch;i++){
+  for(i=0;i<ms->ch;i++){
     visible[i]=multi_master_set.panel_visible;
     active[i]=multi_master_set.panel_active;
     w[i]=&sw[ab];
@@ -609,12 +611,13 @@
 }
 
 time_linkage *multicompand_read_channel(time_linkage *in){
-  int visible[input_ch];
-  int active[input_ch];
-  subband_window *w[input_ch];
+  multicompand_state *ms=&channel_state;
+  int visible[ms->ch];
+  int active[ms->ch];
+  subband_window *w[ms->ch];
   int i;
   
-  for(i=0;i<input_ch;i++){
+  for(i=0;i<ms->ch;i++){
 
     /* do any filters need updated from UI changes? */
     float o_attackms=multi_channel_set[i].over_attack*.1;

Modified: trunk/postfish/multicompand.h
===================================================================
--- trunk/postfish/multicompand.h	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/multicompand.h	2004-05-17 08:16:56 UTC (rev 6712)
@@ -82,7 +82,7 @@
 } multicompand_settings;
 
 extern void multicompand_reset();
-extern int multicompand_load(void);
+extern int multicompand_load(int outch);
 
 extern time_linkage *multicompand_read_channel(time_linkage *in);
 extern time_linkage *multicompand_read_master(time_linkage *in);

Modified: trunk/postfish/mute.c
===================================================================
--- trunk/postfish/mute.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/mute.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -23,14 +23,13 @@
 
 #include <sys/types.h>
 #include "postfish.h"
+#include "mix.h"
 #include "mute.h"
 
-
-sig_atomic_t *mute_active;
 extern int input_ch;
+extern sig_atomic_t *mixpanel_active;
 
 int mute_load(void){
-  mute_active=calloc(input_ch,sizeof(*mute_active));
   return 0;
 }
 
@@ -43,7 +42,7 @@
   int i;
 
   for(i=0;i<input_ch;i++)
-    if(!mute_active[i])
+    if(mixpanel_active[i])
       val|= (1<<i);
 
   in->active=val;

Deleted: trunk/postfish/mutedummy.c
===================================================================
--- trunk/postfish/mutedummy.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/mutedummy.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -1,53 +0,0 @@
-/*
- *
- *  postfish
- *    
- *      Copyright (C) 2002-2004 Monty
- *
- *  Postfish 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.
- *   
- *  Postfish 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 "postfish.h"
-#include <gtk/gtk.h>
-#include <gdk/gdkkeysyms.h>
-#include "readout.h"
-#include "multibar.h"
-#include "mainpanel.h"
-#include "mutedummy.h"
-
-extern sig_atomic_t *mute_active;
-extern int input_ch;
-
-static int activebutton_action(GtkWidget *widget,gpointer in){
-  int num=(int)in;
-  int active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-  mute_active[num]=active;
-  
-  return FALSE;
-}
-
-void mutedummy_create(postfish_mainpanel *mp,
-		      GtkWidget **windowbutton,
-		      GtkWidget **activebutton){
-  int i;
-
-  /* nothing to do here but slap an activation callback on each activebutton */
-  for(i=0;i<input_ch;i++)
-    g_signal_connect_after (G_OBJECT (activebutton[i]), "clicked",
-			    G_CALLBACK (activebutton_action), (gpointer)i);
-    
-}

Modified: trunk/postfish/output.c
===================================================================
--- trunk/postfish/output.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/output.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -35,8 +35,10 @@
 #include "suppress.h"
 #include "limit.h"
 #include "mute.h"
+#include "mix.h"
 
 extern int input_size;
+extern int input_rate;
 sig_atomic_t playback_active=0;
 sig_atomic_t playback_exit=0;
 sig_atomic_t playback_seeking=0;
@@ -64,6 +66,7 @@
   suppress_reset(); /* clear any persistent lapping state */
   limit_reset(); /* clear any persistent lapping state */
   output_reset(); /* clear any persistent lapping state */
+  mix_reset();
 }
 
 typedef struct output_feedback{
@@ -247,6 +250,9 @@
     link=eq_read_channel(link);
     result|=link->samples;
 
+    link=mix_read(link,0,0);
+    result|=link->samples;
+
     link=multicompand_read_master(link);
     result|=link->samples;
     link=singlecomp_read_master(link);
@@ -267,11 +273,6 @@
     }    
 
 
-    /* the limiter is single-block zero additional latency */
-    for(i=0;i<input_ch;i++)
-      if(mute_channel_muted(link->active,i))
-	memset(link->data[i],0,sizeof(**link->data)*input_size);
-
     link=limit_read(link);
 
     /************/
@@ -281,7 +282,10 @@
       memset(rms,0,sizeof(*rms)*(input_ch+2));
       memset(peak,0,sizeof(*peak)*(input_ch+2));
       ch=link->channels;
-      rate=link->rate;
+      rate=input_rate;
+
+      /* temporary! */
+      if(ch>2)ch=2;
       
       /* lazy playbak setup; we couldn't do it until we had rate and
          channel information from the pipeline */
@@ -295,8 +299,8 @@
         setupp=1;
       }
       
-      if(audiobufsize<link->channels*link->samples*outbytes){
-	audiobufsize=link->channels*link->samples*outbytes;
+      if(audiobufsize<ch*link->samples*outbytes){
+	audiobufsize=ch*link->samples*outbytes;
         if(audiobuf)
           audiobuf=realloc(audiobuf,sizeof(*audiobuf)*audiobufsize);
         else
@@ -309,7 +313,7 @@
         float mean=0.;
         float divrms=0.;
         
-	for(j=0;j<link->channels;j++){
+	for(j=0;j<ch;j++){
           float dval=link->data[j][i];
 
           switch(outbytes){
@@ -358,12 +362,12 @@
         rms[input_ch]+= mean*mean;
         
         /* div */
-	for(j=0;j<link->channels;j++){
+	for(j=0;j<ch;j++){
           float dval=mean-link->data[j][i];
           if(fabs(dval)>peak[input_ch+1])peak[input_ch+1]=fabs(dval);
           divrms+=dval*dval;
         }
-	rms[input_ch+1]+=divrms/link->channels;
+	rms[input_ch+1]+=divrms/ch;
         
       }
 
@@ -372,7 +376,7 @@
         rms[j]=sqrt(rms[j]);
       }
       
-      count+=fwrite(audiobuf,1,link->channels*link->samples*outbytes,playback_fd);
+      count+=fwrite(audiobuf,1,ch*link->samples*outbytes,playback_fd);
       
       /* inform Lord Vader his shuttle is ready */
       push_output_feedback(peak,rms);

Modified: trunk/postfish/postfish.h
===================================================================
--- trunk/postfish/postfish.h	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/postfish.h	2004-05-17 08:16:56 UTC (rev 6712)
@@ -50,6 +50,8 @@
 #include <signal.h>
 #include <fcntl.h>
 
+#define OUTPUT_CHANNELS 6
+
 static inline float todB(float x){
   return logf((x)*(x)+1e-30f)*4.34294480f;
 }
@@ -65,7 +67,7 @@
 }
 
 static inline float fromdB_a(float x){
-  int y=1.39331762961e+06f*(x+764.6161886f);
+  int y=1.39331762961e+06f*((x<-400?-400:x)+764.6161886f);
   return *(float *)&y;
 }
 
@@ -81,16 +83,19 @@
 
 #endif
 
+#ifndef max
+#define max(x,y) ((x)>(y)?(x):(y))
+#endif
+
+
 #define toOC(n)     (log(n)*1.442695f-5.965784f)
 #define fromOC(o)   (exp(((o)+5.965784f)*.693147f))
 #define toBark(n)   (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n))
 #define fromBark(z) (102.f*(z)-2.f*pow(z,2.f)+.4f*pow(z,3.f)+pow(1.46f,z)-1.f)
 
 typedef struct time_linkage {
-  int size;
   int samples;  /* normally same as size; exception is EOF */
   int channels;
-  int rate;
   float **data;
   u_int32_t active; /* active channel bitmask */
 } time_linkage;

Added: trunk/postfish/reverb.c
===================================================================
--- trunk/postfish/reverb.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/reverb.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -0,0 +1,409 @@
+/*
+ *
+ *  postfish
+ *    
+ *      Copyright (C) 2002-2004 Monty
+ *
+ *  Postfish 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.
+ *   
+ *  Postfish 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.
+ *
+ * 
+ */
+
+/* The plate reverb implementation in this file is originally the work
+   of Steve Harris, released under the GPL2 as part of the SWH plugins
+   package.  In the interests of proper attribution, the 'AUTHORS' file
+   from SWH is reproduced here:
+
+   "[Authors] In no particular order:
+
+    Steve Harris - general stuff
+    Frank Neumann - documentation, proofreading, DSP code
+    Juhana Sadeharju - DSP code
+    Joern Nettingsmeier - DSP code, bug reports and inspiration
+    Mark Knecht - testesting, docuementation
+    Pascal Haakmat - bugfixes, testing
+    Marcus Andersson - DSP code
+    Paul Winkler - documentation
+    Matthias Nagorni - testing, inspiration
+    Nathaniel Virgo - bugfixes
+    Patrick Shirkey - testing, inspiration
+
+    Project maintainted by Steve Harris, Southampton UK.
+    steve at plugin.org.uk or swh at ecs.soton.ac.uk
+    
+    Plugin website at http://plugin.org.uk/" */
+
+#include "postfish.h"
+#include "reverb.h"
+
+typedef struct {
+  int size;
+  float *buffer[2];
+  int ptr;
+  int delay;
+  float fc;
+  float lp[2];
+  float a1a;
+  float a1b;
+  float zm1[2];
+} waveguide_nl;
+
+typedef struct {
+  float *outbuffer;
+  waveguide_nl w[8];
+} plate;
+
+typedef struct {
+  time_linkage out;
+  time_linkage outA;
+  time_linkage outB;
+
+  plate *plates;
+  int *prevactive;
+  int fillstate;
+} plate_state;
+
+extern int input_size;
+extern int input_ch;
+
+extern float *frame_window;
+plate_set *plate_channel_set;
+plate_set plate_master_set;
+
+static plate_state channel;
+static plate_state master;
+
+/* linear waveguide model */
+
+static void waveguide_init(waveguide_nl *wg,
+			   int size, float fc, float da, float db){
+  wg->size = size;
+  wg->delay = size;
+  wg->buffer[0] = calloc(size, sizeof(float));
+  wg->buffer[1] = calloc(size, sizeof(float));
+  wg->ptr = 0;
+  wg->fc = fc;
+  wg->lp[0] = 0.0f;
+  wg->lp[1] = 0.0f;
+  wg->zm1[0] = 0.0f;
+  wg->zm1[1] = 0.0f;
+  wg->a1a = (1.0f - da) / (1.0f + da);
+  wg->a1b = (1.0f - db) / (1.0f + db);
+}
+
+static void waveguide_nl_reset(waveguide_nl *wg){
+  memset(wg->buffer[0], 0, wg->size * sizeof(float));
+  memset(wg->buffer[1], 0, wg->size * sizeof(float));
+  wg->lp[0] = 0.0f;
+  wg->lp[1] = 0.0f;
+  wg->zm1[0] = 0.0f;
+  wg->zm1[1] = 0.0f;
+}
+
+static void waveguide_nl_set_delay(waveguide_nl *wg, int delay){
+  if (delay > wg->size) {
+    wg->delay = wg->size;
+  } else if (delay < 1) {
+    wg->delay = 1;
+  } else {
+    wg->delay = delay;
+  }
+}
+
+static void waveguide_nl_set_fc(waveguide_nl *wg, float fc){
+  wg->fc = fc;
+}
+
+static void waveguide_nl_process_lin(waveguide_nl *wg, float in0, float in1, 
+				     float *out0, float *out1){
+  float tmp;
+  
+  *out0 = wg->buffer[0][(wg->ptr + wg->delay) % wg->size];
+  *out0 = wg->lp[0] * (wg->fc - 1.0f) + wg->fc * *out0;
+  wg->lp[0] = *out0;
+  tmp = *out0 * -(wg->a1a) + wg->zm1[0];
+  wg->zm1[0] = tmp * wg->a1a + *out0;
+  *out0 = tmp;
+  
+  *out1 = wg->buffer[1][(wg->ptr + wg->delay) % wg->size];
+  *out1 = wg->lp[1] * (wg->fc - 1.0f) + wg->fc * *out1;
+  wg->lp[1] = *out1;
+  tmp = *out1 * -(wg->a1a) + wg->zm1[1];
+  wg->zm1[1] = tmp * wg->a1a + *out1;
+  *out1 = tmp;
+  
+  wg->buffer[0][wg->ptr] = in0;
+  wg->buffer[1][wg->ptr] = in1;
+  wg->ptr--;
+  if (wg->ptr < 0) wg->ptr += wg->size;
+}
+
+/* model the plate reverb as a set of eight linear waveguides */
+
+#define LP_INNER 0.96f
+#define LP_OUTER 0.983f
+
+#define RUN_WG(n, junct_a, junct_b) waveguide_nl_process_lin(&w[n], junct_a - out[n*2+1], junct_b - out[n*2], out+n*2, out+n*2+1)
+
+static void plate_reset_helper(plate_state *ps){
+  int i,j;
+
+  for(i=0;i<ps->out.channels;i++){
+    for (j = 0; j < 8; j++) 
+      waveguide_nl_reset(&ps->plates[i].w[j]);
+    memset(ps->plates[i].outbuffer,0,
+	   32*sizeof(*ps->plates[i].outbuffer));
+  }
+  ps->fillstate=0;
+}
+
+void plate_reset(void){
+  plate_reset_helper(&master);
+  plate_reset_helper(&channel);
+}
+
+static void plate_init(plate *p){
+  memset(p,0,sizeof(*p));
+  p->outbuffer = calloc(32, sizeof(*p->outbuffer));
+
+  waveguide_init(&p->w[0], 2389, LP_INNER, 0.04f, 0.0f);
+  waveguide_init(&p->w[1], 4742, LP_INNER, 0.17f, 0.0f);
+  waveguide_init(&p->w[2], 4623, LP_INNER, 0.52f, 0.0f);
+  waveguide_init(&p->w[3], 2142, LP_INNER, 0.48f, 0.0f);
+  waveguide_init(&p->w[4], 5597, LP_OUTER, 0.32f, 0.0f);
+  waveguide_init(&p->w[5], 3692, LP_OUTER, 0.89f, 0.0f);
+  waveguide_init(&p->w[6], 5611, LP_OUTER, 0.28f, 0.0f);
+  waveguide_init(&p->w[7], 3703, LP_OUTER, 0.29f, 0.0f);
+
+}
+ 
+int plate_load(int outch){
+  int i;
+
+  /* setting storage */
+  memset(&plate_master_set,0,sizeof(plate_master_set));
+  plate_channel_set=calloc(input_ch,sizeof(*plate_channel_set));
+
+  /* output linkages for master and channels */
+
+  master.out.channels=outch;
+  master.out.data=malloc(outch*sizeof(*master.out.data));
+  for(i=0;i<outch;i++)
+    master.out.data[i]=malloc(input_size*sizeof(**master.out.data));
+
+  channel.out.channels=input_ch;
+  channel.outA.channels=input_ch;
+  channel.outB.channels=input_ch;
+  channel.out.data=malloc(input_ch*sizeof(*channel.out.data));
+  channel.outA.data=malloc(input_ch*sizeof(*channel.outA.data));
+  channel.outB.data=malloc(input_ch*sizeof(*channel.outB.data));
+  for(i=0;i<input_ch;i++){
+    channel.out.data[i]=malloc(input_size*sizeof(**master.out.data));
+    channel.outA.data[i]=malloc(input_size*sizeof(**master.outA.data));
+    channel.outB.data[i]=malloc(input_size*sizeof(**master.outB.data));
+  }
+
+  /* allocate/initialize plates */
+  channel.plates=calloc(input_ch,sizeof(*channel.plates));
+  for(i=0;i<input_ch;i++)
+    plate_init(&channel.plates[i]);
+  
+  master.plates=calloc(outch,sizeof(*master.plates));
+  for(i=0;i<outch;i++)
+    plate_init(&master.plates[i]);
+
+  channel.prevactive=calloc(input_ch,sizeof(*channel.prevactive));
+  master.prevactive=calloc(1,sizeof(*master.prevactive));
+  return 0;
+}
+ 
+static void plate_compute(plate_set *p, plate *ps, float *in, 
+			  float *outA, float *outB, float *outC,
+			  int count){
+
+  waveguide_nl *w = ps->w;
+  float *out=ps->outbuffer;
+
+  int pos;
+  const float scale = powf(p->time*.0009999f, 1.34f);
+  const float lpscale = 1.0f - p->damping*.001f * 0.93f;
+  const float wet = p->wet*.001f;
+
+  /* waveguide reconfig */
+  for (pos=0; pos<8; pos++) 
+    waveguide_nl_set_delay(&w[pos], w[pos].size * scale);  
+  for (pos=0; pos<4; pos++) 
+    waveguide_nl_set_fc(&w[pos], LP_INNER * lpscale);
+  for (; pos<8; pos++) 
+    waveguide_nl_set_fc(&w[pos], LP_OUTER * lpscale);
+	
+  for (pos = 0; pos < count; pos++) {
+    const float alpha = (out[0] + out[2] + out[4] + out[6]) * 0.5f + in[pos];
+    const float beta = (out[1] + out[9] + out[14]) * 0.666666666f;
+    const float gamma = (out[3] + out[8] + out[11]) * 0.666666666f;
+    const float delta = (out[5] + out[10] + out[13]) * 0.666666666f;
+    const float epsilon = (out[7] + out[12] + out[15]) * 0.666666666f;
+    
+    RUN_WG(0, beta, alpha);
+    RUN_WG(1, gamma, alpha);
+    RUN_WG(2, delta, alpha);
+    RUN_WG(3, epsilon, alpha);
+    RUN_WG(4, beta, gamma);
+    RUN_WG(5, gamma, delta);
+    RUN_WG(6, delta, epsilon);
+    RUN_WG(7, epsilon, beta);
+    
+    if(!outB || !outC){
+      outA[pos]=in[pos] * (1.0f - wet) +  beta * wet;
+    }else{
+      outA[pos]=in[pos] * (1.0f - wet);
+      outB[pos]= beta * wet;
+      outC[pos]= gamma * wet;
+    }
+  }
+}
+
+time_linkage *plate_read_channel(time_linkage *in,
+				 time_linkage **revA,
+				 time_linkage **revB){
+  int i,j,ch=in->channels;
+  plate_state *ps=&channel;
+  
+  *revA=&ps->outA;
+  *revB=&ps->outB;
+
+  if(in->samples==0){
+    ps->out.samples=0;
+    ps->outA.samples=0;
+    ps->outB.samples=0;
+  }
+
+  ps->outA.active=0;
+  ps->outB.active=0;
+
+  if(ps->fillstate==0){
+    for(i=0;i<ch;i++)
+      ps->prevactive[i]=plate_channel_set[i].panel_active;
+    ps->fillstate=1;
+  }
+
+  for(i=0;i<ch;i++){
+    if(plate_channel_set[i].panel_active || ps->prevactive[i]){
+      float *x=in->data[i];
+      float *y=ps->out.data[i];
+      float *yA=ps->outA.data[i];
+      float *yB=ps->outB.data[i];
+      
+      /* clear the waveguides of old state if they were inactive */
+      if (!ps->prevactive[i]){
+	for (j = 0; j < 8; j++) 
+	  waveguide_nl_reset(&ps->plates[i].w[j]);
+	memset(ps->plates[i].outbuffer,0,
+	       32*sizeof(*ps->plates[i].outbuffer));
+      }
+
+      /* process this plate */
+      plate_compute(&plate_channel_set[i], &ps->plates[i], 
+		    x,y,yA,yB,input_size);
+      
+      if(!plate_channel_set[i].panel_active){
+	/* transition to inactive */
+	for(j=0;j<input_ch;j++){
+	  y[j]= y[j]*(1.f - frame_window[j]) + x[j] * frame_window[j];
+	  yA[j]= yA[j]*(1.f - frame_window[j]);
+	  yB[j]= yB[j]*(1.f - frame_window[j]);
+	}
+	
+      }else if (!ps->prevactive[i]){
+	/* transition to active */
+	for(j=0;j<input_ch;j++){
+	  y[j]=   y[j]* frame_window[j] + x[j] * (1. - frame_window[j]);
+	  yA[j]= yA[j]* frame_window[j];
+	  yB[j]= yB[j]* frame_window[j];
+	}
+      }
+      ps->outA.active |= 1<<i;
+      ps->outB.active |= 1<<i;
+
+    }else{
+      /* fully inactive */
+      float *temp=ps->out.data[i];
+      ps->out.data[i]=in->data[i];
+      in->data[i]=temp;
+    }
+    ps->prevactive[i]=plate_channel_set[i].panel_active;
+  }
+
+  ps->out.active=in->active;
+  ps->out.samples=in->samples;
+  ps->outA.samples=in->samples;
+  ps->outB.samples=in->samples;
+  return &ps->out;
+}
+
+time_linkage *plate_read_master(time_linkage *in){
+  int i,j,ch=in->channels;
+  plate_state *ps=&master;
+  
+  if(in->samples==0){
+    ps->out.samples=0;
+  }
+
+  if(ps->fillstate==0){
+    ps->prevactive[0]=plate_master_set.panel_active;
+    ps->fillstate=1;
+  }
+
+  for(i=0;i<ch;i++){
+    if(plate_master_set.panel_active || ps->prevactive[0]){
+      float *x=in->data[i];
+      float *y=ps->out.data[i];
+      
+      /* clear the waveguides of old state if they were inactive */
+      if (!ps->prevactive[0]){
+	for (j = 0; j < 8; j++) 
+	  waveguide_nl_reset(&ps->plates[i].w[j]);
+	memset(ps->plates[i].outbuffer,0,
+	       32*sizeof(*ps->plates[i].outbuffer));
+      }
+      
+      /* process this plate */
+      plate_compute(&plate_master_set, &ps->plates[i], 
+		    x,y,0,0,input_size);
+      
+      if(!plate_master_set.panel_active){
+	/* transition to inactive */
+	for(j=0;j<input_ch;j++)
+	  y[j]= y[j]*(1.f - frame_window[j]) + x[j] * frame_window[j];
+	
+      }else if (!ps->prevactive[0]){
+	/* transition to active */
+	for(j=0;j<input_ch;j++)
+	  y[j]=   y[j]* frame_window[j] + x[j] * (1. - frame_window[j]);
+
+      }
+    }else{
+      /* fully inactive */
+      float *temp=ps->out.data[i];
+      ps->out.data[i]=in->data[i];
+      in->data[i]=temp;
+    }
+  }
+  ps->prevactive[0]=plate_master_set.panel_active;
+
+  ps->out.active=in->active;
+  ps->out.samples=in->samples;
+  return &ps->out;
+}

Added: trunk/postfish/reverb.h
===================================================================
--- trunk/postfish/reverb.h	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/reverb.h	2004-05-17 08:16:56 UTC (rev 6712)
@@ -0,0 +1,38 @@
+/*
+ *
+ *  postfish
+ *    
+ *      Copyright (C) 2002-2004 Monty
+ *
+ *  Postfish 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.
+ *   
+ *  Postfish 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.
+ *
+ * 
+ */
+
+typedef struct {
+  sig_atomic_t panel_active;
+  sig_atomic_t panel_visible;
+
+  sig_atomic_t time;     /* 1-1000 */
+  sig_atomic_t damping;  /* 0.-1. * 1000 */ 
+  sig_atomic_t wet;      /* 0.-1. * 1000 */
+} plate_set;
+
+extern void plate_reset(void);
+extern int plate_load(int outch);
+extern time_linkage *plate_read_channel(time_linkage *in,
+					time_linkage **revA,
+					time_linkage **revB);
+extern time_linkage *plate_read_master(time_linkage *in);

Modified: trunk/postfish/singlecomp.c
===================================================================
--- trunk/postfish/singlecomp.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/singlecomp.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -63,10 +63,10 @@
 
   int mutemaskP;
   int mutemask0;
-
+  int ch;
 } singlecomp_state;
 
-float *window;
+static float *window;
 
 singlecomp_settings  singlecomp_master_set;
 singlecomp_settings *singlecomp_channel_set;
@@ -95,9 +95,9 @@
   if(!f)return 0;
   
   if(peak)
-    memcpy(peak,f->peak,sizeof(*peak)*input_ch);
+    memcpy(peak,f->peak,sizeof(*peak)*scs->ch);
   if(rms)
-    memcpy(rms,f->rms,sizeof(*rms)*input_ch);
+    memcpy(rms,f->rms,sizeof(*rms)*scs->ch);
   feedback_old(&scs->feedpool,(feedback_generic *)f);
   return 1;
 }
@@ -110,47 +110,46 @@
   return pull_singlecomp_feedback(&channel_state,peak,rms);
 }
 
-static void singlecomp_load_helper(singlecomp_state *scs){
+static void singlecomp_load_helper(singlecomp_state *scs,int ch){
   int i;
   memset(scs,0,sizeof(scs));
 
-  scs->activeP=calloc(input_ch,sizeof(*scs->activeP));
-  scs->active0=calloc(input_ch,sizeof(*scs->active0));
+  scs->ch=ch;
+  scs->activeP=calloc(scs->ch,sizeof(*scs->activeP));
+  scs->active0=calloc(scs->ch,sizeof(*scs->active0));
 
-  scs->o_attack=calloc(input_ch,sizeof(*scs->o_attack));
-  scs->o_decay=calloc(input_ch,sizeof(*scs->o_decay));
-  scs->u_attack=calloc(input_ch,sizeof(*scs->u_attack));
-  scs->u_decay=calloc(input_ch,sizeof(*scs->u_decay));
-  scs->b_attack=calloc(input_ch,sizeof(*scs->b_attack));
-  scs->b_decay=calloc(input_ch,sizeof(*scs->b_decay));
+  scs->o_attack=calloc(scs->ch,sizeof(*scs->o_attack));
+  scs->o_decay=calloc(scs->ch,sizeof(*scs->o_decay));
+  scs->u_attack=calloc(scs->ch,sizeof(*scs->u_attack));
+  scs->u_decay=calloc(scs->ch,sizeof(*scs->u_decay));
+  scs->b_attack=calloc(scs->ch,sizeof(*scs->b_attack));
+  scs->b_decay=calloc(scs->ch,sizeof(*scs->b_decay));
 
-  scs->o_iir=calloc(input_ch,sizeof(*scs->o_iir));
-  scs->b_iir=calloc(input_ch,sizeof(*scs->b_iir));
-  scs->u_iir=calloc(input_ch,sizeof(*scs->u_iir));
+  scs->o_iir=calloc(scs->ch,sizeof(*scs->o_iir));
+  scs->b_iir=calloc(scs->ch,sizeof(*scs->b_iir));
+  scs->u_iir=calloc(scs->ch,sizeof(*scs->u_iir));
 
-  scs->o_peak=calloc(input_ch,sizeof(*scs->o_peak));
-  scs->b_peak=calloc(input_ch,sizeof(*scs->b_peak));
-  scs->u_peak=calloc(input_ch,sizeof(*scs->u_peak));
+  scs->o_peak=calloc(scs->ch,sizeof(*scs->o_peak));
+  scs->b_peak=calloc(scs->ch,sizeof(*scs->b_peak));
+  scs->u_peak=calloc(scs->ch,sizeof(*scs->u_peak));
 
-  scs->out.size=input_size;
-  scs->out.channels=input_ch;
-  scs->out.rate=input_rate;
-  scs->out.data=malloc(input_ch*sizeof(*scs->out.data));
-  for(i=0;i<input_ch;i++)
+  scs->out.channels=scs->ch;
+  scs->out.data=malloc(scs->ch*sizeof(*scs->out.data));
+  for(i=0;i<scs->ch;i++)
     scs->out.data[i]=malloc(input_size*sizeof(**scs->out.data));
 
   scs->fillstate=0;
-  scs->cache=malloc(input_ch*sizeof(*scs->cache));
-  for(i=0;i<input_ch;i++)
+  scs->cache=malloc(scs->ch*sizeof(*scs->cache));
+  for(i=0;i<scs->ch;i++)
     scs->cache[i]=malloc(input_size*sizeof(**scs->cache));
 
 }
 
 /* called only by initial setup */
-int singlecomp_load(void){
+int singlecomp_load(int outch){
   int i;
-  singlecomp_load_helper(&master_state);
-  singlecomp_load_helper(&channel_state);
+  singlecomp_load_helper(&master_state,outch);
+  singlecomp_load_helper(&channel_state,input_ch);
 
   window=malloc(input_size/2*sizeof(*window));
   for(i=0;i<input_size/2;i++){
@@ -159,12 +158,12 @@
   }
 
   singlecomp_channel_set=calloc(input_ch,sizeof(*singlecomp_channel_set));
-  master_set_bundle=malloc(input_ch*sizeof(*master_set_bundle));
+  master_set_bundle=malloc(outch*sizeof(*master_set_bundle));
   channel_set_bundle=malloc(input_ch*sizeof(*channel_set_bundle));
-  for(i=0;i<input_ch;i++){
-    master_set_bundle[i]=&singlecomp_master_set;
+  for(i=0;i<input_ch;i++)
     channel_set_bundle[i]=&singlecomp_channel_set[i];
-  }
+  for(i=0;i<outch;i++)
+    master_set_bundle[i]=&singlecomp_master_set;
 
   return 0;
 }
@@ -188,12 +187,12 @@
 }
 
 static void reset_filter(singlecomp_state *scs){
-  memset(scs->o_peak,0,input_ch*sizeof(&scs->o_peak));
-  memset(scs->u_peak,0,input_ch*sizeof(&scs->u_peak));
-  memset(scs->b_peak,0,input_ch*sizeof(&scs->b_peak));
-  memset(scs->o_iir,0,input_ch*sizeof(&scs->o_iir));
-  memset(scs->u_iir,0,input_ch*sizeof(&scs->u_iir));
-  memset(scs->b_iir,0,input_ch*sizeof(&scs->b_iir));
+  memset(scs->o_peak,0,scs->ch*sizeof(&scs->o_peak));
+  memset(scs->u_peak,0,scs->ch*sizeof(&scs->u_peak));
+  memset(scs->b_peak,0,scs->ch*sizeof(&scs->b_peak));
+  memset(scs->o_iir,0,scs->ch*sizeof(&scs->o_iir));
+  memset(scs->u_iir,0,scs->ch*sizeof(&scs->u_iir));
+  memset(scs->b_iir,0,scs->ch*sizeof(&scs->b_iir));
 }
 
 /* called only in playback thread */
@@ -374,12 +373,12 @@
   u_int32_t mutemask0=scs->mutemask0;
   u_int32_t mutemaskP=scs->mutemaskP;
 
-  float peakfeed[input_ch];
-  float rmsfeed[input_ch];
+  float peakfeed[scs->ch];
+  float rmsfeed[scs->ch];
   memset(peakfeed,0,sizeof(peakfeed));
   memset(rmsfeed,0,sizeof(rmsfeed));
   
-  for(i=0;i<input_ch;i++){
+  for(i=0;i<scs->ch;i++){
 
     int activeC= active[i] && !mute_channel_muted(mutemaskC,i);
     int active0= scs->active0[i];
@@ -551,10 +550,10 @@
       (singlecomp_feedback *)feedback_new(&scs->feedpool,new_singlecomp_feedback);
     
     if(!ff->peak)
-      ff->peak=malloc(input_ch*sizeof(*ff->peak));
+      ff->peak=malloc(scs->ch*sizeof(*ff->peak));
     
     if(!ff->rms)
-      ff->rms=malloc(input_ch*sizeof(*ff->rms));
+      ff->rms=malloc(scs->ch*sizeof(*ff->rms));
     
     memcpy(ff->peak,peakfeed,sizeof(peakfeed));
     memcpy(ff->rms,rmsfeed,sizeof(rmsfeed));
@@ -583,7 +582,7 @@
       return &scs->out;
     }
     
-    for(i=0;i<input_ch;i++){
+    for(i=0;i<scs->ch;i++){
       memset(scs->o_iir+i,0,sizeof(*scs->o_iir));
       memset(scs->u_iir+i,0,sizeof(*scs->u_iir));
       memset(scs->b_iir+i,0,sizeof(*scs->b_iir));
@@ -599,17 +598,17 @@
 
     scs->fillstate=1;
     scs->out.samples=0;
-    if(in->samples==in->size)goto tidy_up;
+    if(in->samples==input_size)goto tidy_up;
     
-    for(i=0;i<input_ch;i++)
-      memset(in->data[i],0,sizeof(**in->data)*in->size);
+    for(i=0;i<scs->ch;i++)
+      memset(in->data[i],0,sizeof(**in->data)*input_size);
     in->samples=0;
     /* fall through */
   case 1: /* nominal processing */
 
     work_and_lapping(scs,scset,in,&scs->out,active);
 
-    if(scs->out.samples<scs->out.size)scs->fillstate=2;
+    if(scs->out.samples<input_size)scs->fillstate=2;
     break;
   case 2: /* we've pushed out EOF already */
     scs->out.samples=0;
@@ -617,7 +616,7 @@
   
  tidy_up:
   {
-    int tozero=scs->out.size-scs->out.samples;
+    int tozero=input_size-scs->out.samples;
     if(tozero)
       for(i=0;i<scs->out.channels;i++)
         memset(scs->out.data[i]+scs->out.samples,0,sizeof(**scs->out.data)*tozero);
@@ -627,20 +626,20 @@
 }
 
 time_linkage *singlecomp_read_master(time_linkage *in){
-  int active[input_ch],i;
+  int active[master_state.ch],i;
 
   /* local copy required to avoid concurrency problems */
-  for(i=0;i<input_ch;i++)
+  for(i=0;i<master_state.ch;i++)
     active[i]=singlecomp_master_set.panel_active;
 
   return singlecomp_read_helper(in, &master_state, master_set_bundle,active);
 }
 
 time_linkage *singlecomp_read_channel(time_linkage *in){
-  int active[input_ch],i;
+  int active[channel_state.ch],i;
 
   /* local copy required to avoid concurrency problems */
-  for(i=0;i<input_ch;i++)
+  for(i=0;i<channel_state.ch;i++)
     active[i]=singlecomp_channel_set[i].panel_active;
   
   return singlecomp_read_helper(in, &channel_state, channel_set_bundle,active);

Modified: trunk/postfish/singlecomp.h
===================================================================
--- trunk/postfish/singlecomp.h	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/singlecomp.h	2004-05-17 08:16:56 UTC (rev 6712)
@@ -52,7 +52,7 @@
 
 extern int pull_singlecomp_feedback_master(float *peak,float *rms);
 extern int pull_singlecomp_feedback_channel(float *peak,float *rms);
-extern int singlecomp_load(void);
+extern int singlecomp_load(int ch);
 extern int singlecomp_reset(void);
 extern time_linkage *singlecomp_read_master(time_linkage *in);
 extern time_linkage *singlecomp_read_channel(time_linkage *in);

Modified: trunk/postfish/singlepanel.c
===================================================================
--- trunk/postfish/singlepanel.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/singlepanel.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -186,19 +186,19 @@
                                                           subpanel_generic *panel,
                                                           singlecomp_settings *scset){
 
-  char *labels[14]={"130","120","110","100","90","80","70",
+  char *labels[15]={"","130","120","110","100","90","80","70",
                     "60","50","40","30","20","10","0"};
   float levels[15]={-140,-130,-120,-110,-100,-90,-80,-70,-60,-50,-40,
                      -30,-20,-10,0};
 
   float compand_levels[9]={.1,.25,.5,.6667,1,1.5,2,4,10};
-  char  *compand_labels[8]={"4:1","2:1","1:1.5","1:1","1:1.5","1:2","1:4","1:10"};
+  char  *compand_labels[9]={"","4:1","2:1","1:1.5","1:1","1:1.5","1:2","1:4","1:10"};
 
   float timing_levels[6]={.5,1,10,100,1000,10000};
-  char  *timing_labels[5]={"1ms","10ms","100ms","1s","10s"};
+  char  *timing_labels[6]={"","1ms","10ms","100ms","1s","10s"};
 
   float per_levels[9]={0,12.5,25,37.5,50,62.5,75,87.5,100};
-  char  *per_labels[8]={"","25%","","50%","","75%","","100%"};
+  char  *per_labels[9]={"0%","","25%","","50%","","75%","","100%"};
 
   singlecomp_panel_state *ps=calloc(1,sizeof(singlecomp_panel_state));
   ps->ms=scset;
@@ -300,7 +300,7 @@
 
     GtkWidget *label=gtk_label_new("compand ratio:");
     GtkWidget *readout=readout_new("1.55:1");
-    GtkWidget *slider=multibar_slider_new(8,compand_labels,compand_levels,1);
+    GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1);
    
     ps->under_compand.r=READOUT(readout);
     ps->under_compand.v=&ps->ms->u_ratio;
@@ -323,7 +323,7 @@
     GtkWidget *label=gtk_label_new("attack/decay:");
     GtkWidget *readout0=readout_new(" 100ms");
     GtkWidget *readout1=readout_new(" 100ms");
-    GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2);
+    GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2);
 
     ps->under_timing.r0=READOUT(readout0);
     ps->under_timing.r1=READOUT(readout1);
@@ -349,7 +349,7 @@
 
     GtkWidget *label=gtk_label_new("lookahead:");
     GtkWidget *readout=readout_new("100%");
-    GtkWidget *slider=multibar_slider_new(8,per_labels,per_levels,1);
+    GtkWidget *slider=multibar_slider_new(9,per_labels,per_levels,1);
     
     ps->under_lookahead.r=READOUT(readout);
     ps->under_lookahead.v=&ps->ms->u_lookahead;
@@ -397,7 +397,7 @@
 
     GtkWidget *label=gtk_label_new("compand ratio:");
     GtkWidget *readout=readout_new("1.55:1");
-    GtkWidget *slider=multibar_slider_new(8,compand_labels,compand_levels,1);
+    GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1);
 
     ps->over_compand.r=READOUT(readout);
     ps->over_compand.v=&ps->ms->o_ratio;
@@ -420,7 +420,7 @@
     GtkWidget *label=gtk_label_new("attack/decay:");
     GtkWidget *readout0=readout_new(" 100ms");
     GtkWidget *readout1=readout_new(" 100ms");
-    GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2);
+    GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2);
    
     ps->over_timing.r0=READOUT(readout0);
     ps->over_timing.r1=READOUT(readout1);
@@ -446,7 +446,7 @@
 
     GtkWidget *label=gtk_label_new("lookahead:");
     GtkWidget *readout=readout_new("100%");
-    GtkWidget *slider=multibar_slider_new(8,per_labels,per_levels,1);
+    GtkWidget *slider=multibar_slider_new(9,per_labels,per_levels,1);
    
     ps->over_lookahead.r=READOUT(readout);
     ps->over_lookahead.v=&ps->ms->o_lookahead;
@@ -490,7 +490,7 @@
 
     GtkWidget *label=gtk_label_new("compand ratio:");
     GtkWidget *readout=readout_new("1.55:1");
-    GtkWidget *slider=multibar_slider_new(8,compand_labels,compand_levels,1);
+    GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1);
    
     ps->base_compand.r=READOUT(readout);
     ps->base_compand.v=&ps->ms->b_ratio;
@@ -513,7 +513,7 @@
     GtkWidget *label=gtk_label_new("attack/decay:");
     GtkWidget *readout0=readout_new(" 100ms");
     GtkWidget *readout1=readout_new(" 100ms");
-    GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2);
+    GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2);
 
     ps->base_timing.r0=READOUT(readout0);
     ps->base_timing.r1=READOUT(readout1);
@@ -539,7 +539,7 @@
   {
     ps->bar.readoutu=readout_new("  +0");
     ps->bar.readouto=readout_new("  +0");
-    ps->bar.slider=multibar_new(14,labels,levels,2,HI_DECAY|LO_DECAY|LO_ATTACK);
+    ps->bar.slider=multibar_new(15,labels,levels,2,HI_DECAY|LO_DECAY|LO_ATTACK);
     ps->bar.vu=&ps->ms->u_thresh;
     ps->bar.vo=&ps->ms->o_thresh;
 
@@ -569,13 +569,13 @@
 void singlepanel_feedback(int displayit){
   int j;
   if(!peakfeed){
-    peakfeed=malloc(sizeof(*peakfeed)*input_ch);
-    rmsfeed=malloc(sizeof(*rmsfeed)*input_ch);
+    peakfeed=malloc(sizeof(*peakfeed)*max(input_ch,OUTPUT_CHANNELS));
+    rmsfeed=malloc(sizeof(*rmsfeed)*max(input_ch,OUTPUT_CHANNELS));
   }
   
   if(pull_singlecomp_feedback_master(peakfeed,rmsfeed)==1)
     multibar_set(MULTIBAR(master_panel->bar.slider),rmsfeed,peakfeed,
-		 input_ch,(displayit && singlecomp_master_set.panel_visible));
+		 OUTPUT_CHANNELS,(displayit && singlecomp_master_set.panel_visible));
   
   /* channel panels are a bit different; we want each in its native color */
   if(pull_singlecomp_feedback_channel(peakfeed,rmsfeed)==1){

Modified: trunk/postfish/subband.c
===================================================================
--- trunk/postfish/subband.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/subband.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -28,10 +28,9 @@
 
 extern int input_size;
 extern int input_rate;
-extern int input_ch;
 
 /* called only by initial setup */
-int subband_load(subband_state *f,int bands,int qblocksize){
+int subband_load(subband_state *f,int bands,int qblocksize,int ch){
   int i,j;
   memset(f,0,sizeof(*f));
 
@@ -40,44 +39,42 @@
   f->fillstate=0;
   f->lap_samples=0;
   f->lap=malloc(bands*sizeof(*f->lap));
-  f->cache0=malloc(input_ch*sizeof(*f->cache0));
-  f->cache1=malloc(input_ch*sizeof(*f->cache1));
+  f->cache0=malloc(ch*sizeof(*f->cache0));
+  f->cache1=malloc(ch*sizeof(*f->cache1));
 
-  f->lap_activeP=malloc(input_ch*sizeof(*f->lap_activeP));
-  f->lap_active1=malloc(input_ch*sizeof(*f->lap_active1));
-  f->lap_active0=malloc(input_ch*sizeof(*f->lap_active0));
-  f->lap_activeC=malloc(input_ch*sizeof(*f->lap_activeC));
+  f->lap_activeP=malloc(ch*sizeof(*f->lap_activeP));
+  f->lap_active1=malloc(ch*sizeof(*f->lap_active1));
+  f->lap_active0=malloc(ch*sizeof(*f->lap_active0));
+  f->lap_activeC=malloc(ch*sizeof(*f->lap_activeC));
 
-  f->visible1=malloc(input_ch*sizeof(*f->visible1));
-  f->visible0=malloc(input_ch*sizeof(*f->visible0));
-  f->visibleC=malloc(input_ch*sizeof(*f->visibleC));
+  f->visible1=malloc(ch*sizeof(*f->visible1));
+  f->visible0=malloc(ch*sizeof(*f->visible0));
+  f->visibleC=malloc(ch*sizeof(*f->visibleC));
   
-  f->effect_activeP=malloc(input_ch*sizeof(*f->effect_activeP));
-  f->effect_active1=malloc(input_ch*sizeof(*f->effect_active1));
-  f->effect_active0=malloc(input_ch*sizeof(*f->effect_active0));
-  f->effect_activeC=malloc(input_ch*sizeof(*f->effect_activeC));
+  f->effect_activeP=malloc(ch*sizeof(*f->effect_activeP));
+  f->effect_active1=malloc(ch*sizeof(*f->effect_active1));
+  f->effect_active0=malloc(ch*sizeof(*f->effect_active0));
+  f->effect_activeC=malloc(ch*sizeof(*f->effect_activeC));
 
-  f->wP=calloc(input_ch,sizeof(*f->wP));
-  f->w1=calloc(input_ch,sizeof(*f->w1));
-  f->w0=calloc(input_ch,sizeof(*f->w0));
-  f->wC=calloc(input_ch,sizeof(*f->wC));
+  f->wP=calloc(ch,sizeof(*f->wP));
+  f->w1=calloc(ch,sizeof(*f->w1));
+  f->w0=calloc(ch,sizeof(*f->w0));
+  f->wC=calloc(ch,sizeof(*f->wC));
 
-  for(i=0;i<input_ch;i++)
+  for(i=0;i<ch;i++)
     f->cache0[i]=malloc(input_size*sizeof(**f->cache0));
-  for(i=0;i<input_ch;i++)
+  for(i=0;i<ch;i++)
     f->cache1[i]=malloc(input_size*sizeof(**f->cache1));
 
   for(i=0;i<bands;i++){
-    f->lap[i]=malloc(input_ch*sizeof(**f->lap));
-    for(j=0;j<input_ch;j++)
+    f->lap[i]=malloc(ch*sizeof(**f->lap));
+    for(j=0;j<ch;j++)
       f->lap[i][j]=malloc(input_size*3*sizeof(***f->lap));
   }
 
-  f->out.size=input_size;
-  f->out.channels=input_ch;
-  f->out.rate=input_rate;
-  f->out.data=malloc(input_ch*sizeof(*f->out.data));
-  for(i=0;i<input_ch;i++)
+  f->out.channels=ch;
+  f->out.data=malloc(ch*sizeof(*f->out.data));
+  for(i=0;i<ch;i++)
     f->out.data[i]=malloc(input_size*sizeof(**f->out.data));
 
   /* fill in time window */
@@ -116,83 +113,98 @@
 
   w->freq_bands=bands;
 
-  /* supersample the spectrum */
+  /* unlike old postfish, we offer all frequencies via smoothly
+     supersampling the spectrum */
+  /* I'm too lazy to figure out the integral symbolically, use this
+     fancy CPU thingy for something */
+  
   w->ho_window=malloc(bands*sizeof(*w->ho_window));
-  {
-    float working[f->qblocksize*4+2];
-    
+  for(i=0;i<bands;i++)
+    w->ho_window[i]=calloc((f->qblocksize*2+1),sizeof(**w->ho_window));
+
+  /* first, build the first-pass desired, supersampled response */
+  for(j=0;j<(((f->qblocksize*2+1)/10)<<5);j++){
+    float localf= .5*j*input_rate/(f->qblocksize<<6);
+    int localbin= j>>5;
+
     for(i=0;i<bands;i++){
       float lastf=(i>0?freq_list[i-1]:0);
       float thisf=freq_list[i];
       float nextf=freq_list[i+1];
-      memset(working,0,sizeof(working));
-      
-      for(j=0;j<((f->qblocksize*2+1)<<5);j++){
-        float localf= .5*j*input_rate/(f->qblocksize<<6);
-        int localbin= j>>5;
-        float localwin;
 
-        if(localf>=lastf && localf<thisf){
-          if(i==0)
-            localwin=1.;
-          else
-            localwin= sin((localf-lastf)/(thisf-lastf)*M_PIl*.5);
-          localwin*=localwin;
-	  working[localbin]+=localwin*(1./32);
+      if(localf>=lastf && localf<nextf){
+	float localwin=1.;
+	if(localf<thisf){
+	  if(i!=0)localwin= sin((localf-lastf)/(thisf-lastf)*M_PIl*.5);
+	}else{
+	  if(i+1!=bands)localwin= sin((nextf-localf)/(nextf-thisf)*M_PIl*.5);
+	}
 
-        }else if(localf>=thisf && localf<nextf){
-          if(i+1==bands)
-            localwin=1.;
-          else
-            localwin= sin((nextf-localf)/(nextf-thisf)*M_PIl*.5);
-          
-          localwin*=localwin;
-          working[localbin]+=localwin*(1./32);
-          
-        }
+	localwin*=localwin;
+	w->ho_window[i][localbin]+=localwin*(1./32);
       }
+    }
+  }
+  j>>=5;
+  for(;j<f->qblocksize*2+1;j++){
+    float localf= .5*j*input_rate/(f->qblocksize<<1);
 
-      /* window this desired response in the time domain so that our
-         convolution is properly padded against being circular */
-      memset(f->fftwf_backward_in,0,sizeof(*f->fftwf_backward_in)*
-	     (f->qblocksize*4+2));
-      for(j=0;j<f->qblocksize*2+2;j++)
-	f->fftwf_backward_in[j*2]=working[j];
+    for(i=0;i<bands;i++){
+      float lastf=(i>0?freq_list[i-1]:0);
+      float thisf=freq_list[i];
+      float nextf=freq_list[i+1];
 
-      fftwf_execute(f->fftwf_backward);
+      if(localf>=lastf && localf<nextf){
+	float localwin=1.;
+	if(localf<thisf){
+	  if(i!=0)localwin= sin((localf-lastf)/(thisf-lastf)*M_PIl*.5);
+	}else{
+	  if(i+1!=bands)localwin= sin((nextf-localf)/(nextf-thisf)*M_PIl*.5);
+	}
 
-      /* window response in time */
-      memcpy(f->fftwf_forward_in,f->fftwf_backward_out,
-	     f->qblocksize*4*sizeof(*f->fftwf_forward_in));
-      for(j=0;j<f->qblocksize;j++){
-	float val=cos(j*M_PI/(f->qblocksize*2));
-	val=sin(val*val*M_PIl*.5);
-	f->fftwf_forward_in[j]*= sin(val*val*M_PIl*.5);
+	w->ho_window[i][j]+=localwin*localwin;
       }
-      
-      for(;j<f->qblocksize*3;j++)
-	f->fftwf_forward_in[j]=0.;
-      
-      for(;j<f->qblocksize*4;j++){
-	float val=sin((j-f->qblocksize*3)*M_PI/(f->qblocksize*2));
-	val=sin(val*val*M_PIl*.5);
-	f->fftwf_forward_in[j]*=sin(val*val*M_PIl*.5);
-      }
-      
-      /* back to frequency; this is all-real data still */
-      fftwf_execute(f->fftwf_forward);
-      for(j=0;j<f->qblocksize*4+2;j++)
-	f->fftwf_forward_out[j]/=f->qblocksize*4;
-      
-      /* now take what we learned and distill it a bit */
-      w->ho_window[i]=calloc((f->qblocksize*2+1),sizeof(**w->ho_window));
-      for(j=0;j<f->qblocksize*2+1;j++)
-        w->ho_window[i][j]=f->fftwf_forward_out[j*2];
-      
-      lastf=thisf;
-      
     }
   }
+
+  for(i=0;i<bands;i++){
+    /* window each desired response in the time domain so that our
+       convolution is properly padded against being circular */
+    memset(f->fftwf_backward_in,0,sizeof(*f->fftwf_backward_in)*
+	   (f->qblocksize*4+2));
+    for(j=0;j<f->qblocksize*2+1;j++)
+      f->fftwf_backward_in[j*2]=w->ho_window[i][j];
+    
+    fftwf_execute(f->fftwf_backward);
+    
+    /* window response in time */
+    memcpy(f->fftwf_forward_in,f->fftwf_backward_out,
+	   f->qblocksize*4*sizeof(*f->fftwf_forward_in));
+    for(j=0;j<f->qblocksize;j++){
+      float val=cos(j*M_PI/(f->qblocksize*2));
+      val=sin(val*val*M_PIl*.5);
+      f->fftwf_forward_in[j]*= sin(val*val*M_PIl*.5);
+    }
+    
+    for(;j<f->qblocksize*3;j++)
+      f->fftwf_forward_in[j]=0.;
+    
+    for(;j<f->qblocksize*4;j++){
+      float val=sin((j-f->qblocksize*3)*M_PI/(f->qblocksize*2));
+      val=sin(val*val*M_PIl*.5);
+      f->fftwf_forward_in[j]*=sin(val*val*M_PIl*.5);
+    }
+    
+    /* back to frequency; this is all-real data still */
+    fftwf_execute(f->fftwf_forward);
+    for(j=0;j<f->qblocksize*4+2;j++)
+      f->fftwf_forward_out[j]/=f->qblocksize*4;
+    
+    /* now take what we learned and distill it a bit */
+    for(j=0;j<f->qblocksize*2+1;j++)
+      w->ho_window[i][j]=f->fftwf_forward_out[j*2];
+    
+  }
   
   return(0);
 }
@@ -215,13 +227,13 @@
                          int      *active){
 
 
-  int i,j,k,l,off;
+  int i,j,k,l,off,ch=f->out.channels;
   float *workoff=f->fftwf_forward_in+f->qblocksize;
   u_int32_t mutemask=in->active;
 
   f->mutemaskC=mutemask;
 
-  for(i=0;i<input_ch;i++){
+  for(i=0;i<ch;i++){
 
     int content_p=  f->lap_activeC[i]= (visible[i]||active[i]) && !mute_channel_muted(mutemask,i);
     int content_p0= f->lap_active0[i];
@@ -320,10 +332,10 @@
 }
 
 static void unsubband_work(subband_state *f,time_linkage *in, time_linkage *out){
-  int i,j,k;
+  int i,j,k,ch=f->out.channels;
 
   f->lap_samples+=in->samples;
-  for(i=0;i<input_ch;i++){
+  for(i=0;i<ch;i++){
     
     int content_pP= f->lap_activeP[i];
     int content_p1= f->lap_active1[i];
@@ -466,20 +478,20 @@
 
   /* rotate full-frame data for next frame */
 
-  memcpy(f->effect_activeP,f->effect_active1,input_ch*sizeof(*f->effect_active1));
-  memcpy(f->effect_active1,f->effect_active0,input_ch*sizeof(*f->effect_active0));
-  memcpy(f->effect_active0,f->effect_activeC,input_ch*sizeof(*f->effect_activeC));
+  memcpy(f->effect_activeP,f->effect_active1,ch*sizeof(*f->effect_active1));
+  memcpy(f->effect_active1,f->effect_active0,ch*sizeof(*f->effect_active0));
+  memcpy(f->effect_active0,f->effect_activeC,ch*sizeof(*f->effect_activeC));
 
-  memcpy(f->visible1,f->visible0,input_ch*sizeof(*f->visible0));
-  memcpy(f->visible0,f->visibleC,input_ch*sizeof(*f->visibleC));
+  memcpy(f->visible1,f->visible0,ch*sizeof(*f->visible0));
+  memcpy(f->visible0,f->visibleC,ch*sizeof(*f->visibleC));
 
   f->mutemaskP=f->mutemask1;
   f->mutemask1=f->mutemask0;
   f->mutemask0=f->mutemaskC;
 
-  memcpy(f->wP,f->w1,input_ch*sizeof(*f->w1));
-  memcpy(f->w1,f->w0,input_ch*sizeof(*f->w0));
-  memcpy(f->w0,f->wC,input_ch*sizeof(*f->wC));
+  memcpy(f->wP,f->w1,ch*sizeof(*f->w1));
+  memcpy(f->w1,f->w0,ch*sizeof(*f->w0));
+  memcpy(f->w0,f->wC,ch*sizeof(*f->wC));
 
   f->lap_samples-=(out?f->out.samples:0);
 
@@ -489,7 +501,7 @@
 time_linkage *subband_read(time_linkage *in, subband_state *f,
                            subband_window **w,int *visible, int *active,
                            void (*workfunc)(void *),void *arg){
-  int i,j;
+  int i,j,ch=f->out.channels;
   
   switch(f->fillstate){
   case 0: /* begin priming the lapping and cache */
@@ -499,7 +511,7 @@
     }
     
     /* initially zero the lapping and cache */
-    for(i=0;i<input_ch;i++){    
+    for(i=0;i<ch;i++){    
       for(j=0;j<f->bands;j++)    
         memset(f->lap[j][i],0,sizeof(***f->lap)*input_size*2);
       memset(f->cache1[i],0,sizeof(**f->cache1)*input_size);
@@ -511,12 +523,12 @@
     /* set the vars to 'active' so that if the first frame is an
        active frame, we don't transition window into it (the window
        would have been in the previous frame */
-    for(i=0;i<input_ch;i++){
+    for(i=0;i<ch;i++){
       int set=(visible[i]||active[i]) && !mute_channel_muted(in->active,i);
-      memset(f->lap_activeP,set,sizeof(*f->lap_activeP)*input_ch);
-      memset(f->lap_active1,set,sizeof(*f->lap_active1)*input_ch);
-      memset(f->lap_active0,set,sizeof(*f->lap_active0)*input_ch);
-      //memset(f->lap_activeC,1,sizeof(*f->lap_activeC)*input_ch);
+      memset(f->lap_activeP,set,sizeof(*f->lap_activeP)*ch);
+      memset(f->lap_active1,set,sizeof(*f->lap_active1)*ch);
+      memset(f->lap_active0,set,sizeof(*f->lap_active0)*ch);
+      //memset(f->lap_activeC,1,sizeof(*f->lap_activeC)*ch);
 
       f->wP[i]=w[i];
       f->w1[i]=w[i];
@@ -524,13 +536,13 @@
 
     }
     
-    memcpy(f->effect_activeP,active,sizeof(*f->effect_activeP)*input_ch);
-    memcpy(f->effect_active1,active,sizeof(*f->effect_active1)*input_ch);
-    memcpy(f->effect_active0,active,sizeof(*f->effect_active0)*input_ch);
-    //memset(f->effect_activeC,1,sizeof(*f->effect_activeC)*input_ch);
+    memcpy(f->effect_activeP,active,sizeof(*f->effect_activeP)*ch);
+    memcpy(f->effect_active1,active,sizeof(*f->effect_active1)*ch);
+    memcpy(f->effect_active0,active,sizeof(*f->effect_active0)*ch);
+    //memset(f->effect_activeC,1,sizeof(*f->effect_activeC)*ch);
 
-    memset(f->visible1,0,sizeof(*f->visible1)*input_ch);
-    memset(f->visible0,0,sizeof(*f->visible0)*input_ch);
+    memset(f->visible1,0,sizeof(*f->visible1)*ch);
+    memset(f->visible0,0,sizeof(*f->visible0)*ch);
     
     f->mutemaskP=in->active;
     f->mutemask1=in->active;
@@ -540,17 +552,17 @@
     memset(f->fftwf_forward_in,0,f->qblocksize*4*sizeof(*f->fftwf_forward_in));
 
     /* extrapolation mechanism; avoid harsh transients at edges */
-    for(i=0;i<input_ch;i++){
+    for(i=0;i<ch;i++){
       
       if(f->lap_active0[i]){
         preextrapolate_helper(in->data[i],input_size,
                             f->cache0[i],input_size);
       
-	if(in->samples<in->size)
+	if(in->samples<input_size)
           postextrapolate_helper(f->cache0[i],input_size,
                                  in->data[i],in->samples,
                                  in->data[i]+in->samples,
-				 in->size-in->samples);
+				 input_size-in->samples);
       }
     }
       
@@ -560,10 +572,10 @@
 
     f->fillstate=1;
     f->out.samples=0;
-    if(in->samples==in->size)goto tidy_up;
+    if(in->samples==input_size)goto tidy_up;
     
-    for(i=0;i<input_ch;i++)
-      memset(in->data[i],0,sizeof(**in->data)*in->size);
+    for(i=0;i<ch;i++)
+      memset(in->data[i],0,sizeof(**in->data)*input_size);
     in->samples=0;
     /* fall through */
 
@@ -571,13 +583,13 @@
 
     /* extrapolation mechanism; avoid harsh transients at edges */
 
-    if(in->samples<in->size)
-      for(i=0;i<input_ch;i++){
+    if(in->samples<input_size)
+      for(i=0;i<ch;i++){
         if((active[i] || visible[i]) && !mute_channel_muted(in->active,i))
           postextrapolate_helper(f->cache0[i],input_size,
                                  in->data[i],in->samples,
                                  in->data[i]+in->samples,
-				 in->size-in->samples);
+				 input_size-in->samples);
       }
       
     subband_work(f,in,w,visible,active);
@@ -586,29 +598,29 @@
 
     f->fillstate=2;
     f->out.samples=0;
-    if(in->samples==in->size)goto tidy_up;
+    if(in->samples==input_size)goto tidy_up;
     
-    for(i=0;i<input_ch;i++)
-      memset(in->data[i],0,sizeof(**in->data)*in->size);
+    for(i=0;i<ch;i++)
+      memset(in->data[i],0,sizeof(**in->data)*input_size);
     in->samples=0;
     /* fall through */
 
   case 2: /* nominal processing */
     
-    if(in->samples<in->size)
-      for(i=0;i<input_ch;i++){
+    if(in->samples<input_size)
+      for(i=0;i<ch;i++){
         if((active[i] || visible[i]) && !mute_channel_muted(in->active,i))
           postextrapolate_helper(f->cache0[i],input_size,
                                  in->data[i],in->samples,
                                  in->data[i]+in->samples,
-				 in->size-in->samples);
+				 input_size-in->samples);
       }
       
     subband_work(f,in,w,visible,active);
     workfunc(arg);
     unsubband_work(f,in,&f->out);
 
-    if(f->out.samples<f->out.size)f->fillstate=3;
+    if(f->out.samples<input_size)f->fillstate=3;
     break;
 
   case 3: /* we've pushed out EOF already */
@@ -618,7 +630,7 @@
 
  tidy_up:
   {
-    int tozero=f->out.size-f->out.samples;
+    int tozero=input_size-f->out.samples;
     if(tozero)
       for(i=0;i<f->out.channels;i++)
         memset(f->out.data[i]+f->out.samples,0,sizeof(**f->out.data)*tozero);

Modified: trunk/postfish/subband.h
===================================================================
--- trunk/postfish/subband.h	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/subband.h	2004-05-17 08:16:56 UTC (rev 6712)
@@ -80,7 +80,7 @@
 
 
 
-extern int subband_load(subband_state *f,int bands, int qb);
+extern int subband_load(subband_state *f,int bands, int qb,int ch);
 extern int subband_load_freqs(subband_state *f,subband_window *w,
                               const float *freq_list,int bands);
 

Modified: trunk/postfish/suppress.c
===================================================================
--- trunk/postfish/suppress.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/suppress.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -104,7 +104,7 @@
 
   suppress_channel_set.active=calloc(input_ch,sizeof(*suppress_channel_set.active));
 
-  subband_load(&channel_state.ss,suppress_freqs,qblocksize);
+  subband_load(&channel_state.ss,suppress_freqs,qblocksize,input_ch);
   subband_load_freqs(&channel_state.ss,&sw,suppress_freq_list,suppress_freqs);
    
   for(i=0;i<suppress_freqs;i++){

Modified: trunk/postfish/suppresspanel.c
===================================================================
--- trunk/postfish/suppresspanel.c	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/suppresspanel.c	2004-05-17 08:16:56 UTC (rev 6712)
@@ -132,10 +132,10 @@
                                                          suppress_settings *sset){
   int i;
   float compand_levels[5]={1,1.5,2,3,5};
-  char  *compand_labels[4]={"1.5","2","3","5"};
+  char  *compand_labels[5]={"","1.5","2","3","5"};
 
   float timing_levels[5]={1, 10, 100, 1000, 10000};
-  char  *timing_labels[4]={"10ms","     100ms","1s","10s"};
+  char  *timing_labels[5]={"","10ms","     100ms","1s","10s"};
 
   GtkWidget *table=gtk_table_new(suppress_freqs+4,5,0);
   GtkWidget *timinglabel=gtk_label_new("suppressor filter timing");
@@ -197,7 +197,7 @@
 
   /* timing controls */
   {
-    GtkWidget *slider=multibar_slider_new(4,timing_labels,timing_levels,3);
+    GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,3);
 
     ps->timing.r0=READOUT(readout_new("10.0ms"));
     ps->timing.r1=READOUT(readout_new("10.0ms"));
@@ -230,7 +230,7 @@
     gtk_widget_set_name(label,"scalemarker");
     
     ps->bars[i].readoutc=READOUT(readout_new("1.55:1"));
-    ps->bars[i].cslider=multibar_slider_new(4,compand_labels,compand_levels,1);
+    ps->bars[i].cslider=multibar_slider_new(5,compand_labels,compand_levels,1);
     ps->bars[i].sp=ps;
     ps->bars[i].v=sset->ratio+i;
     ps->bars[i].number=i;

Modified: trunk/postfish/version.h
===================================================================
--- trunk/postfish/version.h	2004-05-17 04:33:46 UTC (rev 6711)
+++ trunk/postfish/version.h	2004-05-17 08:16:56 UTC (rev 6712)
@@ -1,2 +1,2 @@
 #define VERSION "$Id$ "
-/* DO NOT EDIT: Automated versioning hack [Mon Apr 26 03:35:14 EDT 2004] */
+/* DO NOT EDIT: Automated versioning hack [Mon May 17 04:15:01 EDT 2004] */

--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list