[xiph-cvs] r6573 - trunk/postfish

xiphmont at xiph.org xiphmont at xiph.org
Tue May 4 21:25:28 PDT 2004



Author: xiphmont
Date: 2004-04-22 05:31:18 -0400 (Thu, 22 Apr 2004)
New Revision: 6573

Modified:
   trunk/postfish/compandpanel.c
   trunk/postfish/freq.c
   trunk/postfish/multicompand.c
   trunk/postfish/multicompand.h
   trunk/postfish/singlecomp.c
   trunk/postfish/subband.c
   trunk/postfish/subband.h
   trunk/postfish/suppress.c
   trunk/postfish/version.h
Log:
Major signal path upgrade to subband.c:
  eliminate all clicks/thumps/dropouts on realtime interaction
  implement mute infrastructure
  active/visible by channel

<p><p>Modified: trunk/postfish/compandpanel.c
===================================================================
--- trunk/postfish/compandpanel.c	2004-04-22 07:37:57 UTC (rev 6572)
+++ trunk/postfish/compandpanel.c	2004-04-22 09:31:18 UTC (rev 6573)
@@ -226,6 +226,7 @@
   cbar *b=(cbar *)in;
   int o,u;
   int i;
+  int adj;
 
   u=multibar_get_value(MULTIBAR(b->slider),0);
   sprintf(buffer,"%+4ddB",u);
@@ -246,101 +247,98 @@
         bc[2].static_o[0]+=o-bc[2].static_o[1];
         bc[2].static_u[0]+=u-bc[2].static_u[1];
       }
-      if (b->number<9){
-	int adj;
-
-	/* convolutions for roundoff behavior */
-	if(b->number>0){
-	  adj=(bc[1].static_o[b->number*2-1]*2 -
-	       bc[1].static_o[b->number*2-2]-bc[1].static_o[b->number*2])/2;
-	  bc[1].static_o[b->number*2-1]=
+      
+      /* convolutions for roundoff behavior */
+      if(b->number>0){
+	adj=(bc[1].static_o[b->number*2-1]*2 -
+	     bc[1].static_o[b->number*2-2]-bc[1].static_o[b->number*2])/2;
+	bc[1].static_o[b->number*2-1]=
             (bc[1].static_o[b->number*2-2]+o)/2+adj;
-
-	  adj=(bc[1].static_u[b->number*2-1]*2 -
-	       bc[1].static_u[b->number*2-2]-bc[1].static_u[b->number*2])/2;
-	  bc[1].static_u[b->number*2-1]=
-	    (bc[1].static_u[b->number*2-2]+u)/2+adj;
-
-	  adj=(bc[2].static_o[b->number*3-1]*3 -
-	       bc[2].static_o[b->number*3-2] - 
-	       bc[2].static_o[b->number*3-2] - 
-	       bc[2].static_o[b->number*3+1])/3;
-	  bc[2].static_o[b->number*3-1]=
-	    (bc[2].static_o[b->number*3-2]+
-	     bc[2].static_o[b->number*3-2]+
-	     o)/3+adj;
-
-	  adj=(bc[2].static_o[b->number*3]*3 -
-	       bc[2].static_o[b->number*3-2] - 
-	       bc[2].static_o[b->number*3+1] - 
-	       bc[2].static_o[b->number*3+1])/3;
-	  bc[2].static_o[b->number*3]=
-	    (bc[2].static_o[b->number*3-2]+o+o)/3+adj;
-
-	  adj=(bc[2].static_u[b->number*3-1]*3 -
-	       bc[2].static_u[b->number*3-2] - 
-	       bc[2].static_u[b->number*3-2] - 
-	       bc[2].static_u[b->number*3+1])/3;
-	  bc[2].static_u[b->number*3-1]=
-	    (bc[2].static_u[b->number*3-2]+
-	     bc[2].static_u[b->number*3-2]+
-	     u)/3+adj;
-
-	  adj=(bc[2].static_u[b->number*3]*3 -
-	       bc[2].static_u[b->number*3-2] - 
-	       bc[2].static_u[b->number*3+1] - 
-	       bc[2].static_u[b->number*3+1])/3;
-	  bc[2].static_u[b->number*3]=
-	    (bc[2].static_u[b->number*3-2]+u+u)/3+adj;
-
-	}
-
-	if(b->number<9){
-	  adj=(bc[1].static_o[b->number*2+1]*2-
-	       bc[1].static_o[b->number*2+2]-bc[1].static_o[b->number*2])/2;
-	  bc[1].static_o[b->number*2+1]=
-	    (bc[1].static_o[b->number*2+2]+o)/2+adj;
-	  
-	  adj=(bc[1].static_u[b->number*2+1]*2-
-	       bc[1].static_u[b->number*2+2]-bc[1].static_u[b->number*2])/2;
-	  bc[1].static_u[b->number*2+1]=
-	    (bc[1].static_u[b->number*2+2]+u)/2+adj;
-
-	  adj=(bc[2].static_o[b->number*3+3]*3 -
-	       bc[2].static_o[b->number*3+4] - 
-	       bc[2].static_o[b->number*3+4] - 
-	       bc[2].static_o[b->number*3+1])/3;
-	  bc[2].static_o[b->number*3+3]=
-	    (bc[2].static_o[b->number*3+4]+
-	     bc[2].static_o[b->number*3+4]+
-	     o)/3+adj;
-
-	  adj=(bc[2].static_o[b->number*3+2]*3 -
-	       bc[2].static_o[b->number*3+4] - 
-	       bc[2].static_o[b->number*3+1] - 
-	       bc[2].static_o[b->number*3+1])/3;
-	  bc[2].static_o[b->number*3+2]=
-	    (bc[2].static_o[b->number*3+4]+o+o)/3+adj;
-
-	  adj=(bc[2].static_u[b->number*3+3]*3 -
-	       bc[2].static_u[b->number*3+4] - 
-	       bc[2].static_u[b->number*3+4] - 
-	       bc[2].static_u[b->number*3+1])/3;
-	  bc[2].static_u[b->number*3+3]=
-	    (bc[2].static_u[b->number*3+4]+
-	     bc[2].static_u[b->number*3+4]+
-	     u)/3+adj;
-
-	  adj=(bc[2].static_u[b->number*3+2]*3 -
-	       bc[2].static_u[b->number*3+4] - 
-	       bc[2].static_u[b->number*3+1] - 
-	       bc[2].static_u[b->number*3+1])/3;
-	  bc[2].static_u[b->number*3+2]=
-	    (bc[2].static_u[b->number*3+4]+u+u)/3+adj;
-
-	}
+	
+	adj=(bc[1].static_u[b->number*2-1]*2 -
+	     bc[1].static_u[b->number*2-2]-bc[1].static_u[b->number*2])/2;
+	bc[1].static_u[b->number*2-1]=
+	  (bc[1].static_u[b->number*2-2]+u)/2+adj;
+	
+	adj=(bc[2].static_o[b->number*3-1]*3 -
+	     bc[2].static_o[b->number*3-2] - 
+	     bc[2].static_o[b->number*3-2] - 
+	     bc[2].static_o[b->number*3+1])/3;
+	bc[2].static_o[b->number*3-1]=
+	  (bc[2].static_o[b->number*3-2]+
+	   bc[2].static_o[b->number*3-2]+
+	   o)/3+adj;
+	
+	adj=(bc[2].static_o[b->number*3]*3 -
+	     bc[2].static_o[b->number*3-2] - 
+	     bc[2].static_o[b->number*3+1] - 
+	     bc[2].static_o[b->number*3+1])/3;
+	bc[2].static_o[b->number*3]=
+	  (bc[2].static_o[b->number*3-2]+o+o)/3+adj;
+	
+	adj=(bc[2].static_u[b->number*3-1]*3 -
+	     bc[2].static_u[b->number*3-2] - 
+	     bc[2].static_u[b->number*3-2] - 
+	     bc[2].static_u[b->number*3+1])/3;
+	bc[2].static_u[b->number*3-1]=
+	  (bc[2].static_u[b->number*3-2]+
+	   bc[2].static_u[b->number*3-2]+
+	   u)/3+adj;
+	
+	adj=(bc[2].static_u[b->number*3]*3 -
+	     bc[2].static_u[b->number*3-2] - 
+	     bc[2].static_u[b->number*3+1] - 
+	     bc[2].static_u[b->number*3+1])/3;
+	bc[2].static_u[b->number*3]=
+	  (bc[2].static_u[b->number*3-2]+u+u)/3+adj;
+	
       }
-
+      
+      if(b->number<9){
+	adj=(bc[1].static_o[b->number*2+1]*2-
+	     bc[1].static_o[b->number*2+2]-bc[1].static_o[b->number*2])/2;
+	bc[1].static_o[b->number*2+1]=
+	  (bc[1].static_o[b->number*2+2]+o)/2+adj;
+	
+	adj=(bc[1].static_u[b->number*2+1]*2-
+	     bc[1].static_u[b->number*2+2]-bc[1].static_u[b->number*2])/2;
+	bc[1].static_u[b->number*2+1]=
+	  (bc[1].static_u[b->number*2+2]+u)/2+adj;
+	
+	adj=(bc[2].static_o[b->number*3+3]*3 -
+	     bc[2].static_o[b->number*3+4] - 
+	     bc[2].static_o[b->number*3+4] - 
+	     bc[2].static_o[b->number*3+1])/3;
+	bc[2].static_o[b->number*3+3]=
+	  (bc[2].static_o[b->number*3+4]+
+	   bc[2].static_o[b->number*3+4]+
+	   o)/3+adj;
+	
+	adj=(bc[2].static_o[b->number*3+2]*3 -
+	     bc[2].static_o[b->number*3+4] - 
+	     bc[2].static_o[b->number*3+1] - 
+	     bc[2].static_o[b->number*3+1])/3;
+	bc[2].static_o[b->number*3+2]=
+	  (bc[2].static_o[b->number*3+4]+o+o)/3+adj;
+	
+	adj=(bc[2].static_u[b->number*3+3]*3 -
+	     bc[2].static_u[b->number*3+4] - 
+	     bc[2].static_u[b->number*3+4] - 
+	     bc[2].static_u[b->number*3+1])/3;
+	bc[2].static_u[b->number*3+3]=
+	  (bc[2].static_u[b->number*3+4]+
+	   bc[2].static_u[b->number*3+4]+
+	   u)/3+adj;
+	
+	adj=(bc[2].static_u[b->number*3+2]*3 -
+	     bc[2].static_u[b->number*3+4] - 
+	     bc[2].static_u[b->number*3+1] - 
+	     bc[2].static_u[b->number*3+1])/3;
+	bc[2].static_u[b->number*3+2]=
+	  (bc[2].static_u[b->number*3+4]+u+u)/3+adj;
+	
+      }
+      
       if(b->number==9){
         bc[1].static_o[19]+=o-bc[1].static_o[18];
         bc[1].static_u[19]+=u-bc[1].static_u[18];
@@ -461,7 +459,8 @@
           gtk_widget_hide(bars[i].readoutu);
         }
       }
