[xiph-commits] r8033 - trunk/postfish

xiphmont at motherfish-iii.xiph.org xiphmont at motherfish-iii.xiph.org
Sat Oct 16 13:57:40 PDT 2004


Author: xiphmont
Date: 2004-10-16 13:57:39 -0700 (Sat, 16 Oct 2004)
New Revision: 8033

Added:
   trunk/postfish/follower.c
   trunk/postfish/follower.h
Modified:
   trunk/postfish/Makefile
   trunk/postfish/bessel.c
   trunk/postfish/bessel.h
   trunk/postfish/compandpanel.c
   trunk/postfish/deverb.c
   trunk/postfish/multicompand.c
   trunk/postfish/outpanel.c
   trunk/postfish/postfish.h
   trunk/postfish/singlecomp.c
   trunk/postfish/version.h
Log:
A second major upgrade to the math behind the Bessel followers used by
the companders.  

a) Soft knees are now computed as a freebie during filter following.
No explicit soft-knee means no sqrt() means considerable optimization

b) streamlined the computation pathway of the followers, partially as
an optimization, partially to prepare for adding the scond tier
over/under filters before release

c) found a bug in the behavior of the new peak-follower math (that was
instigated to repair a more serious bug in the original version);
decay was still using a second order bessel which could still ring
about zero.  Restored the peak-hold behavior to near-original
behavior, but now use the same first-order-decay-limited filters as
the RMS follower.

Depending on platform and compander usage, these changes are good for
getting back 10-25% of the CPU.



Modified: trunk/postfish/Makefile
===================================================================
--- trunk/postfish/Makefile	2004-10-16 18:05:24 UTC (rev 8032)
+++ trunk/postfish/Makefile	2004-10-16 20:57:39 UTC (rev 8033)
@@ -30,13 +30,13 @@
 	feedback.c freq.c eq.c eqpanel.c compandpanel.c subband.c lpc.c \
 	bessel.c deverbpanel.c deverb.c singlecomp.c singlepanel.c \
 	limit.c limitpanel.c mute.c mixpanel.c mix.c reverb.c reverbpanel.c \
-	outpanel.c config.c window.c
+	outpanel.c config.c window.c follower.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 deverbpanel.o deverb.o singlecomp.o singlepanel.o \
 	limit.o limitpanel.o mute.o mixpanel.o mix.o reverb.o reverbpanel.o \
-	outpanel.o config.o window.o
+	outpanel.o config.o window.o follower.o
 GCF = -DETCDIR=\\\"$(ETCDIR)\\\" `pkg-config --cflags gtk+-2.0` -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED
 
 all:	

Modified: trunk/postfish/bessel.c
===================================================================
--- trunk/postfish/bessel.c	2004-10-16 18:05:24 UTC (rev 8032)
+++ trunk/postfish/bessel.c	2004-10-16 20:57:39 UTC (rev 8033)
@@ -201,7 +201,7 @@
   while(i<n){
     double ya= (x[i]+x0*2.+x1)*a_g + y0*a_c0+y1*a_c1;
     double yl= y0*l_c0;
-    if(ya<y0 && ya<yl)ya=yl;
+    if(ya<yl)ya=yl;
    
     x1=x0;x0=x[i];
     y1=y0;x[i]=y0=ya;
@@ -269,7 +269,7 @@
       x1=x0;x0=x[i];
     }
 
-    if(ya<y0 && ya<yl)ya=yl;
+    if(ya<yl)ya=yl;
    
     y1=y0;x[i]=y0=ya;
     i++;
@@ -313,40 +313,225 @@
   
 }
 