-      multicompand_set_bank(bank_active);
+
+      c.active_bank=bank_active;
       
     }
   }

Modified: trunk/postfish/freq.c
===================================================================
--- trunk/postfish/freq.c	2004-04-22 07:37:57 UTC (rev 6572)
+++ trunk/postfish/freq.c	2004-04-22 09:31:18 UTC (rev 6573)
@@ -476,6 +476,7 @@
     break;
   case 3: /* we've pushed out EOF already */
     f->out.samples=0;
+    return &f->out;
   }
   
   /* finish up the state feedabck */

Modified: trunk/postfish/multicompand.c
===================================================================
--- trunk/postfish/multicompand.c	2004-04-22 07:37:57 UTC (rev 6572)
+++ trunk/postfish/multicompand.c	2004-04-22 09:31:18 UTC (rev 6573)
@@ -32,23 +32,33 @@
 extern int input_rate;
 extern int input_ch;
 
+/* feedback! */
+typedef struct multicompand_feedback{
+  feedback_generic parent_class;
+  float **peak;
+  float **rms;
+  int freq_bands;
+  int bypass;
+} multicompand_feedback;
+
 typedef struct {
   int loc;
   float val;
 } peak_state;
 
 typedef struct {
+  feedback_generic_pool feedpool;
   subband_state ss;
   subband_window sw[multicomp_banks];
   
-  iir_filter over_attack[multicomp_banks][multicomp_freqs_max];
-  iir_filter over_decay[multicomp_banks][multicomp_freqs_max];
+  iir_filter over_attack;
+  iir_filter over_decay;
 
-  iir_filter under_attack[multicomp_banks][multicomp_freqs_max];
-  iir_filter under_decay[multicomp_banks][multicomp_freqs_max];
+  iir_filter under_attack;
+  iir_filter under_decay;
 
-  iir_filter base_attack[multicomp_banks][multicomp_freqs_max];
-  iir_filter base_decay[multicomp_banks][multicomp_freqs_max];
+  iir_filter base_attack;
+  iir_filter base_decay;
 
   iir_state *over_iir[multicomp_freqs_max];
   iir_state *under_iir[multicomp_freqs_max];
@@ -58,9 +68,8 @@
   peak_state *under_peak[multicomp_freqs_max];
   peak_state *base_peak[multicomp_freqs_max];
   
-  sig_atomic_t pending_bank;
-  sig_atomic_t active_bank;
-
+  float **peak;
+  float **rms;
 } multicompand_state;
 
 sig_atomic_t compand_visible;
@@ -71,26 +80,66 @@
 
 static multicompand_state ms;
 
-int pull_multicompand_feedback(float **peak,float **rms,int *bands){
-  return pull_subband_feedback(&ms.ss,peak,rms,bands);
+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;
 }
 
-void multicompand_reset(){
-  int i,j;
+/* total, peak, rms are pulled in array[freqs][input_ch] order */
+
+int pull_multicompand_feedback(float **peak,float **rms,int *b){
+  multicompand_feedback *f=(multicompand_feedback *)feedback_pull(&ms.feedpool);
+  int i;
   
-  subband_reset(&ms.ss);
+  if(!f)return 0;
   
+  if(f->bypass){
+    feedback_old(&ms.feedpool,(feedback_generic *)f);
+    return 2;
+  }else{
+    if(peak)
+      for(i=0;i<f->freq_bands;i++)
+	memcpy(peak[i],f->peak[i],sizeof(**peak)*input_ch);
+    if(rms)
+      for(i=0;i<f->freq_bands;i++)
+	memcpy(rms[i],f->rms[i],sizeof(**rms)*input_ch);
+    if(b)*b=f->freq_bands;
+    feedback_old(&ms.feedpool,(feedback_generic *)f);
+    return 1;
+  }
+}
+
+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++){
-      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));
-      memset(&ms.over_iir[i][j],0,sizeof(iir_state));
-      memset(&ms.under_iir[i][j],0,sizeof(iir_state));
-      memset(&ms.base_iir[i][j],0,sizeof(iir_state));
+      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));
+      memset(&ms->over_iir[i][j],0,sizeof(iir_state));
+      memset(&ms->under_iir[i][j],0,sizeof(iir_state));
+      memset(&ms->base_iir[i][j],0,sizeof(iir_state));
     }
 }
 
+void multicompand_reset(){
+  
+  subband_reset(&ms.ss);
+  while(pull_multicompand_feedback(NULL,NULL,NULL));
+  reset_filters(&ms);
+
+}
+
 int multicompand_load(void){
   int h,i;
   int qblocksize=input_size/8;
@@ -111,14 +160,17 @@
     ms.base_iir[i]=calloc(input_ch,sizeof(iir_state));
   }
 
-  ms.active_bank=0;
-
+  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));
+  
   return 0;
 }
 
-static void multicompand_filter_set(float msec,
-				   iir_filter *filter,
-				   int attackp){
+static int multicompand_filter_set(float msec,
+				    iir_filter *filter,
+				    int attackp){
   float alpha;
   float corner_freq= 500./msec;
 
@@ -131,47 +183,32 @@
   filter->g=mkbessel(alpha,2,filter->c);
   filter->alpha=alpha;
   filter->Hz=alpha*input_rate;
-}
 
-
-static int multicompand_filterbank_set(float msec,
-				       iir_filter 
-				       filterbank[multicomp_banks]
-				       [multicomp_freqs_max],
-				       int attackp){
-  int i,j;
-  for(j=0;j<multicomp_banks;j++){
-    int bands=multicomp_freqs[j];
-    iir_filter *filters=filterbank[j];
-    
-    for(i=0;i<bands;i++)
-      multicompand_filter_set(msec,filters+i,attackp);
-  }
   return 0;
 }
 
 int multicompand_over_attack_set(float msec){
-  return multicompand_filterbank_set(msec,ms.over_attack,1);
+  return multicompand_filter_set(msec,&ms.over_attack,1);
 }
 
 int multicompand_over_decay_set(float msec){
-  return multicompand_filterbank_set(msec,ms.over_decay,0);  
+  return multicompand_filter_set(msec,&ms.over_decay,0);  
 }
 
 int multicompand_under_attack_set(float msec){
-  return multicompand_filterbank_set(msec,ms.under_attack,1);
+  return multicompand_filter_set(msec,&ms.under_attack,1);
 }
 
 int multicompand_under_decay_set(float msec){
-  return multicompand_filterbank_set(msec,ms.under_decay,0);
+  return multicompand_filter_set(msec,&ms.under_decay,0);
 }
 
 int multicompand_base_attack_set(float msec){
-  return multicompand_filterbank_set(msec,ms.base_attack,1);
+  return multicompand_filter_set(msec,&ms.base_attack,1);
 }
 
 int multicompand_base_decay_set(float msec){
-  return multicompand_filterbank_set(msec,ms.base_decay,0);
+  return multicompand_filter_set(msec,&ms.base_decay,0);
 }
 
 static void prepare_rms(float *rms, float *xx, int n, int ahead){
@@ -192,8 +229,8 @@
      reset if the lookahead is exceptionally long */
   if(loc==0 && val==0){
     for(ii=0;ii<ahead;ii++) 
-      if(fabs(x[ii])>val){
-	val=fabs(x[ii]);
+      if((x[ii]*x[ii])>val){
+	val=(x[ii]*x[ii]);
         loc=ii+hold;
       }
   }
@@ -201,18 +238,18 @@
   if(val>peak[0])peak[0]=val;
   
   for(ii=1;ii<n;ii++){
-    if(fabs(x[ii+ahead])>val){
-      val=fabs(x[ii+ahead]);
+    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(fabs(x[jj])>val)val=fabs(x[jj]);
+	if((x[jj]*x[jj])>val)val=(x[jj]*x[jj]);
         if(jj<n && val>peak[jj])peak[jj]=val;
       }
-      val=fabs(x[ii+ahead-1]);
+      val=(x[ii+ahead-1]*x[ii+ahead-1]);
       loc=ii+ahead+hold;
     }
     if(val>peak[ii])peak[ii]=val; 
@@ -223,25 +260,11 @@
   
 }
 
-static void run_filter_only(float *dB,int n,int mode,
-			    iir_state *iir,iir_filter *attack,iir_filter *decay){
-  int i;
-  compute_iir2(dB, n, iir, attack, decay);
-  
-  if(mode==0)
-    for(i=0;i<n;i++)
-      dB[i]=todB_a(dB+i)*.5f;
-  else
-    for(i=0;i<n;i++)
-      dB[i]=todB_a(dB+i);
-
-}
-
 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)
@@ -252,8 +275,11 @@
   else
     prepare_rms(dB, x, n, impulse_ahead2(attack->alpha)*lookahead);
 
+  compute_iir2(dB, n, iir, attack, decay);
   
-  run_filter_only(dB,n,mode,iir,attack,decay);
+  for(i=0;i<n;i++)
+    dB[i]=todB_a(dB+i)*.5f;
+
 }
 
 static float soft_knee(float x){
@@ -267,16 +293,16 @@
 static void over_compand(float *lx,float zerocorner,
                          iir_filter *attack, iir_filter *decay,
                          iir_state *iir, peak_state *ps,
-			 float *peakfeed, float *rmsfeed,float *adj,int active){
+			 float *adj){
   int k;
   float overdB[input_size];
   float lookahead=c.over_lookahead/1000.;
   int mode=c.over_mode;
-  float corner_multiplier=(1.-1./(c.over_ratio/1000.));
 
-  run_filter(overdB,lx,input_size,lookahead,mode,iir,attack, decay,ps);
+  run_filter(overdB,lx,input_size,lookahead,mode,iir,attack,decay,ps);
   
-  if(active){
+  if(adj){
+    float corner_multiplier=(1.-1./(c.over_ratio*.001));
     if(c.over_softknee){
       for(k=0;k<input_size;k++)
         adj[k]+=soft_knee(overdB[k]-zerocorner)*corner_multiplier;
@@ -285,126 +311,206 @@
         adj[k]+=hard_knee(overdB[k]-zerocorner)*corner_multiplier;
     }
   }
-  
-  {
-    /* determine rms and peak for feedback */
-    float max=-1.;
-    int maxpos=-1;
-    float rms=0.;
-    
-    for(k=0;k<input_size;k++){
-      float val=lx[k]*lx[k];
-      if(val>max){
-	max=val;
-	maxpos=k;
-      }
-      rms+=val;
-    }
-    *peakfeed=todB(max)*.5+adj[maxpos];
-    *rmsfeed=todB(rms/input_size)*.5+adj[maxpos];
-  }
 }
 
 static void base_compand(float *x,
                          iir_filter *attack, iir_filter *decay,
                          iir_state *iir, peak_state *ps,
-			 float *adj,int active){
+			 float *adj){
   int k;
   float basedB[input_size];
   int mode=c.base_mode;
-  float base_multiplier=(1.-1./(c.base_ratio/1000.));
 
   run_filter(basedB,x,input_size,1.,mode,
              iir,attack,decay,ps);
   
-  if(active)
+  if(adj){
+    float base_multiplier=(1.-1./(c.base_ratio*.001));
     for(k=0;k<input_size;k++)
       adj[k]-=(basedB[k]+adj[k])*base_multiplier;
-  
+  }
 }
 
 static void under_compand(float *x,float zerocorner,
                          iir_filter *attack, iir_filter *decay,
                          iir_state *iir, peak_state *ps,
-			 float *adj,int active){
+			 float *adj){
   int k;
   float underdB[input_size];
   float lookahead=c.under_lookahead/1000.;
   int mode=c.under_mode;
-  float corner_multiplier=(1.-1./(c.under_ratio/1000.));
 
   run_filter(underdB,x,input_size,lookahead,mode,
              iir,attack,decay,ps);
   
-  if(active){
+  if(adj){
+    float corner_multiplier=(1./(c.under_ratio*.001)-1.);
     if(c.under_softknee){
       for(k=0;k<input_size;k++)
-	adj[k]-=soft_knee(zerocorner-underdB[k])*corner_multiplier;
+	adj[k]=soft_knee(zerocorner-underdB[k])*corner_multiplier;
     }else{
       for(k=0;k<input_size;k++)
-	adj[k]-=hard_knee(zerocorner-underdB[k])*corner_multiplier;
+	adj[k]=hard_knee(zerocorner-underdB[k])*corner_multiplier;
     }
   }
 }
 
-static void multicompand_work(float **peakfeed,float **rmsfeed){
-  int i,j,k;
+static void multicompand_work(void *vs){
+
+  multicompand_state *ms=(multicompand_state *)vs;
+  subband_state *ss=&ms->ss;
+  int i,j,k,bypass_visible=1;
   float adj[input_size];
-  float *x;
-  int active=compand_active;
 
-  for(i=0;i<multicomp_freqs[ms.active_bank];i++){
+  float **peakfeed=ms->peak;
+  float **rmsfeed=ms->rms;
 
+  int bank;
+  subband_window *w=ss->w1;
+  subband_window *wP=ss->wP;
+  int maxbands=ss->wC->freq_bands;
+  if(maxbands<ss->w0->freq_bands)maxbands=ss->w0->freq_bands;
+  if(maxbands<ss->w1->freq_bands)maxbands=ss->w1->freq_bands;
+
+  if(w==&ms->sw[0]){
+    bank=0;
+  }else if(w==&ms->sw[1]){
+    bank=1;
+  }else bank=2;
+  
+  for(i=0;i<maxbands;i++){
     for(j=0;j<input_ch;j++){
-      memset(adj,0,sizeof(adj));
+      float *x=ss->lap[i][j];
+      int active=(ss->effect_active1[j] || 
+		  ss->effect_active0[j] || 
+		  ss->effect_activeC[j]);
 
-      if(active || compand_visible){
-	under_compand(ms.ss.lap[i][j],  
-		      bc[ms.active_bank].static_u[i],
-		      &ms.under_attack[ms.active_bank][i],
-		      &ms.under_decay[ms.active_bank][i],
-		      &ms.under_iir[i][j],
-		      &ms.under_peak[i][j],
-		      adj,active);
+      if(active){
+	/* one thing is worth a note here; 'maxbands' can be
+	   'overrange' for the current bank.  This is intentional; we
+	   may need to run the additional (allocated and valid)
+	   filters before or after their bands are active.  The only
+	   garbage data here is the xxxx_u, xxxx_o and xxxx_b
+	   settings.  There are allocated, but unset; if overrange,
+	   they're ignored in the compand worker */
+	under_compand(x,  
+		      bc[bank].static_u[i], 
+		      &ms->under_attack,
+		      &ms->under_decay,
+		      &ms->under_iir[i][j],
+		      &ms->under_peak[i][j],
+		      (i>=w->freq_bands?0:adj));
         
-	over_compand(ms.ss.lap[i][j],  
-		     bc[ms.active_bank].static_o[i],
-		     &ms.over_attack[ms.active_bank][i],
-		     &ms.over_decay[ms.active_bank][i],
-		     &ms.over_iir[i][j],
-		     &ms.over_peak[i][j],
-		     &peakfeed[i][j],
-		     &rmsfeed[i][j],
-		     adj,active);
-	
-	base_compand(ms.ss.lap[i][j],  
-		     &ms.base_attack[ms.active_bank][i],
-		     &ms.base_decay[ms.active_bank][i],
-		     &ms.base_iir[i][j],
-		     &ms.base_peak[i][j],
-		     adj,active);
+	over_compand(x,  
+		     bc[bank].static_o[i],
+		     &ms->over_attack,
+		     &ms->over_decay,
+		     &ms->over_iir[i][j],
+		     &ms->over_peak[i][j],
+		     (i>=w->freq_bands?0:adj));
+
       }
 
+      if(ss->visible1[j] && !mute_channel_muted(ss->mutemask1,j)){
+	/* determine rms and peak for feedback */
+	float max=-1.;
+	int maxpos=-1;
+	float rms=0.;
+	if(bypass_visible){
+	  int ii;
+	  for(ii=0;ii<w->freq_bands;ii++){
+	    memset(peakfeed[ii],0,input_ch*sizeof(**peakfeed));
+	    memset(rmsfeed[ii],0,input_ch*sizeof(**rmsfeed));
+	  }
+	}
+	bypass_visible=0;
+
+	for(k=0;k<input_size;k++){
+	  float val=x[k]*x[k];
+	  if(val>max){
+	    max=val;
+	    maxpos=k;
+	  }
+	  rms+=val;
+	}
+	if(active){
+	  peakfeed[i][j]=todB(max)*.5+adj[maxpos];
+	  rmsfeed[i][j]=todB(rms/input_size)*.5+adj[maxpos];
+	}else{
+	  peakfeed[i][j]=todB(max)*.5;
+	  rmsfeed[i][j]=todB(rms/input_size)*.5;
+	}
+      }
       
       if(active){
-	x=ms.ss.lap[i][j];
-	for(k=0;k<input_size;k++)
-	  x[k]*=fromdB_a(adj[k]);
+	base_compand(x,  
+		     &ms->base_attack,
+		     &ms->base_decay,
+		     &ms->base_iir[i][j],
+		     &ms->base_peak[i][j],
+		     (i>=w->freq_bands?0:adj));
+	
+	if(ss->effect_activeC[j]){
+	  for(k=0;k<input_size;k++)
+	    x[k]*=fromdB_a(adj[k]);
+	}
+      } else if (ss->effect_activeP[j]){ 
+	/* this lapping channel just became inactive */
+	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));
+	memset(&ms->over_iir[i][j],0,sizeof(iir_state));
+	memset(&ms->under_iir[i][j],0,sizeof(iir_state));
+	memset(&ms->base_iir[i][j],0,sizeof(iir_state));
       }
+
     }
   }
-}
 
-void multicompand_set_bank(int bank){
-  ms.pending_bank=bank;
+  for(;i<wP->freq_bands;i++)
+    for(j=0;j<input_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));
+      memset(&ms->over_iir[i][j],0,sizeof(iir_state));
+      memset(&ms->under_iir[i][j],0,sizeof(iir_state));
+      memset(&ms->base_iir[i][j],0,sizeof(iir_state));
+    }
+
+  /* finish up the state feedabck */
+  if(bypass_visible){
+    multicompand_feedback *ff=
+      (multicompand_feedback *)
+      feedback_new(&ms->feedpool,new_multicompand_feedback);
+    ff->bypass=1;
+    feedback_push(&ms->feedpool,(feedback_generic *)ff);
+  }else{
+    multicompand_feedback *ff=
+      (multicompand_feedback *)
+      feedback_new(&ms->feedpool,new_multicompand_feedback);
+    
+    for(i=0;i<w->freq_bands;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));
+    } 
+    ff->bypass=0;
+    ff->freq_bands=w->freq_bands;
+    feedback_push(&ms->feedpool,(feedback_generic *)ff);
+  }
 }
 
 time_linkage *multicompand_read(time_linkage *in){
-  int bypass=!(compand_visible||compand_active);
-  
-  ms.active_bank=ms.pending_bank;
+  int visible[input_ch];
+  int active[input_ch];
+  int i;
 
-  return subband_read(in,&ms.ss,&ms.sw[ms.active_bank],
-		      multicompand_work,bypass);
+  for(i=0;i<input_ch;i++){
+    visible[i]=compand_visible;
+    active[i]=compand_active;
+  }
+  return subband_read(in, &ms.ss, &ms.sw[c.active_bank],
+		      visible,active,multicompand_work,&ms);
+
 }
 