-/* applies a 1st order freefall filter, followed by a 2nd order attack
-   filter */
-void compute_iir_freefall1_then_symmetric2(float *x, int n, iir_state *is, 
-					   iir_filter *attack, 
-					   iir_filter *decay){
-  double a_c0=attack->c[0],d_c0=decay->c[0];
-  double a_c1=attack->c[1];
-  double a_g=1./attack->g;
-  
-  double x0=is->x[0],x1=is->x[1];
-  double y0=is->y[0],y1=is->y[1];
-  double yd=is->y[2];
-  
-  int i=0;
+/* a new experiment; bessel followers constructed specifically for
+   compand functions.  Hard and soft knee are implemented as part of
+   the follower. */
 
-  if(zerome(y0) && zerome(y1)) y0=y1=0.;
-  if(zerome(yd)) yd=0.;
+#define prologue   double a_c0=attack->c[0],l_c0=limit->c[0]; \
+                   double a_c1=attack->c[1]; \
+                   double a_g=1./(knee * attack->g);\
+                   double x0=is->x[0],x1=is->x[1]; \
+                   double y0=is->y[0],y1=is->y[1]; \
+                   int i=0; \
+                   if(zerome(y0) && zerome(y1)) y0=y1=0.; \
+                   while(i<n)
 
-  while(i<n){
-    
-    yd*=d_c0;
-    if(yd<x[i])yd=x[i];
-    
-    {
-      double ya= (yd+x0*2.+x1)*a_g + y0*a_c0+y1*a_c1;
-      
-      x1=x0;x0=yd;
-      y1=y0;x[i]=y0=ya;
-    }
+/* Three delicious filters in one: The 'attack' filter is a fast
+   second-order Bessel used two ways; as a direct RMS follower and as
+   a filter pegged to free-fall to the knee value.  The 'limit' filter
+   is a first-order free-fall (to 0) Bessel used to limit the 'attack'
+   filter to a linear-dB decay. Output is normalized to place the knee
+   at 1.0 (0dB) */
+
+void compute_iir_over_soft(float *x, int n, iir_state *is, 
+			   iir_filter *attack, iir_filter *limit,
+			   float knee, float mult, float *adj){
+  double xag=4./attack->g;
+  prologue {
+
+    double ya = (x[i]+x0*2.+x1)*a_g;
+    if(ya<xag)ya=xag;
+    ya += y0*a_c0;
+    ya += y1*a_c1;
+    double yl = y0*l_c0; 
+    if(ya<yl)ya=yl;
+
+    x1=x0;x0=x[i]; 
+    y1=y0;y0=ya;
+    adj[i++]-= todB_a((float)ya)*mult;
+
+  } 
+
+  is->x[0]=x0;is->x[1]=x1;
+  is->y[0]=y0;is->y[1]=y1;
+}
+
+void compute_iir_under_soft(float *x, int n, iir_state *is, 
+			    iir_filter *attack, iir_filter *limit,
+			    float knee, float mult, float *adj){
+  double xag=4./attack->g;
+  prologue {
+
+    double ya = (x[i]+x0*2.+x1)*a_g;
+    if(ya>xag)ya=xag;
+    ya += y0*a_c0;
+    ya += y1*a_c1;
+    double yl = y0*l_c0; 
+    if(ya<yl)ya=yl;
+
+    x1=x0;x0=x[i]; 
+    y1=y0;y0=ya;
+    adj[i++]-= todB_a((float)ya)*mult;
+
+  } 
+
+  is->x[0]=x0;is->x[1]=x1;
+  is->y[0]=y0;is->y[1]=y1;
+}
+
+void compute_iir_over_hard(float *x, int n, iir_state *is, 
+			   iir_filter *attack, iir_filter *limit,
+			   float knee, float mult, float *adj){
+  prologue {
+
+    double ya = (x[i]+x0*2.+x1)*a_g;
+    ya += y0*a_c0;
+    ya += y1*a_c1;
+    double yl = y0*l_c0; 
+    if(ya<yl)ya=yl;
+
+    x1=x0;x0=x[i]; 
+    y1=y0;y0=ya;
+    if(ya>1.)adj[i]-= todB_a((float)ya)*mult;
     i++;
-  }
+  } 
 
   is->x[0]=x0;is->x[1]=x1;
   is->y[0]=y0;is->y[1]=y1;
-  is->y[2]=yd;
 }
 
+void compute_iir_under_hard(float *x, int n, iir_state *is, 
+			    iir_filter *attack, iir_filter *limit,
+			    float knee, float mult, float *adj){
+  prologue {
+
+    double ya = (x[i]+x0*2.+x1)*a_g;
+    ya += y0*a_c0;
+    ya += y1*a_c1;
+    double yl = y0*l_c0; 
+    if(ya<yl)ya=yl;
+
+    x1=x0;x0=x[i]; 
+    y1=y0;y0=ya;
+    if(ya<1.)adj[i]-= todB_a((float)ya)*mult;
+    i++;
+  } 
+
+  is->x[0]=x0;is->x[1]=x1;
+  is->y[0]=y0;is->y[1]=y1;
+}
+
+/* One more take on the above; we need to be able to gently slew
+   multiplier changes from one block to the next.  Although it seems
+   absurd to make eight total compander follower variants, doing this
+   inline avoids a copy later on, and these are enough of a CPU sink
+   that the silliness is actually worth it. */
+
+void compute_iir_over_soft_del(float *x, int n, iir_state *is, 
+			       iir_filter *attack, iir_filter *limit,
+			       float knee, float mult, float mult2, 
+			       float *adj){
+  float multadd=(mult2-mult)/n;
+  double xag=4./attack->g;
+  prologue {
+
+    double ya = (x[i]+x0*2.+x1)*a_g;
+    if(ya<xag)ya=xag;
+    ya += y0*a_c0;
+    ya += y1*a_c1;
+    double yl = y0*l_c0; 
+    if(ya<yl)ya=yl;
+
+    x1=x0;x0=x[i]; 
+    y1=y0;y0=ya;
+    adj[i++]-= todB_a((float)ya)*mult;
+    mult+=multadd;
+
+  } 
+
+  is->x[0]=x0;is->x[1]=x1;
+  is->y[0]=y0;is->y[1]=y1;
+}
+
+void compute_iir_under_soft_del(float *x, int n, iir_state *is, 
+				iir_filter *attack, iir_filter *limit,
+				float knee, float mult, float mult2,
+				float *adj){
+  float multadd=(mult2-mult)/n;
+  double xag=4./attack->g;
+  prologue {
+
+    double ya = (x[i]+x0*2.+x1)*a_g;
+    if(ya>xag)ya=xag;
+    ya += y0*a_c0;
+    ya += y1*a_c1;
+    double yl = y0*l_c0; 
+    if(ya<yl)ya=yl;
+
+    x1=x0;x0=x[i]; 
+    y1=y0;y0=ya;
+    adj[i++]-= todB_a((float)ya)*mult;
+    mult+=multadd;
+
+  } 
+
+  is->x[0]=x0;is->x[1]=x1;
+  is->y[0]=y0;is->y[1]=y1;
+}
+
+void compute_iir_over_hard_del(float *x, int n, iir_state *is, 
+			       iir_filter *attack, iir_filter *limit,
+			       float knee, float mult, float mult2,
+			       float *adj){
+  float multadd=(mult2-mult)/n;
+  prologue {
+
+    double ya = (x[i]+x0*2.+x1)*a_g;
+    ya += y0*a_c0;
+    ya += y1*a_c1;
+    double yl = y0*l_c0; 
+    if(ya<yl)ya=yl;
+
+    x1=x0;x0=x[i]; 
+    y1=y0;y0=ya;
+    if(ya>1.)adj[i]-= todB_a((float)ya)*mult;
+    mult+=multadd;
+    i++;
+  } 
+
+  is->x[0]=x0;is->x[1]=x1;
+  is->y[0]=y0;is->y[1]=y1;
+}
+
+void compute_iir_under_hard_del(float *x, int n, iir_state *is, 
+				iir_filter *attack, iir_filter *limit,
+				float knee, float mult, float mult2,
+				float *adj){
+  float multadd=(mult2-mult)/n;
+  prologue {
+
+    double ya = (x[i]+x0*2.+x1)*a_g;
+    ya += y0*a_c0;
+    ya += y1*a_c1;
+    double yl = y0*l_c0; 
+    if(ya<yl)ya=yl;
+
+    x1=x0;x0=x[i]; 
+    y1=y0;y0=ya;
+    if(ya<1.)adj[i]-= todB_a((float)ya)*mult;
+    mult+=multadd;
+    i++;
+  } 
+
+  is->x[0]=x0;is->x[1]=x1;
+  is->y[0]=y0;is->y[1]=y1;
+}
+
+void reset_iir(iir_state *is,float value){
+  int i;
+  for(i=0;i<MAXORDER;i++){
+    is->x[i]=(double)value;
+    is->y[i]=(double)value;
+  }
+}
+

Modified: trunk/postfish/bessel.h
===================================================================
--- trunk/postfish/bessel.h	2004-10-16 18:05:24 UTC (rev 8032)
+++ trunk/postfish/bessel.h	2004-10-16 20:57:39 UTC (rev 8033)
@@ -66,7 +66,7 @@
 
 typedef struct {
   double x[MAXORDER];
-  double y[MAXORDER+1];
+  double y[MAXORDER];
 } iir_state;
 
 extern double mkbessel(double raw_alpha,int order,double *ycoeff);
@@ -85,7 +85,42 @@
 extern void compute_iir_freefallonly1(float *x, int n, iir_state *is, 
 				       iir_filter *decay);
 
-extern void compute_iir_freefall1_then_symmetric2(float *x, int n, 
-						  iir_state *is, 
-						  iir_filter *attack, 
-						  iir_filter *decay);
+
+extern void compute_iir_over_soft(float *x, int n, iir_state *is, 
+				   iir_filter *attack, iir_filter *limit,
+				   float knee, float mult, float *adj);
+
+extern void compute_iir_under_soft(float *x, int n, iir_state *is, 
+				   iir_filter *attack, iir_filter *limit,
+				   float knee, float mult, float *adj);
+
+extern void compute_iir_over_hard(float *x, int n, iir_state *is, 
+				  iir_filter *attack, iir_filter *limit,
+				  float knee, float mult, float *adj);
+
+extern void compute_iir_under_hard(float *x, int n, iir_state *is, 
+				   iir_filter *attack, iir_filter *limit,
+				   float knee, float mult, float *adj);
+
+extern void compute_iir_over_soft_del(float *x, int n, iir_state *is, 
+					  iir_filter *attack, iir_filter *limit,
+					  float knee, float mult, float mult2, 
+					  float *adj);
+
+extern void compute_iir_under_soft_del(float *x, int n, iir_state *is, 
+					   iir_filter *attack, iir_filter *limit,
+					   float knee, float mult, float mult2,
+					   float *adj);
+
+extern void compute_iir_over_hard_del(float *x, int n, iir_state *is, 
+					  iir_filter *attack, iir_filter *limit,
+					  float knee, float mult, float mult2,
+					  float *adj);
+
+extern void compute_iir_under_hard_del(float *x, int n, iir_state *is, 
+					   iir_filter *attack, iir_filter *limit,
+					   float knee, float mult, float mult2,
+					   float *adj);
+
+extern void reset_iir(iir_state *is,float value);
+

Modified: trunk/postfish/compandpanel.c
===================================================================
--- trunk/postfish/compandpanel.c	2004-10-16 18:05:24 UTC (rev 8032)
+++ trunk/postfish/compandpanel.c	2004-10-16 20:57:39 UTC (rev 8033)
@@ -317,8 +317,6 @@
 static void average_change(GtkWidget *w,gpointer in){
   multi_panel_state *mp=(multi_panel_state *)in;
   if(!mp->updating_av_slider){
-    multicompand_settings *ms=mp->ms;
-    banked_multicompand_settings *bc=ms->bc;
     cbar *b=mp->bars+multicomp_freqs_max;
     cbar *bars=mp->bars;
     int bank_active=mp->bank_active;
@@ -370,8 +368,6 @@
   int bank_active=mp->bank_active;
 
   int o,u;
-  int i;
-  int adj;
 
   u=multibar_get_value(MULTIBAR(b->slider),0);
   sprintf(buffer,"%+4ddB",u);

Modified: trunk/postfish/deverb.c
===================================================================
--- trunk/postfish/deverb.c	2004-10-16 18:05:24 UTC (rev 8032)
+++ trunk/postfish/deverb.c	2004-10-16 20:57:39 UTC (rev 8033)
@@ -213,14 +213,14 @@
 	    if(multiplier==sss->prevratio[i]){
 	      
 	      for(k=0;k<input_size;k++)
-		fast[k]=fromdB_a((todB_a(slow+k)-todB_a(fast+k))*.5*multiplier);
+		fast[k]=fromdB_a((todB_a(slow[k])-todB_a(fast[k]))*.5*multiplier);
 	      
 	    }else{
 	      float multiplier_add=(multiplier-sss->prevratio[i])/input_size;
 	      multiplier=sss->prevratio[i];
 	      
 	      for(k=0;k<input_size;k++){
-		fast[k]=fromdB_a((todB_a(slow+k)-todB_a(fast+k))*.5*multiplier);
+		fast[k]=fromdB_a((todB_a(slow[k])-todB_a(fast[k]))*.5*multiplier);
 		multiplier+=multiplier_add;
 	      }
 	      

Added: trunk/postfish/follower.c
===================================================================
--- trunk/postfish/follower.c	2004-10-16 18:05:24 UTC (rev 8032)
+++ trunk/postfish/follower.c	2004-10-16 20:57:39 UTC (rev 8033)
@@ -0,0 +1,231 @@
+/*
+ *
+ *  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 "follower.h"
+
+static void _analysis(char *base,int seq, float *data, int n,int dB, 
+		      off_t offset){
+
+  FILE *f;
+  char buf[80];
+  sprintf(buf,"%s_%d.m",base,seq);
+
+  f=fopen(buf,"a");
+  if(f){
+    int i;
+    for(i=0;i<n;i++)
+      if(dB)
+	fprintf(f,"%d %f\n",(int)(i+offset),todB(data[i]));
+      else
+	fprintf(f,"%d %f\n",(int)(i+offset),(data[i]));
+
+  }
+  fclose(f);
+}
+
+off_t offset=0;
+int offch;
+
+/* Common follower code */
+
+static void prepare_peak(float *peak, float *x, int n, int ahead,
+			 int hold, peak_state *ps){
+  int ii,jj;
+  int loc=ps->loc;
+  float val=ps->val;
+
+  /* Although we have two input_size blocks of zeroes after a
+     reset, we may still need to look ahead explicitly after a
+     reset if the lookahead is exceptionally long */
+
+  if(loc==0 && val==0){
+    for(ii=0;ii<ahead;ii++) 
+      if((x[ii]*x[ii])>val){
+        val=(x[ii]*x[ii]);
+        loc=ii+hold;
+      }
+  }
+  
+  if(val>peak[0])peak[0]=val;
+
+  for(ii=1;ii<n;ii++){
+    if((x[ii+ahead]*x[ii+ahead])>val){
+      val=(x[ii+ahead]*x[ii+ahead]);
+      loc=ii+ahead+hold;
+    }     
+    if(ii>=loc){
+      /* backfill */
+      val=0;
+      for(jj=ii+ahead-1;jj>=ii;jj--){
+        if((x[jj]*x[jj])>val)val=(x[jj]*x[jj]);
+        if(jj<n && val>peak[jj])peak[jj]=val;
+      }
+      val=(x[ii+ahead]*x[ii+ahead]);
+      loc=ii+ahead+hold;
+    }
+    if(val>peak[ii])peak[ii]=val; 
+  }
+
+  ps->loc=loc-input_size;
+  ps->val=val;
+}
+
+static void fill_work(float *A, float *B, float *work,
+		      int ahead, int hold, int mode, peak_state *ps){
+  int k;
+
+  if(mode){
+    /* peak mode */
+
+    memset(work,0,sizeof(*work)*input_size);
+    
+    if(B){
+      float bigcache[input_size*2];
+      memcpy(bigcache,A,sizeof(*work)*input_size);
+      memcpy(bigcache+input_size,B,sizeof(*work)*input_size);
+      
+      prepare_peak(work, bigcache, input_size, ahead, hold, ps);
+    }else{
+      prepare_peak(work, A, input_size, ahead, hold, ps);
+    }
+  }else{
+    /* rms mode */
+    float *cachea=A+ahead;
+    
+    if(B){
+      float *worka=work+input_size-ahead;
+      
+      for(k=0;k<input_size-ahead;k++)
+	work[k]=cachea[k]*cachea[k];
+      
+      for(k=0;k<ahead;k++)
+	worka[k]=B[k]*B[k];    
+    }else{
+
+      for(k=0;k<input_size;k++)
+	work[k]=cachea[k]*cachea[k];
+      
+    }
+  }
+
+}
+
+void bi_compand(float *A,float *B,float *adj,
+		float corner,
+		float multiplier,
+		float currmultiplier,
+		float lookahead, 
+		int mode,int softknee,
+		iir_filter *attack, iir_filter *decay,
+		iir_state *iir, peak_state *ps,
+		int active,
+		int over){
+  
+  float work[input_size];
+  float kneelevel=fromdB(corner*2);
+  int hold,ahead=(mode?step_ahead(attack->alpha):impulse_ahead2(attack->alpha));
+  
+  if(ahead>input_size)ahead=input_size;
+  hold=ahead*(1.-lookahead);
+  ahead*=lookahead;
+  
+  fill_work(A,B,work,ahead,hold,mode,ps);
+  
+  multiplier*=.5;
+  currmultiplier*=.5;
+  
+  if(!active || !adj)adj=work;
+
+  if(over){
+    if(multiplier!=currmultiplier){
+      if(softknee){
+	compute_iir_over_soft_del(work, input_size, iir, attack, decay, 
+				  kneelevel, multiplier, currmultiplier, adj);
+      }else{
+	compute_iir_over_hard_del(work, input_size, iir, attack, decay, 
+				  kneelevel, multiplier, currmultiplier, adj);
+      }
+    }else{
+      if(softknee){
+	compute_iir_over_soft(work, input_size, iir, attack, decay, 
+			      kneelevel, multiplier, adj);
+      }else{
+	compute_iir_over_hard(work, input_size, iir, attack, decay, 
+			      kneelevel, multiplier, adj);
+      }
+    }
+  }else{
+    if(multiplier!=currmultiplier){
+      if(softknee){
+	compute_iir_under_soft_del(work, input_size, iir, attack, decay, 
+				   kneelevel, multiplier, currmultiplier, adj);
+      }else{
+	compute_iir_under_hard_del(work, input_size, iir, attack, decay, 
+				 kneelevel, multiplier, currmultiplier, adj);
+      }
+    }else{
+      if(softknee){
+	compute_iir_under_soft(work, input_size, iir, attack, decay, 
+			       kneelevel, multiplier, adj);
+      }else{
+	compute_iir_under_hard(work, input_size, iir, attack, decay, 
+			       kneelevel, multiplier, adj);
+      }
+    }
+  }
+
+}
+
+void full_compand(float *A,float *B,float *adj,
+		  float multiplier,float currmultiplier,
+		  int mode,
+		  iir_filter *attack, iir_filter *decay,
+		  iir_state *iir, peak_state *ps,
+		  int active){
+  
+  int k;
+  float work[input_size];
+  int ahead=(mode?step_ahead(attack->alpha):impulse_ahead2(attack->alpha));
+  
+  fill_work(A,B,work,ahead,0,mode,ps);
+  
+  multiplier*=.5;
+  currmultiplier*=.5;
+  
+  compute_iir_symmetric_limited(work, input_size, iir, attack, decay);
+  
+  if(active){
+    if(multiplier!=currmultiplier){
+      float multiplier_add=(currmultiplier-multiplier)/input_size;
+      
+      for(k=0;k<input_size;k++){
+	adj[k]-=(todB_a2(work[k])+adj[k])*multiplier;
+	multiplier+=multiplier_add;
+      }
+    }else{ 
+      for(k=0;k<input_size;k++)
+	adj[k]-=(todB_a2(work[k])+adj[k])*multiplier;
+    }
+  }
+}

Added: trunk/postfish/follower.h
===================================================================
--- trunk/postfish/follower.h	2004-10-16 18:05:24 UTC (rev 8032)
+++ trunk/postfish/follower.h	2004-10-16 20:57:39 UTC (rev 8033)
@@ -0,0 +1,47 @@
+/*
+ *
+ *  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 "bessel.h"
+
+typedef struct {
+  int loc;
+  float val;
+} peak_state;
+
+extern void bi_compand(float *A,float *B,float *adj,
+		       float corner,
+		       float multiplier,
+		       float currmultiplier,
+		       float lookahead, 
+		       int mode,int softknee,
+		       iir_filter *attack, iir_filter *decay,
+		       iir_state *iir, peak_state *ps,
+		       int active,
+		       int over);
+
+extern void full_compand(float *A,float *B,float *adj,
+			 float multiplier,float currmultiplier,
+			 int mode,
+			 iir_filter *attack, iir_filter *decay,
+			 iir_state *iir, peak_state *ps,
+			 int active);

Modified: trunk/postfish/multicompand.c
===================================================================
--- trunk/postfish/multicompand.c	2004-10-16 18:05:24 UTC (rev 8032)
+++ trunk/postfish/multicompand.c	2004-10-16 20:57:39 UTC (rev 8033)
@@ -26,8 +26,11 @@
 #include "multicompand.h"
 #include <fftw3.h>
 #include "subband.h"
-#include "bessel.h"
+#include "follower.h"
 
+extern off_t offset;
+extern int offch;
+
 /* feedback! */
 typedef struct multicompand_feedback{
   feedback_generic parent_class;
@@ -38,11 +41,6 @@
 } multicompand_feedback;
 
 typedef struct {
-  int loc;
-  float val;
-} peak_state;
-
-typedef struct {
   sig_atomic_t static_u[multicomp_freqs_max];
   sig_atomic_t under_ratio;
 
@@ -134,9 +132,12 @@
 
 static void reset_filters_onech(multicompand_state *ms,int ch){
   int i;
-  ms->base_delay[ch]=2;
-  ms->over_delay[ch]=2;
-  ms->under_delay[ch]=2;
+  /* delays are only used to softstart individual filters that went
+     inactive at unity; the key is that we know they're starting from
+     mult of zero, which is not necessarily true at a reset */
+  ms->base_delay[ch]=0;
+  ms->over_delay[ch]=0;
+  ms->under_delay[ch]=0;
   for(i=0;i<multicomp_freqs_max;i++){
     memset(&ms->over_peak[i][ch],0,sizeof(peak_state));
     memset(&ms->under_peak[i][ch],0,sizeof(peak_state));
@@ -249,218 +250,6 @@
 
 }
 
-static void prepare_rms(float *rms, float *xx, int n, int ahead){
-  int i;
-  float *x=xx+ahead;
-  for(i=0;i<n;i++)
-    rms[i]+=x[i]*x[i];
-}
-
-static void prepare_peak(float *peak, float *x, int n, int ahead,
-                         peak_state *ps){
-  int ii,jj;
-  int loc=ps->loc;
-  float val=ps->val;
-
-  /* Although we have two input_size blocks of zeroes after a
-     reset, we may still need to look ahead explicitly after a
-     reset if the lookahead is exceptionally long */
-
-  if(loc==0 && val==0){
-    for(ii=0;ii<ahead;ii++) 
-      if((x[ii]*x[ii])>val){
-        val=(x[ii]*x[ii]);
-        loc=ii;
-      }
-  }
-  
-  if(val>peak[0])peak[0]=val;
-
-  for(ii=1;ii<n;ii++){
-    if((x[ii+ahead]*x[ii+ahead])>val){
-      val=(x[ii+ahead]*x[ii+ahead]);
-      loc=ii+ahead;
-    }     
-    if(ii>=loc){
-      /* backfill */
-      val=0;
-      for(jj=ii+ahead-1;jj>=ii;jj--){
-        if((x[jj]*x[jj])>val)val=(x[jj]*x[jj]);
-        if(jj<n && val>peak[jj])peak[jj]=val;
-      }
-      val=(x[ii+ahead]*x[ii+ahead]);
-      loc=ii+ahead;
-    }
-    if(val>peak[ii])peak[ii]=val; 
-  }
-
-  ps->loc=loc-input_size;
-  ps->val=val;
-}
-
-static void run_filter(float *dB,float *x,int n,
-		       float lookahead,int mode,
-		       iir_state *iir,iir_filter *attack,iir_filter *decay,
-		       peak_state *ps){
-  int i;
-  memset(dB,0,sizeof(*dB)*n);
-  
-  if(mode){
-    int ahead=step_ahead(attack->alpha)*lookahead;
-    if(ahead>input_size*2)ahead=input_size*2;
-    
-    prepare_peak(dB, x, n, ahead, ps);
-    compute_iir_freefall1_then_symmetric2(dB, n, iir, attack, decay);
-
-  }else{
-    int ahead=impulse_ahead2(attack->alpha)*lookahead;
-    if(ahead>input_size*2)ahead=input_size*2;
-    prepare_rms(dB, x, n, ahead);
-    compute_iir_symmetric_limited(dB, n, iir, attack, decay);
-
-  }
-
-  for(i=0;i<n;i++)
-    dB[i]=todB_a(dB+i)*.5f;
-
-}
-
-static float soft_knee(float x){
-  return (sqrtf(x*x+30.f)+x)*-.5f;
-}
-
-static float hard_knee(float x){
-  return (x>0.f?-x:0.f);
-}
-
-static void over_compand(float *lx,
-			 float zerocorner,
-			 float currcorner,
-			 iir_filter *attack, iir_filter *decay,
-			 iir_state *iir, peak_state *ps,
-			 float lookahead,int mode,int knee,
-			 float prevratio,
-			 float currratio,
-			 float *adj){
-  int k;
-  float overdB[input_size];
-
-  run_filter(overdB,lx,input_size,lookahead,mode,iir,attack,decay,ps);
-  
-  if(adj){
-    float ratio_multiplier= 1.- 1000./prevratio;
-    
-    if(zerocorner!=currcorner || prevratio!=currratio){
-      /* slew limit these attenuators */
-      float ratio_add= ((1.- 1000./currratio)-ratio_multiplier)/input_size;
-      float corner_add= (currcorner-zerocorner)/input_size;
-      
-      if(knee){
-	for(k=0;k<input_size;k++){
-	  adj[k]+=soft_knee(overdB[k]-zerocorner)*ratio_multiplier;
-	  ratio_multiplier+=ratio_add;
-	  zerocorner+=corner_add;
-	}
-      }else{
-	for(k=0;k<input_size;k++){
-	  adj[k]+=hard_knee(overdB[k]-zerocorner)*ratio_multiplier;
-	  ratio_multiplier+=ratio_add;
-	  zerocorner+=corner_add;
-	}
-      }
-    }else{
-      if(knee){
-	for(k=0;k<input_size;k++)
-	  adj[k]+=soft_knee(overdB[k]-zerocorner)*ratio_multiplier;
-      }else{
-	for(k=0;k<input_size;k++)
-	  adj[k]+=hard_knee(overdB[k]-zerocorner)*ratio_multiplier;
-      }
-    }
-  }
-}
-
-static void base_compand(float *x,
-			 iir_filter *attack, iir_filter *decay,
-			 iir_state *iir, peak_state *ps,
-			 int mode,
-			 float prevratio,
-			 float currratio,
-			 float *adj){
-  int k;
-  float basedB[input_size];
-
-  run_filter(basedB,x,input_size,1.,mode,
-	     iir,attack,decay,ps);
-  
-  if(adj){
-    float ratio_multiplier=1.-1000./prevratio;
-
-    if(prevratio!=currratio){
-      /* slew limit the attenuators */
-      float ratio_add= ((1.- 1000./currratio)-ratio_multiplier)/input_size;
-
-      for(k=0;k<input_size;k++){
-	adj[k]-=(basedB[k]+adj[k])*ratio_multiplier;
-	ratio_multiplier+=ratio_add;
-      }
-
-    }else{
-      for(k=0;k<input_size;k++)
-	adj[k]-=(basedB[k]+adj[k])*ratio_multiplier;
-    }
-  }
-}
-
-static void under_compand(float *x,
-			 float zerocorner,
-			 float currcorner,
-			 iir_filter *attack, iir_filter *decay,
-			 iir_state *iir, peak_state *ps,
-			 float lookahead,int mode,int knee,
-			 float prevratio,
-			 float currratio,
-			 float *adj){
-  int k;
-  float underdB[input_size];
-
-  run_filter(underdB,x,input_size,lookahead,mode,
-	     iir,attack,decay,ps);
-  
-  if(adj){
-    float ratio_multiplier=1000./prevratio - 1.;
-    
-    if(zerocorner!=currcorner || prevratio!=currratio){
-      /* slew limit these attenuators */
-      float ratio_add= ((1000./currratio - 1.)-ratio_multiplier)/input_size;
-      float corner_add= (currcorner-zerocorner)/input_size;
-      
-      if(knee){
-	for(k=0;k<input_size;k++){
-	  adj[k]+=soft_knee(zerocorner-underdB[k])*ratio_multiplier;
-	  ratio_multiplier+=ratio_add;
-	  zerocorner+=corner_add;
-	}
-      }else{
-	for(k=0;k<input_size;k++){
-	  adj[k]+=hard_knee(zerocorner-underdB[k])*ratio_multiplier;
-	  ratio_multiplier+=ratio_add;
-	  zerocorner+=corner_add;
-	}
-      }
-
-    }else{
-      if(knee){
-	for(k=0;k<input_size;k++)
-	  adj[k]+=soft_knee(zerocorner-underdB[k])*ratio_multiplier;
-      }else{
-	for(k=0;k<input_size;k++)
-	  adj[k]+=hard_knee(zerocorner-underdB[k])*ratio_multiplier;
-      }
-    }
-  }
-}
-
 static int find_maxbands(subband_state *ss,int channel){
   int maxbands=ss->wC[channel]->freq_bands;
   if(maxbands<ss->w0[channel]->freq_bands)maxbands=ss->w0[channel]->freq_bands;
@@ -567,35 +356,39 @@
       memset(adj,0,sizeof(*adj)*input_size);
       
     if(u_active)
-      under_compand(x,  
-		    prevset->static_u[i],
-		    currset->static_u[i],
-		    &ms->under_attack[channel],
-		    &ms->under_decay[channel],
-		    &ms->under_iir[i][channel],
-		    &ms->under_peak[i][channel],
-		      c->under_lookahead/1000.,
-		    c->under_mode,
-		    c->under_softknee,
-		    prevset->under_ratio,
-		    currset->under_ratio,
-		    (i>=w->freq_bands?0:adj));
-    
-    if(o_active)	
-      over_compand(x,  
-		   prevset->static_o[i],
-		   currset->static_o[i],
-		   &ms->over_attack[channel],
-		   &ms->over_decay[channel],
-		   &ms->over_iir[i][channel],
-		   &ms->over_peak[i][channel],
-		   c->over_lookahead/1000.,
-		   c->over_mode,
-		   c->over_softknee,
-		   prevset->over_ratio,
-		   currset->over_ratio,
-		   (i>=w->freq_bands?0:adj));
+      bi_compand(x,0,(i>=w->freq_bands?0:adj),
+		 //prevset->static_u[i],
+		 currset->static_u[i],
+		 1.f-1000.f/prevset->under_ratio,
+		 1.f-1000.f/currset->under_ratio,
+		 c->under_lookahead/1000.f,
+		 c->under_mode,
+		 c->under_softknee,
+		 &ms->under_attack[channel],
+		 &ms->under_decay[channel],
+		 &ms->under_iir[i][channel],
+		 &ms->under_peak[i][channel],
+		 ss->effect_active1[channel] && 
+		 (i<w->freq_bands),
+		 0);
 
+    if(o_active)
+      bi_compand(x,0,(i>=w->freq_bands?0:adj),
+		 //prevset->static_o[i],
+		 currset->static_o[i],
+		 1.f-1000.f/prevset->over_ratio,
+		 1.f-1000.f/currset->over_ratio,
+		 c->over_lookahead/1000.f,
+		 c->over_mode,
+		 c->over_softknee,
+		 &ms->over_attack[channel],
+		 &ms->over_decay[channel],
+		 &ms->over_iir[i][channel],
+		 &ms->over_peak[i][channel],
+		 ss->effect_active1[channel] && 
+		 (i<w->freq_bands),
+		 1);
+
     if(ss->visible1[channel]){
       feedback_p=1;
       
@@ -613,7 +406,7 @@
 	  }
 	  rms+=val;
 	}
-	if(active){
+	if(u_active || o_active || b_active){
 	  peakfeed[i][channel]=todB(max)*.5+adj[maxpos];
 	  rmsfeed[i][channel]=todB(rms/input_size)*.5+adj[maxpos];
 	}else{
@@ -624,15 +417,16 @@
     }
     
     if(b_active)
-      base_compand(x,  
+      full_compand(x,0,(i>=w->freq_bands?0:adj),
+		   1.f-1000.f/prevset->base_ratio,
+		   1.f-1000.f/currset->base_ratio,
+		   c->base_mode,
 		   &ms->base_attack[channel],
 		   &ms->base_decay[channel],
 		   &ms->base_iir[i][channel],
 		   &ms->base_peak[i][channel],
-		   c->base_mode,
-		   prevset->base_ratio,
-		   currset->base_ratio,
-		   (i>=w->freq_bands?0:adj));
+		   ss->effect_active1[channel] &&
+		   i<w->freq_bands);
 
     if(u_active || o_active || b_active){
       if(ss->effect_active1[channel]){

Modified: trunk/postfish/outpanel.c
===================================================================
--- trunk/postfish/outpanel.c	2004-10-16 18:05:24 UTC (rev 8032)
+++ trunk/postfish/outpanel.c	2004-10-16 20:57:39 UTC (rev 8033)
@@ -81,7 +81,8 @@
   config_get_sigat("output_monitor_set",bank,0,0,0,0,&outset.monitor.device);
 
   /* don't set a device that doesn't exist */
-  if(state.monitor.device && outset.monitor.device<monitor_entries)
+  if(outset.monitor.device>=monitor_entries)outset.monitor.device=monitor_entries-1;
+  if(state.monitor.device)
     gtk_combo_box_set_active(GTK_COMBO_BOX(state.monitor.device),outset.monitor.device);
 
   config_get_sigat("output_monitor_set",bank,0,0,0,1,&outset.monitor.bytes);

Modified: trunk/postfish/postfish.h
===================================================================
--- trunk/postfish/postfish.h	2004-10-16 18:05:24 UTC (rev 8032)
+++ trunk/postfish/postfish.h	2004-10-16 20:57:39 UTC (rev 8033)
@@ -85,10 +85,15 @@
 
 #ifdef UGLY_IEEE754_FLOAT32_HACK
 
-static inline float todB_a(const float *x){
-  return (float)((*(int32_t *)x)&0x7fffffff) * 7.17711438e-7f -764.6161886f;
+static inline float todB_a(float x){
+  return (float)((*((int32_t *)&x))&0x7fffffff) * 7.17711438e-7f -764.6161886f;
 }
 
+// eliminate a *.5 in ops on sq magnitudes
+static inline float todB_a2(float x){
+  return (float)((*((int32_t *)&x))&0x7fffffff) * 3.58855719e-7f -382.3080943f;
+}
+
 static inline float fromdB_a(float x){
   int y=(x < -300 ? 0 : 1.39331762961e+06f*(x+764.6161886f));
   return *(float *)&y;

Modified: trunk/postfish/singlecomp.c
===================================================================
--- trunk/postfish/singlecomp.c	2004-10-16 18:05:24 UTC (rev 8032)
+++ trunk/postfish/singlecomp.c	2004-10-16 20:57:39 UTC (rev 8033)
@@ -24,7 +24,7 @@
 #include "postfish.h"
 #include "feedback.h"
 #include "window.h"
-#include "bessel.h"
+#include "follower.h"
 #include "singlecomp.h"
 
 extern int input_size;
@@ -32,11 +32,6 @@
 extern int input_ch;
 
 typedef struct {
-  int loc;
-  float val;
-} peak_state;
-
-typedef struct {
   sig_atomic_t u_thresh;
   sig_atomic_t u_ratio;
 
@@ -191,12 +186,19 @@
   memset(scs->o_peak+i,0,sizeof(*scs->o_peak));
   memset(scs->u_peak+i,0,sizeof(*scs->u_peak));
   memset(scs->b_peak+i,0,sizeof(*scs->b_peak));
+
+  /* all filters are set to 0, even the ones that steady-state at one,
+     because we know that our steepest attack will complete in the
+     pre-charge time, but there's no such guarantee about decay */
   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));
-  scs->o_delay[i]=1;
-  scs->u_delay[i]=1;
-  scs->b_delay[i]=1;
+
+  /* delays are only used for soft-starting individual filters when we
+     know things began at unity multiplier */
+  scs->o_delay[i]=0;
+  scs->u_delay[i]=0;
+  scs->b_delay[i]=0;
 }
 
 static void reset_filter(singlecomp_state *scs){
@@ -218,241 +220,6 @@
   return 0;
 }
 
-static void prepare_peak(float *peak, float *x, int n, int ahead,
-                         peak_state *ps){
-  int ii,jj;
-  int loc=ps->loc;
-  float val=ps->val;
-
-  /* Although we have two input_size blocks of zeroes after a
-     reset, we may still need to look ahead explicitly after a
-     reset if the lookahead is exceptionally long */
-
-  if(loc==0 && val==0){
-    for(ii=0;ii<ahead;ii++) 
-      if((x[ii]*x[ii])>val){
-        val=(x[ii]*x[ii]);
-        loc=ii;
-      }
-  }
-  
-  if(val>peak[0])peak[0]=val;
-
-  for(ii=1;ii<n;ii++){
-    if((x[ii+ahead]*x[ii+ahead])>val){
-      val=(x[ii+ahead]*x[ii+ahead]);
-      loc=ii+ahead;
-    }     
-    if(ii>=loc){
-      /* backfill */
-      val=0;
-      for(jj=ii+ahead-1;jj>=ii;jj--){
-        if((x[jj]*x[jj])>val)val=(x[jj]*x[jj]);
-        if(jj<n && val>peak[jj])peak[jj]=val;
-      }
-      val=(x[ii+ahead]*x[ii+ahead]);
-      loc=ii+ahead;
-    }
-    if(val>peak[ii])peak[ii]=val; 
-  }
-
-  ps->loc=loc-input_size;
-  ps->val=val;
-}
-
-#if 0
-static void _analysis(char *base,int seq, float *data, int n,int dB, 
-		      off_t offset){
-
-  FILE *f;
-  char buf[80];
-  sprintf(buf,"%s_%d.m",base,seq);
-
-  f=fopen(buf,"a");
-  if(f){
-    int i;
-    for(i=0;i<n;i++)
-      if(dB)
-	fprintf(f,"%d %f\n",(int)(i+offset),todB(data[i]));
-      else
-	fprintf(f,"%d %f\n",(int)(i+offset),(data[i]));
-
-  }
-  fclose(f);
-}
-
-static int seq=0;
-static int offch;
-#endif
-
-static void run_filter(float *cache, float *in, float *work,
-                       int ahead,int mode,
-                       iir_state *iir,
-		       iir_filter *attack,
-		       iir_filter *decay,
-                       peak_state *ps){
-  int k;
-
-  if(mode){
-    /* peak mode */
-    float bigcache[input_size*2];
-    memcpy(bigcache,cache,sizeof(*work)*input_size);
-    memcpy(bigcache+input_size,in,sizeof(*work)*input_size);
-    
-    memset(work,0,sizeof(*work)*input_size);
-    prepare_peak(work, bigcache, input_size, ahead, ps);
-    
-    compute_iir_freefall1_then_symmetric2(work, input_size, iir, attack, decay);
-    
-  }else{
-    /* rms mode */
-    float *cachea=cache+ahead;
-    float *worka=work+input_size-ahead;
-    
-    for(k=0;k<input_size-ahead;k++)
-      work[k]=cachea[k]*cachea[k];
-    
-    for(k=0;k<ahead;k++)
-      worka[k]=in[k]*in[k];    
-
-    compute_iir_symmetric_limited(work, input_size, iir, attack, decay);
-    
-  }
-
-  for(k=0;k<input_size;k++)
-    work[k]=todB_a(work+k)*.5f;
-}
-
-static float soft_knee(float x){
-  return (sqrtf(x*x+30.f)+x)*-.5f;
-}
-
-static float hard_knee(float x){
-  return (x>0.f?-x:0.f);
-}
-
-static void over_compand(float *A,float *B,float *adj,
-			 float zerocorner,
-			 float currcorner,
-			 float multiplier,
-			 float currmultiplier,
-			 float lookahead,int mode,int softknee,
-                         iir_filter *attack, iir_filter *decay,
-                         iir_state *iir, peak_state *ps,
-			 int active){
-  
-  int k;
-  float work[input_size*2];
-  int ahead=(mode?step_ahead(attack->alpha):impulse_ahead2(attack->alpha))*lookahead;
-  if(ahead>input_size)ahead=input_size;
-
-  run_filter(A,B,work,ahead,mode,iir,attack,decay,ps);
-  
-  if(active){
-    if(multiplier!=currmultiplier || zerocorner!=currcorner){
-      float multiplier_add=(currmultiplier-multiplier)/input_size;
-      float zerocorner_add=(currcorner-zerocorner)/input_size;
-
-      if(softknee){
-	for(k=0;k<input_size;k++){
-	  adj[k]+=soft_knee(work[k]-zerocorner)*multiplier;
-	  multiplier+=multiplier_add;
-	  zerocorner+=zerocorner_add;
-	}
-      }else{
-	for(k=0;k<input_size;k++){
-	  adj[k]+=hard_knee(work[k]-zerocorner)*multiplier;
-	  multiplier+=multiplier_add;
-	  zerocorner+=zerocorner_add;
-	}
-      }
-
-    }else{
-      if(softknee){
-	for(k=0;k<input_size;k++)
-	  adj[k]+=soft_knee(work[k]-zerocorner)*multiplier;
-      }else{
-	for(k=0;k<input_size;k++)
-	  adj[k]+=hard_knee(work[k]-zerocorner)*multiplier;
-      }
-    }
-  }
-}
-
-static void under_compand(float *A,float *B,float *adj,
-			  float zerocorner,float currcorner,
-			  float multiplier,float currmultiplier,
-			  float lookahead,int mode,int softknee,
-			  iir_filter *attack, iir_filter *decay,
-			  iir_state *iir, peak_state *ps,
-			  int active){
-  int k;
-  float work[input_size*2];
-  int ahead=(mode?step_ahead(attack->alpha):impulse_ahead2(attack->alpha))*lookahead;
-  if(ahead>input_size)ahead=input_size;
-  
-  run_filter(A,B,work,ahead,mode,iir,attack,decay,ps);
-
-  if(active){
-    if(multiplier!=currmultiplier || zerocorner!=currcorner){
-      float multiplier_add=(currmultiplier-multiplier)/input_size;
-      float zerocorner_add=(currcorner-zerocorner)/input_size;
-
-      if(softknee){
-	for(k=0;k<input_size;k++){
-	  adj[k]+= -soft_knee(zerocorner-work[k])*multiplier;
-	  multiplier+=multiplier_add;
-	  zerocorner+=zerocorner_add;
-	}
-      }else{
-	for(k=0;k<input_size;k++){
-	  adj[k]+= -hard_knee(zerocorner-work[k])*multiplier;
-	  multiplier+=multiplier_add;
-	  zerocorner+=zerocorner_add;
-	}
-      }
-
-    }else{
-      if(softknee){
-	for(k=0;k<input_size;k++)
-	  adj[k]+= -soft_knee(zerocorner-work[k])*multiplier;
-      }else{
-	for(k=0;k<input_size;k++)
-	  adj[k]+= -hard_knee(zerocorner-work[k])*multiplier;
-      }
-    }
-  }
-  
-}
-
-static void base_compand(float *A,float *B,float *adj,
-			 float multiplier,float currmultiplier,
-			 int mode,
-			 iir_filter *attack, iir_filter *decay,
-			 iir_state *iir, peak_state *ps,
-			 int active){
-  
-  int k;
-  float work[input_size*2];
-  int ahead=(mode?step_ahead(attack->alpha):impulse_ahead2(attack->alpha));
-
-  run_filter(A,B,work,ahead,mode,iir,attack,decay,ps);
-
-  if(active){
-    if(multiplier!=currmultiplier){
-      float multiplier_add=(currmultiplier-multiplier)/input_size;
-      
-      for(k=0;k<input_size;k++){
-	adj[k]-=(work[k]+adj[k])*multiplier;
-	multiplier+=multiplier_add;
-      }
-    }else{ 
-      for(k=0;k<input_size;k++)
-	adj[k]-=(work[k]+adj[k])*multiplier;
-    }
-  }
-}
-
 static void work_and_lapping(singlecomp_state *scs,
 			     singlecomp_settings **scset,
 			     time_linkage *in,
@@ -497,7 +264,9 @@
     
     if(!active0 && !activeC){
       
-      if(activeP) reset_onech_filter(scs,i); /* just became inactive; reset all filters for this channel */
+      if(activeP) reset_onech_filter(scs,i); /* just became inactive;
+                                                reset all filters for
+                                                this channel */
       
       /* feedback */
       if(scset[i]->panel_visible){
@@ -514,9 +283,9 @@
 	    if(peak<val)peak=val;
 	  }
 	}
-	peakfeed[i]=todB_a(&peak)*.5;
+	peakfeed[i]=todB_a(peak)*.5;
 	rms/=input_size;
-	rmsfeed[i]=todB_a(&rms)*.5;
+	rmsfeed[i]=todB_a(rms)*.5;
       }
 
       /* rotate data vectors */
@@ -539,13 +308,12 @@
       currset->b_ratio=scset[i]->b_ratio;
       
       /* don't slew from an unknown value */
-
       if(!activeP || !scs->fillstate) 
 	memcpy(prevset,currset,sizeof(*currset));
-
+      
       /* don't run filters that will be applied at unity */
       if(prevset->u_ratio==1000 && currset->u_ratio==1000){
-	scs->u_delay[i]=2;
+	scs->u_delay[i]=1;
 	memset(scs->u_peak+i,0,sizeof(peak_state));
 	memset(scs->u_iir+i,0,sizeof(iir_state));
       }else{
@@ -555,7 +323,7 @@
       }
 
       if(prevset->o_ratio==1000 && currset->o_ratio==1000){
-	scs->o_delay[i]=2;
+	scs->o_delay[i]=1;
 	memset(scs->o_peak+i,0,sizeof(peak_state));
 	memset(scs->o_iir+i,0,sizeof(iir_state));
       }else{
@@ -565,7 +333,7 @@
       }
 
       if(prevset->b_ratio==1000 && currset->b_ratio==1000){
-	scs->b_delay[i]=2;
+	scs->b_delay[i]=1;
 	memset(scs->b_peak+i,0,sizeof(peak_state));
 	memset(scs->b_iir+i,0,sizeof(iir_state));
       }else{
@@ -573,36 +341,37 @@
 	if(scs->b_delay[i]<0)scs->b_delay[i]=0;
 	b_active=1;
       }
-      
+
       /* run the filters */
       memset(adj,0,sizeof(*adj)*input_size);
 
       if(u_active)
-	under_compand(scs->cache[i],in->data[i],adj,
-		      scs->prevset[i].u_thresh,
-		      scs->currset[i].u_thresh,
-		      1.-1000./scs->prevset[i].u_ratio,
-		      1.-1000./scs->currset[i].u_ratio,
-		      scset[i]->u_lookahead/1000.,
-		      scset[i]->u_mode,
-		      scset[i]->u_softknee,
-		      scs->u_attack+i,scs->u_decay+i,
-		      scs->u_iir+i,scs->u_peak+i,
-		      active0);
+	bi_compand(scs->cache[i],in->data[i],adj,
+		   //scs->prevset[i].u_thresh,
+		   scs->currset[i].u_thresh,
+		   1.f-1000./scs->prevset[i].u_ratio,
+		   1.f-1000./scs->currset[i].u_ratio,
+		   scset[i]->u_lookahead/1000.f,
+		   scset[i]->u_mode,
+		   scset[i]->u_softknee,
+		   scs->u_attack+i,scs->u_decay+i,
+		   scs->u_iir+i,scs->u_peak+i,
+		   active0,0);
       
       if(o_active)
-	over_compand(scs->cache[i],in->data[i],adj,
-		     scs->prevset[i].o_thresh,
-		     scs->currset[i].o_thresh,
-		     1.-1000./scs->prevset[i].o_ratio,
-		     1.-1000./scs->currset[i].o_ratio,
-		     scset[i]->o_lookahead/1000.,
-		     scset[i]->o_mode,
-		     scset[i]->o_softknee,
-		     scs->o_attack+i,scs->o_decay+i,
-		     scs->o_iir+i,scs->o_peak+i,
-		     active0);
+	bi_compand(scs->cache[i],in->data[i],adj,
+		   //scs->prevset[i].o_thresh,
+		   scs->currset[i].o_thresh,
+		   1.f-1000.f/scs->prevset[i].o_ratio,
+		   1.f-1000.f/scs->currset[i].o_ratio,
+		   scset[i]->o_lookahead/1000.f,
+		   scset[i]->o_mode,
+		   scset[i]->o_softknee,
+		   scs->o_attack+i,scs->o_decay+i,
+		   scs->o_iir+i,scs->o_peak+i,
+		   active0,1);
       
+
       /* feedback before base */
       if(scset[i]->panel_visible){
 	int k;
@@ -622,16 +391,16 @@
 	    
 	  }
 	}
-	peakfeed[i]=todB_a(&peak)*.5;
+	peakfeed[i]=todB_a(peak)*.5;
 	rms/=input_size;
-	rmsfeed[i]=todB_a(&rms)*.5;
+	rmsfeed[i]=todB_a(rms)*.5;
       }
 
       if(b_active)
-	base_compand(scs->cache[i],in->data[i],adj,
+	full_compand(scs->cache[i],in->data[i],adj,
 		     1.-1000./scs->prevset[i].b_ratio,
 		     1.-1000./scs->currset[i].b_ratio,
-		   scset[i]->b_mode,
+		     scset[i]->b_mode,
 		     scs->b_attack+i,scs->b_decay+i,
 		     scs->b_iir+i,scs->b_peak+i,
 		     active0);
@@ -785,6 +554,6 @@
   /* local copy required to avoid concurrency problems */
   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/version.h
===================================================================
--- trunk/postfish/version.h	2004-10-16 18:05:24 UTC (rev 8032)
+++ trunk/postfish/version.h	2004-10-16 20:57:39 UTC (rev 8033)
@@ -1,2 +1,2 @@
 #define VERSION "$Id$ "
-/* DO NOT EDIT: Automated versioning hack [Mon Oct 11 22:10:04 EDT 2004] */
+/* DO NOT EDIT: Automated versioning hack [Sat Oct 16 17:09:50 EDT 2004] */



More information about the commits mailing list