+

Modified: trunk/postfish/multicompand.h
===================================================================
--- trunk/postfish/multicompand.h	2004-04-22 07:37:57 UTC (rev 6572)
+++ trunk/postfish/multicompand.h	2004-04-22 09:31:18 UTC (rev 6573)
@@ -73,12 +73,12 @@
   sig_atomic_t under_lookahead;
   sig_atomic_t under_trim;
 
+  sig_atomic_t active_bank;
 } other_compand_settings;
 
 extern void multicompand_reset();
 extern int multicompand_load(void);
 extern time_linkage *multicompand_read(time_linkage *in);
-extern void multicompand_set_bank(int bank);
 extern int pull_multicompand_feedback(float **peak,float **rms,int *bands);
 
 extern int multicompand_over_attack_set(float msec);

Modified: trunk/postfish/singlecomp.c
===================================================================
--- trunk/postfish/singlecomp.c	2004-04-22 07:37:57 UTC (rev 6572)
+++ trunk/postfish/singlecomp.c	2004-04-22 09:31:18 UTC (rev 6573)
@@ -61,35 +61,13 @@
   float **cache;
   int cache_samples;
 
+  u_int32_t mutemask0;
+
 } singlecomp_state;
 
 singlecomp_settings scset;
 singlecomp_state scs;
 
-static void _analysis(char *base,int i,float *v,int n,int dB,int offset){
-  int j;
-  FILE *of;
-  char buffer[80];
-
-  sprintf(buffer,"%s_%d.m",base,i);
-  of=fopen(buffer,"a");
-  
-  if(!of)perror("failed to open data dump file");
-  
-  for(j=0;j<n;j++){
-    fprintf(of,"%f ",(float)j+offset);
-    if(dB)
-      fprintf(of,"%f\n",todB(v[j]));
-    else
-      fprintf(of,"%f\n",(v[j]));
-  }
-  fprintf(of,"\n");
-  fclose(of);
-}
-
-static int offset=0;
-
-
 /* feedback! */
 typedef struct singlecomp_feedback{
   feedback_generic parent_class;
@@ -361,6 +339,8 @@
       scs.out.samples=0;
       return &scs.out;
     }
+    scs.mutemask0=in->active;
+
     for(i=0;i<input_ch;i++){
       float *temp=in->data[i];
       float adj[input_size]; // under will set it
@@ -514,8 +494,8 @@
         memset(scs.out.data[i]+scs.out.samples,0,sizeof(**scs.out.data)*tozero);
   }
 
-  offset+=input_size;
-
+  scs.out.active=scs.mutemask0;
+  scs.mutemask0=in->active;
   return &scs.out;
 }
 

Modified: trunk/postfish/subband.c
===================================================================
--- trunk/postfish/subband.c	2004-04-22 07:37:57 UTC (rev 6572)
+++ trunk/postfish/subband.c	2004-04-22 09:31:18 UTC (rev 6573)
@@ -23,7 +23,6 @@
 
 #include "postfish.h"
 #include <fftw3.h>
-#include "feedback.h"
 #include "subband.h"
 #include "lpc.h"
 
@@ -31,44 +30,6 @@
 extern int input_rate;
 extern int input_ch;
 
-/* feedback! */
-typedef struct subband_feedback{
-  feedback_generic parent_class;
-  float **peak;
-  float **rms;
-  int freq_bands;
-  int bypass;
-} subband_feedback;
-
-static feedback_generic *new_subband_feedback(void){
-  subband_feedback *ret=calloc(1,sizeof(*ret));
-  return (feedback_generic *)ret;
-}
-
-/* total, peak, rms are pulled in array[freqs][input_ch] order */
-
-int pull_subband_feedback(subband_state *ff,float **peak,float **rms,int *b){
-  subband_feedback *f=(subband_feedback *)feedback_pull(&ff->feedpool);
-  int i;
-  
-  if(!f)return 0;
-  
-  if(f->bypass){
-    feedback_old(&ff->feedpool,(feedback_generic *)f);
-    return 2;
-  }else{
-    if(peak)
-      for(i=0;i<ff->bands;i++)
-	memcpy(peak[i],f->peak[i],sizeof(**peak)*input_ch);
-    if(rms)
-      for(i=0;i<ff->bands;i++)
-	memcpy(rms[i],f->rms[i],sizeof(**rms)*input_ch);
-    if(b)*b=f->freq_bands;
-    feedback_old(&ff->feedpool,(feedback_generic *)f);
-    return 1;
-  }
-}
-
 /* called only by initial setup */
 int subband_load(subband_state *f,int bands,int qblocksize){
   int i,j;
@@ -79,10 +40,27 @@
   f->fillstate=0;
   f->lap_samples=0;
   f->lap=malloc(bands*sizeof(*f->lap));
-  f->cache=malloc(input_ch*sizeof(*f->cache));
+  f->cache0=malloc(input_ch*sizeof(*f->cache0));
+  f->cache1=malloc(input_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->visible1=malloc(input_ch*sizeof(*f->visible1));
+  f->visible0=malloc(input_ch*sizeof(*f->visible0));
+  f->visibleC=malloc(input_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));
+
   for(i=0;i<input_ch;i++)
-    f->cache[i]=malloc(input_size*sizeof(**f->cache));
+    f->cache0[i]=malloc(input_size*sizeof(**f->cache0));
+  for(i=0;i<input_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));
@@ -101,8 +79,6 @@
   f->window=malloc(f->qblocksize*2*sizeof(*f->window)); 
   /* we need a smooth-edged, symmetric window */
   for(i=0;i<f->qblocksize*2;i++)f->window[i]=sin(M_PIl*i/(f->qblocksize*2));
-  //for(i=0;i<f->qblocksize*2;i++)f->window[i]*=f->window[i];
-  //for(i=0;i<f->qblocksize*2;i++)f->window[i]=sin(f->window[i]*M_PIl*.5);
   for(i=0;i<f->qblocksize*2;i++)f->window[i]*=f->window[i]*.25/f->qblocksize;
 
   f->fftwf_forward_out  = fftwf_malloc(sizeof(*f->fftwf_forward_out) * 
@@ -137,7 +113,6 @@
 
   /* supersample the spectrum */
   w->ho_window=malloc(bands*sizeof(*w->ho_window));
-  w->ho_area=calloc(bands,sizeof(*w->ho_area));
   {
     float working[f->qblocksize*4+2];
     
@@ -176,11 +151,11 @@
          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;j++)
+      for(j=0;j<f->qblocksize*2+2;j++)
         f->fftwf_backward_in[j*2]=working[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));
@@ -207,7 +182,7 @@
       /* 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_area[i]+=w->ho_window[i][j]=f->fftwf_forward_out[j*2];
+        w->ho_window[i][j]=f->fftwf_forward_out[j*2];
       
       lastf=thisf;
       
@@ -221,7 +196,6 @@
 int subband_reset(subband_state *f){
   /* reset cached pipe state */
   f->fillstate=0;
-  while(pull_subband_feedback(f,NULL,NULL,NULL));
   return 0;
 }
 
@@ -229,171 +203,288 @@
    linear time-convolution using the response filters created earlier
    and padded FFTs with 75% overlap. */
 
-static void subband_work(subband_state *f,time_linkage *in,subband_window *w){
+static void subband_work(subband_state *f,
+			 time_linkage *in,
+			 subband_window *w,
+			 int      *visible,
+			 int      *active){
+
+
   int i,j,k,l,off;
   float *workoff=f->fftwf_forward_in+f->qblocksize;
+  u_int32_t mutemask=in->active;
 
+  f->mutemaskC=mutemask;
+  f->wC=w;
+
   for(i=0;i<input_ch;i++){
-    off=0;
 
-    for(j=0;j<(input_size/f->qblocksize);j++){
-      
-      switch(j){
-      case 0:
-	memcpy(workoff,f->cache[i]+input_size-f->qblocksize*2,
-	       sizeof(*workoff)*f->qblocksize*2);
-	break;
-      case 1:	
-	memcpy(workoff,f->cache[i]+input_size-f->qblocksize,
-	       sizeof(*workoff)*f->qblocksize);
-	memcpy(workoff+f->qblocksize,in->data[i],
-	       sizeof(*workoff)*f->qblocksize);
-	break;
-      default:
-	memcpy(workoff,in->data[i]+off,
-	       sizeof(*workoff)*f->qblocksize*2);
-	off+=f->qblocksize;
-	break;
-      }
+    int content_p=  f->lap_activeC[i]= (visible[i]||active[i]) && !mute_channel_muted(mutemask,i);
+    int content_p0= f->lap_active0[i];
+    int content_p1= f->lap_active1[i];
 
-      /* window; assume the edges are already zeroed */
-      for(k=0;k<f->qblocksize*2;k++)workoff[k]*=f->window[k];
+    int maxbands=w->freq_bands;
+    if(maxbands<f->w0->freq_bands)maxbands=f->w0->freq_bands;
+    if(maxbands<f->w1->freq_bands)maxbands=f->w1->freq_bands;
 
-      fftwf_execute(f->fftwf_forward);
+    f->effect_activeC[i] = active[i] && !mute_channel_muted(mutemask,i);
+    f->visibleC[i] = visible[i];
 
-      /* repeatedly filter and transform back */
-      for(k=0;k<w->freq_bands;k++){
-	float *lapcb=f->lap[k][i]+input_size*2+(j-3)*f->qblocksize;
+    if(!content_p1 && !content_p0 && !content_p){
+      /* all disabled, lap is already zeroed.  Nothing to do */
+      continue;
+
+    }else if(!content_p0 && content_p){
+      /* from inactive to active; first block to be processed must be
+         entirely within new data so prepare the lap */
+
+      for(k=0;k<maxbands;k++)
+	memset(f->lap[k][i]+input_size*2,0,f->qblocksize*3*sizeof(***f->lap));
+
+    }else if (content_p0 && !content_p){
+      /* from active to inactive; the previous lap is done, just zero out this frame */
+      for(k=0;k<maxbands;k++)
+	memset(f->lap[k][i]+input_size*2,0,input_size*sizeof(*f->lap[k][i]));
+    } 
+
+    if(content_p){ /* there is something to do */
+
+      if(content_p0){ /* was lap active last block? */
+	j=0; /* yes; span the gap */
+	off=0;
+      }else{
+	j=3; /* no; start entirely within new data */
+	off=f->qblocksize;
+      }
+
+      for(;j<(input_size/f->qblocksize);j++){
         
-	for(l=0;l<f->qblocksize*2+1;l++){
-	  f->fftwf_backward_in[2*l]= 
-	    f->fftwf_forward_out[2*l]*w->ho_window[k][l];
-	  f->fftwf_backward_in[2*l+1]= 
-	    f->fftwf_forward_out[2*l+1]*w->ho_window[k][l];
+	switch(j){
+	case 0:
+	  memcpy(workoff,f->cache0[i]+input_size-f->qblocksize*2,
+		 sizeof(*workoff)*f->qblocksize*2);
+	  break;
+	case 1:	
+	  memcpy(workoff,f->cache0[i]+input_size-f->qblocksize,
+		 sizeof(*workoff)*f->qblocksize);
+	  memcpy(workoff+f->qblocksize,in->data[i],
+		 sizeof(*workoff)*f->qblocksize);
+	  break;
+	default:
+	  memcpy(workoff,in->data[i]+off,
+		 sizeof(*workoff)*f->qblocksize*2);
+	  off+=f->qblocksize;
+	  break;
         }
         
-	fftwf_execute(f->fftwf_backward);
+	/* window; assume the edges are already zeroed */
+	for(k=0;k<f->qblocksize*2;k++)workoff[k]*=f->window[k];
         
-	/* lap back into the subband; the convolution is already
-           balanced so no further windowing needed */
-	for(l=0;l<f->qblocksize*3;l++)
-	  lapcb[l]+=f->fftwf_backward_out[l];
-	for(;l<f->qblocksize*4;l++)
-	  lapcb[l]=f->fftwf_backward_out[l];
-
-      }
-      /* if we're suddenly processing fewer bands than we were, we
-         have to trail out zeroes until the band lap is emptied */
-      {
-	int bands=f->lapbands[0];
-	if(bands<f->lapbands[1])bands=f->lapbands[1];
-	if(bands<f->lapbands[2])bands=f->lapbands[2];
-
-	for(;k<bands;k++){
+	fftwf_execute(f->fftwf_forward);
+	
+	/* repeatedly filter and transform back */
+	for(k=0;k<w->freq_bands;k++){
           float *lapcb=f->lap[k][i]+input_size*2+(j-3)*f->qblocksize;
-	  memset(lapcb+f->qblocksize*3,0,sizeof(*lapcb)*f->qblocksize);
+	  
+	  for(l=0;l<f->qblocksize*2+1;l++){
+	    f->fftwf_backward_in[2*l]= 
+	      f->fftwf_forward_out[2*l]*w->ho_window[k][l];
+	    f->fftwf_backward_in[2*l+1]= 
+	      f->fftwf_forward_out[2*l+1]*w->ho_window[k][l];
+	  }
+	  
+	  fftwf_execute(f->fftwf_backward);
+	  
+	  /* lap back into the subband; the convolution is already
+	     balanced so no further windowing needed */
+	  for(l=0;l<f->qblocksize*3;l++)
+	    lapcb[l]+=f->fftwf_backward_out[l];
+	  for(;l<f->qblocksize*4;l++)
+	    lapcb[l]=f->fftwf_backward_out[l];
+	  
         }
       }
+      /* if we're suddenly processing fewer bands than we were, we
+	 have to trail out zeroes until the band lap is emptied */
+      for(k=w->freq_bands;k<maxbands;k++)
+	memset(f->lap[k][i]+input_size*2,0,sizeof(*f->lap[k][i])*input_size);
+	  
     }
   }
 }
 
-static void bypass_work(subband_state *f,time_linkage *in){
-  int i,j;
-  float scale=f->qblocksize*4.;
+static void unsubband_work(subband_state *f,time_linkage *in, time_linkage *out){
+  int i,j,k;
 
+  f->lap_samples+=in->samples;
   for(i=0;i<input_ch;i++){
-    float *lapcb=f->lap[0][i]+input_size*2-f->qblocksize*2;
-    float *x=f->cache[i]+input_size-f->qblocksize*2;
-	
-    for(j=0;j<f->qblocksize;j++)
-      lapcb[j]+=x[j]*f->window[j]*scale;
-
-    lapcb+=f->qblocksize;
-    x+=f->qblocksize;
     
-    memcpy(lapcb,x,sizeof(*x)*f->qblocksize);
+    int content_pP= f->lap_activeP[i];
+    int content_p1= f->lap_active1[i];
+    int content_p0= f->lap_active0[i];
+    int content_pC= f->lap_activeC[i];
 
-    lapcb+=f->qblocksize;
-    x=in->data[i];
+    int active_pP= f->effect_activeP[i];
+    int active_p1= f->effect_active1[i];
+    int active_p0= f->effect_active0[i];
 
-    memcpy(lapcb,x,sizeof(*x)*(input_size-f->qblocksize*2));
+    int muted_p1= mute_channel_muted(f->mutemask1,i);
 
-    lapcb+=(input_size-f->qblocksize*2);
-    x+=(input_size-f->qblocksize*2);
+    int maxbands=f->wC->freq_bands;
+    if(maxbands<f->w0->freq_bands)maxbands=f->w0->freq_bands;
+    if(maxbands<f->w1->freq_bands)maxbands=f->w1->freq_bands;
+  
+    /* even if the lapping for a channel is active, we will draw
+       output from the cache is the effect is inactive; it saves
+       performing the summation across bands */
 
-    for(j=0;j<f->qblocksize;j++)
-      lapcb[j]=x[j]*f->window[j+f->qblocksize]*scale;
+    /*   OUTPUT PROCESSING
 
-    for(;j<f->qblocksize*2;j++)
-      lapcb[j]=0.;
+	 if muted, lap is inactive
+	 if visible or active (and not muted) lap is active
+	 if inactive and invisible, lap is inactive
 
-    /* do we need to keep propogating zeros forward in other bands? */
-    {
-      int bands=f->lapbands[0];
-      if(bands<f->lapbands[1])bands=f->lapbands[1];
-      if(bands<f->lapbands[2])bands=f->lapbands[2];
-      
-      for(j=1;j<bands;j++){
-	float *lapcb=f->lap[j][i]+input_size*2-f->qblocksize;
-	memset(lapcb,0,sizeof(*lapcb)*(input_size+f->qblocksize));
-      }
-    }
-  }
-}
+            lap  effect mute 
+	 1. (I)   (I)    A  : muted; do nothing, the mask will take care of it
+	 2.  X     I     I  : full bypass, audible data; rotate the cache into output
+	 3.  I     A     I  : not possible
+	 4.  A     A     I  : nominal
+	 
+	 we transition from effect active/inactive/active:
 
-static void unsubband_work(subband_state *f,float **out,int inbands){
-  int i,j,k;
+	 a) transitions always happen in the shared active portion
+	 b) sum frame from active lap
+	 c) window beginning/end of resulting summation if necessary
+	 d) window/add beginning/end of final frame from cache data if necessary
 
-  int bands=f->lapbands[0];
-  if(bands<f->lapbands[1])bands=f->lapbands[1];
-  if(bands<f->lapbands[2])bands=f->lapbands[2];
-  if(bands<inbands)bands=inbands;
+    */
 
-  for(i=0;i<input_ch;i++){
-    for(j=bands-1;j>=0;j--){
-      
-      /* add bands back together for output */
-      if(out){
-	if(j==bands-1){
-	  memcpy(out[i],f->lap[j][i],input_size*(sizeof **out));
-	}else{
+    if(out){
+      if(muted_p1 || !active_p1){
+	/* case 1,2; they're similar enough  */
+	
+	float *temp=f->cache1[i];
+	f->cache1[i]=out->data[i];
+	out->data[i]=temp;
+	/* mutemask will be propogated later */
+	
+      }else{
+	/* 'other' */
+	
+	/* b) sum the lap */
+	float *o=out->data[i];
+	memcpy(o,f->lap[0][i],input_size*sizeof(*out->data[i]));
+	for(j=1;j<maxbands;j++){
+	  float *x=f->lap[j][i];
           for(k=0;k<input_size;k++)
-	    out[i][k]+=f->lap[j][i][k];
+	    o[k]+=x[k];
         }
+	
+	/* c) window beginning/end of summation if needed */
+	if(!active_pP && content_pP){
+
+ 	  /* transitioning to active effect, but the lap was already
+	     previously active; window the transition */
+	  float *lo=o+f->qblocksize;
+	  float scale=f->qblocksize*4;
+	  memset(o,0,sizeof(*o)*f->qblocksize);
+	  for(j=0;j<f->qblocksize;j++)
+	    lo[j]*=f->window[j]*scale;
+	  
+	}else if (!active_p0 && content_p0){
+
+	  /* transitioning from active effect, but the lap will continue
+	     to be active; window the transition */
+	  float *lo=o+input_size-f->qblocksize*2;
+	  float *lw=f->window+f->qblocksize;
+	  float scale=f->qblocksize*4;
+	  memset(o+input_size-f->qblocksize,0,sizeof(*o)*f->qblocksize);
+	  for(j=0;j<f->qblocksize;j++)
+	    lo[j]*=lw[j]*scale;
+
+	} /* otherwise any transitions we need are already windowed as
+	     above by the lap handling code in subband_work */
+	
+	/* d) window/add cache bits if needed */
+	if(!active_pP){
+	  /* beginning transition */
+	  float *lo=o+f->qblocksize;
+	  float *lc=f->cache1[i]+f->qblocksize;
+	  float *lw=f->window+f->qblocksize;
+	  float scale=f->qblocksize*4;
+
+	  memcpy(o,f->cache1[i],sizeof(*o)*f->qblocksize);
+	  for(j=0;j<f->qblocksize;j++)
+	    lo[j]+=lc[j]*lw[j]*scale;
+	  
+	}else if (!active_p0){
+	  /* end transition */
+	  float *lo=o+input_size-f->qblocksize*2;
+	  float *lc=f->cache1[i]+input_size-f->qblocksize*2;
+	  float scale=f->qblocksize*4;
+
+	  memcpy(o+input_size-f->qblocksize,
+		 f->cache1[i]+input_size-f->qblocksize,
+		 sizeof(*o)*f->qblocksize);
+	  for(j=0;j<f->qblocksize;j++)
+	    lo[j]+=lc[j]*f->window[j]*scale;
+	  
+	}
       }
+
+    }
+    
+    /* out is done for this channel */
+    /* rotate lap */
+    if(content_p1 || content_p0 || content_pC){
+      for(j=0;j<maxbands;j++)
+	memmove(f->lap[j][i],f->lap[j][i]+input_size,
+		sizeof(***f->lap)*input_size*2);
       
-      /* shift bands for next lap */
-      /* optimization target: ringbuffer me! */
-      memmove(f->lap[j][i],f->lap[j][i]+input_size,
-	      sizeof(***f->lap)*input_size*2);
-      
+      f->lap_activeP[i]=f->lap_active1[i];
+      f->lap_active1[i]=f->lap_active0[i];
+      f->lap_active0[i]=f->lap_activeC[i];
     }
+    /* rotate cache data vectors */
+    {
+      float *temp=f->cache1[i];
+      f->cache1[i]=f->cache0[i];
+      f->cache0[i]=in->data[i];
+      in->data[i]=temp;
+    }
   }
+  if(out){
+    out->active=f->mutemask1;
+    f->out.samples=(f->lap_samples>input_size?input_size:f->lap_samples);
+  }
 
-  f->lapbands[0]=f->lapbands[1];
-  f->lapbands[1]=f->lapbands[2];
-  f->lapbands[2]=inbands;
+  /* 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->visible1,f->visible0,input_ch*sizeof(*f->visible0));
+  memcpy(f->visible0,f->visibleC,input_ch*sizeof(*f->visibleC));
+
+  f->mutemaskP=f->mutemask1;
+  f->mutemask1=f->mutemask0;
+  f->mutemask0=f->mutemaskC;
+
+  f->wP=f->w1;
+  f->w1=f->w0;
+  f->w0=f->wC;
+
+  f->lap_samples-=(out?f->out.samples:0);
+
 }
 
 /* called only by playback thread */
 time_linkage *subband_read(time_linkage *in, subband_state *f,
-			   subband_window *w,
-			   void (*func)(float **, float **),int bypass){
+			   subband_window *w,int *visible, int *active,
+			   void (*workfunc)(void *),void *arg){
   int i,j;
-  float peak[w->freq_bands][input_ch];
-  float rms[w->freq_bands][input_ch];
   
-  float *peakp[w->freq_bands];
-  float *rmsp[w->freq_bands];
-  
-  if(!bypass)
-    for(i=0;i<w->freq_bands;i++){
-      peakp[i]=peak[i];
-      rmsp[i]=rms[i];
-    }
-  
   switch(f->fillstate){
   case 0: /* begin priming the lapping and cache */
     if(in->samples==0){
@@ -401,44 +492,64 @@
       return &f->out;
     }
     
-    /* initially zero the lapping */
+    /* initially zero the lapping and cache */
     for(i=0;i<input_ch;i++){    
       for(j=0;j<f->bands;j++)    
         memset(f->lap[j][i],0,sizeof(***f->lap)*input_size*2);
-      memset(f->cache[i],0,sizeof(**f->cache)*input_size);
+      memset(f->cache1[i],0,sizeof(**f->cache1)*input_size);
+      memset(f->cache0[i],0,sizeof(**f->cache0)*input_size);
     }
 
+    /* and set up state variables */
+    /* 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++){
+      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);
+    }
+    
+    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);
+
+    memset(f->visible1,0,sizeof(*f->visible1)*input_ch);
+    memset(f->visible0,0,sizeof(*f->visible0)*input_ch);
+    
+    f->mutemaskP=in->active;
+    f->mutemask1=in->active;
+    f->mutemask0=in->active;
+
+    f->wP=w;
+    f->w1=w;
+    f->w0=w;
+
     /* initially zero the padding of the input working array */
     memset(f->fftwf_forward_in,0,f->qblocksize*4*sizeof(*f->fftwf_forward_in));
 
-    if(bypass){
-      bypass_work(f,in);
-      unsubband_work(f,0,1);
-    }else{
-      /* extrapolation mechanism; avoid harsh transients at edges */
-      for(i=0;i<input_ch;i++){
+    /* extrapolation mechanism; avoid harsh transients at edges */
+    for(i=0;i<input_ch;i++){
+      
+      if(f->lap_active0[i]){
         preextrapolate_helper(in->data[i],input_size,
-			      f->cache[i],input_size);
+			    f->cache0[i],input_size);
       
-      if(in->samples<in->size)
-	postextrapolate_helper(f->cache[i],input_size,
-			       in->data[i],in->samples,
-			       in->data[i]+in->samples,
-			       in->size-in->samples);
+	if(in->samples<in->size)
+	  postextrapolate_helper(f->cache0[i],input_size,
+				 in->data[i],in->samples,
+				 in->data[i]+in->samples,
+				 in->size-in->samples);
       }
+    }
       
-      subband_work(f,in,w);
-      func(peakp,rmsp);
-      unsubband_work(f,0,w->freq_bands);
-    }
+    subband_work(f,in,w,visible,active);
+    workfunc(arg);
+    unsubband_work(f,in,NULL);
 
-    for(i=0;i<input_ch;i++){
-      float *temp=in->data[i];
-      in->data[i]=f->cache[i];
-      f->cache[i]=temp;
-    }
-    
-    f->lap_samples=in->samples;
     f->fillstate=1;
     f->out.samples=0;
     if(in->samples==in->size)goto tidy_up;
@@ -450,31 +561,21 @@
 
   case 1: /* finish priming the lapping and cache */
 
-    if(bypass){
-      bypass_work(f,in);
-      unsubband_work(f,0,1);
-    }else{
-      /* extrapolation mechanism; avoid harsh transients at edges */
+    /* extrapolation mechanism; avoid harsh transients at edges */
+
+    if(in->samples<in->size)
       for(i=0;i<input_ch;i++){
-	if(in->samples<in->size)
-	  postextrapolate_helper(f->cache[i],input_size,
+	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);
       }
       
-      subband_work(f,in,w);
-      func(peakp,rmsp);
-      unsubband_work(f,0,w->freq_bands);
-    }
+    subband_work(f,in,w,visible,active);
+    workfunc(arg);
+    unsubband_work(f,in,NULL);
 
-    for(i=0;i<input_ch;i++){
-      float *temp=in->data[i];
-      in->data[i]=f->cache[i];
-      f->cache[i]=temp;
-    }
-    
-    f->lap_samples=in->samples;
     f->fillstate=2;
     f->out.samples=0;
     if(in->samples==in->size)goto tidy_up;
@@ -486,34 +587,20 @@
 
   case 2: /* nominal processing */
     
-    if(bypass){
-      bypass_work(f,in);
-      unsubband_work(f,f->out.data,1);
-    }else{
-      /* extrapolation mechanism; avoid harsh transients at edges */
+    if(in->samples<in->size)
       for(i=0;i<input_ch;i++){
-	if(in->samples<in->size)
-	  postextrapolate_helper(f->cache[i],input_size,
+	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);
       }
       
-      subband_work(f,in,w);
-      func(peakp,rmsp);
-      unsubband_work(f,f->out.data,w->freq_bands);
-    }
-    for(i=0;i<input_ch;i++){
-      float *temp=in->data[i];
-      in->data[i]=f->cache[i];
-      f->cache[i]=temp;
-    }
-    
-    f->lap_samples+=in->samples;
-    f->fillstate=2;
-    f->out.samples=(f->lap_samples>input_size?input_size:f->lap_samples);
-    f->lap_samples-=f->out.samples;
-    if(f->out.samples<f->out.size)f->fillstate=2;
+    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;
     break;
 
   case 3: /* we've pushed out EOF already */
@@ -521,36 +608,6 @@
     break;
   }
 
-  /* finish up the state feedabck */
-  if(!bypass){
-    subband_feedback *ff=
-      (subband_feedback *)feedback_new(&f->feedpool,new_subband_feedback);
-
-    if(!ff->peak){
-      ff->peak=malloc(f->bands*sizeof(*ff->peak));
-      for(i=0;i<f->bands;i++)
-	ff->peak[i]=malloc(input_ch*sizeof(**ff->peak));
-    }
-    if(!ff->rms){
-      ff->rms=malloc(f->bands*sizeof(*ff->rms));
-      for(i=0;i<f->bands;i++)
-	ff->rms[i]=malloc(input_ch*sizeof(**ff->rms));
-    }
-
-    for(i=0;i<w->freq_bands;i++){
-      memcpy(ff->peak[i],peak[i],input_ch*sizeof(**peak));
-      memcpy(ff->rms[i],rms[i],input_ch*sizeof(**rms));
-    } 
-    ff->bypass=0;
-    ff->freq_bands=w->freq_bands;
-    feedback_push(&f->feedpool,(feedback_generic *)ff);
-  }else{
-    subband_feedback *ff=
-      (subband_feedback *)feedback_new(&f->feedpool,new_subband_feedback);
-    ff->bypass=1;
-    feedback_push(&f->feedpool,(feedback_generic *)ff);
-  }
-
  tidy_up:
   {
     int tozero=f->out.size-f->out.samples;
@@ -558,6 +615,6 @@
       for(i=0;i<f->out.channels;i++)
         memset(f->out.data[i]+f->out.samples,0,sizeof(**f->out.data)*tozero);
   }
-
+  
   return &f->out;
 }

Modified: trunk/postfish/subband.h
===================================================================
--- trunk/postfish/subband.h	2004-04-22 07:37:57 UTC (rev 6572)
+++ trunk/postfish/subband.h	2004-04-22 09:31:18 UTC (rev 6573)
@@ -24,8 +24,14 @@
 #include "postfish.h"
 
 typedef struct {
+
+  int      freq_bands;
+  float  **ho_window;
+  
+} subband_window;
+
+typedef struct {
   time_linkage out;
-  feedback_generic_pool feedpool;
 
   float *fftwf_forward_out;
   float *fftwf_backward_in;
@@ -38,36 +44,50 @@
   float   *window;
   int      bands;
   float ***lap;
-  float  **cache;
+  float  **cache0;
+  float  **cache1;
+
+  int      *lap_activeC;
+  int      *lap_active0;
+  int      *lap_active1;
+  int      *lap_activeP;
+
+  int      *visibleC;
+  int      *visible0;
+  int      *visible1;
+
+  int      *effect_activeC;
+  int      *effect_active0;
+  int      *effect_active1;
+  int      *effect_activeP;
+
+  u_int32_t mutemaskC;
+  u_int32_t mutemask0;
+  u_int32_t mutemask1;
+  u_int32_t mutemaskP;
+
   int      lap_samples;
   int      fillstate;     /* 0: uninitialized
                              1: partial prime
                              2: nominal
                              3: eof processed */
-  int lapbands[3];
+  subband_window *wP;
+  subband_window *w0;
+  subband_window *w1;
+  subband_window *wC;
+
 } subband_state;
 
-typedef struct {
 
-  int      freq_bands;
-  float  **ho_window;
-  float   *ho_area;
-  
-} subband_window;
 
-
-
 extern int subband_load(subband_state *f,int bands, int qb);
 extern int subband_load_freqs(subband_state *f,subband_window *w,
                               const float *freq_list,int bands);
 
 extern time_linkage *subband_read(time_linkage *in, subband_state *f,
-				  subband_window *w,
-				  void (*func)(float **, float **),
-				  int bypass);
+				  subband_window *w,int *visible, int *active,
+				  void (*workfunc)(void *),void *arg);
 
 extern int subband_reset(subband_state *f);
-extern int pull_subband_feedback(subband_state *ff,
-				 float **peak,float **rms,int *bands);
 
 

Modified: trunk/postfish/suppress.c
===================================================================
--- trunk/postfish/suppress.c	2004-04-22 07:37:57 UTC (rev 6572)
+++ trunk/postfish/suppress.c	2004-04-22 09:31:18 UTC (rev 6573)
@@ -115,14 +115,16 @@
   return 0;
 }
 
-static void suppress_work(float **peakfeed,float **rmsfeed){
+static void suppress_work(void *vs){
+  suppress_state *sss=(suppress_state *)vs;
+  subband_state *ss=&sss->ss;
   int i,j,k,l;
   float smoothms=sset.smooth*.1;
   float triggerms=sset.trigger*.1;
   float releasems=sset.release*.1;
-  iir_filter *trigger=&sss.trigger;
-  iir_filter *smooth=&sss.smooth;
-  iir_filter *release=&sss.release;
+  iir_filter *trigger=&sss->trigger;
+  iir_filter *smooth=&sss->smooth;
+  iir_filter *release=&sss->release;
   int ahead;
 
   if(smoothms!=smooth->ms)filter_set(smoothms,smooth,1,4);
@@ -132,48 +134,52 @@
   ahead=impulse_ahead4(smooth->alpha);
   
   for(i=0;i<suppress_freqs;i++){
-
-    if(suppress_active){
-      float fast[input_size];
-      float slow[input_size];
-      float multiplier = 1.-1000./sset.ratio[i];
-
-      for(j=0;j<input_ch;j++){
+    int firstlink=0;
+    float fast[input_size];
+    float slow[input_size];
+    float multiplier = 1.-1000./sset.ratio[i];
+    
+    for(j=0;j<input_ch;j++){
+      int active=(ss->effect_active1[j] || 
+		  ss->effect_active0[j] || 
+		  ss->effect_activeC[j]);
+      
+      if(active){
         if(sset.linkp){
-	  if(j==0){
+	  if(!firstlink){
+	    firstlink++;
             memset(fast,0,sizeof(fast));
             float scale=1./input_ch;
             for(l=0;l<input_ch;l++){
-	      float *x=sss.ss.lap[i][l]+ahead;
+	      float *x=sss->ss.lap[i][l]+ahead;
               for(k=0;k<input_size;k++)
                 fast[k]+=x[k]*x[k];
             }
             for(k=0;k<input_size;k++)
               fast[k]*=scale;
-
-	    //_analysis("rms",i,fast,input_size,0,offset);
-
+	    
           }
           
         }else{
-	  float *x=sss.ss.lap[i][j]+ahead;
+	  float *x=sss->ss.lap[i][j]+ahead;
           for(k=0;k<input_size;k++)
             fast[k]=x[k]*x[k];
         }
-
         
-	if(j==0 || sset.linkp==0){
-
-	  compute_iir_symmetric4(fast, input_size, &sss.iirS[i][j],
-				smooth);
+	
+	if(sset.linkp==0 || firstlink==1){
+	  firstlink++;
           
+	  compute_iir_symmetric4(fast, input_size, &sss->iirS[i][j],
+				 smooth);
+	  
           //_analysis("smooth",i,fast,input_size,1,offset);
           
-	  compute_iir_freefall1(fast, input_size, &sss.iirT[i][j],
-	  		 trigger);
+	  compute_iir_freefall1(fast, input_size, &sss->iirT[i][j],
+				trigger);
           memcpy(slow,fast,sizeof(slow));
-	  compute_iir_freefall1(slow, input_size, &sss.iirR[i][j],
-			       release);
+	  compute_iir_freefall1(slow, input_size, &sss->iirR[i][j],
+				release);
           
           //_analysis("fast",i,fast,input_size,1,offset);
           //_analysis("slow",i,slow,input_size,1,offset);
@@ -181,24 +187,35 @@
             fast[k]=fromdB_a((todB_a(slow+k)-todB_a(fast+k))*.5*multiplier);
           //_analysis("adj",i,fast,input_size,1,offset);
         }
-
-
+	
+	
         {
-	  float *x=sss.ss.lap[i][j];
+	  float *x=sss->ss.lap[i][j];
           for(k=0;k<input_size;k++)
             if(fast[k]<1.)
               x[k]*=fast[k];
         }
+      }else{
+	/* reset filters to sane inactive default */
+	memset(&sss->iirS[i][j],0,sizeof(iir_state));
+	memset(&sss->iirT[i][j],0,sizeof(iir_state));
+	memset(&sss->iirR[i][j],0,sizeof(iir_state));
       }
     }
   }
 }
 
 time_linkage *suppress_read(time_linkage *in){
-  int bypass=!(suppress_active);
+  int visible[input_ch];
+  int active[input_ch];
+  int i;
+
+  for(i=0;i<input_ch;i++){
+    visible[i]=0;
+    active[i]=suppress_active;
+  }
   
-  return subband_read(in,&sss.ss,&sss.sw,
-		      suppress_work,bypass);
+  return subband_read(in, &sss.ss, &sss.sw, visible, active, suppress_work, &sss);
 }
 
 

Modified: trunk/postfish/version.h
===================================================================
--- trunk/postfish/version.h	2004-04-22 07:37:57 UTC (rev 6572)
+++ trunk/postfish/version.h	2004-04-22 09:31:18 UTC (rev 6573)
@@ -1,2 +1,2 @@
 #define VERSION "$Id$ "
-/* DO NOT EDIT: Automated versioning hack [Sun Apr 18 22:28:48 EDT 2004] */
+/* DO NOT EDIT: Automated versioning hack [Thu Apr 22 05:28:07 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