[xiph-cvs] r6595 - trunk/postfish

xiphmont at xiph.org xiphmont at xiph.org
Tue May 4 21:27:07 PDT 2004



Author: xiphmont
Date: 2004-04-26 02:05:03 -0400 (Mon, 26 Apr 2004)
New Revision: 6595

Modified:
   trunk/postfish/Makefile
   trunk/postfish/eq.c
   trunk/postfish/eq.h
   trunk/postfish/eqpanel.c
   trunk/postfish/freq.c
   trunk/postfish/freq.h
   trunk/postfish/multicompand.c
   trunk/postfish/output.c
   trunk/postfish/version.h
Log:
Rewrite of freq.c/EQ signal path to implement muting, bypassing and smooth
transitions between settings.

Fix mute bug in subband feedback that sent visual feedback up to 0dB on mute 

<p><p>Modified: trunk/postfish/Makefile
===================================================================
--- trunk/postfish/Makefile	2004-04-25 23:28:36 UTC (rev 6594)
+++ trunk/postfish/Makefile	2004-04-26 06:05:03 UTC (rev 6595)
@@ -33,7 +33,7 @@
         $(MAKE) target CFLAGS="-pg -g -O3 -ffast-math $(GCF) $(ADD_DEF)" LIBS="-lgprof-helper"
 
 clean:
-	rm -f $(OBJ) *.d gmon.out
+	rm -f $(OBJ) *.d *.d.* gmon.out
 
 %.d: %.c
         $(CC) -M $(GCF) $< > $@.$$$$; sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; rm -f $@.$$$$

Modified: trunk/postfish/eq.c
===================================================================
--- trunk/postfish/eq.c	2004-04-25 23:28:36 UTC (rev 6594)
+++ trunk/postfish/eq.c	2004-04-26 06:05:03 UTC (rev 6595)
@@ -29,71 +29,117 @@
 
 extern int input_size;
 
-sig_atomic_t eq_active;
-sig_atomic_t eq_visible;
+typedef struct{
 
-sig_atomic_t curve_dirty=1;
+  freq_state eq;
 
-freq_state eq;
+} eq_state;
 
+eq_settings eq_master_set;
+eq_settings *eq_channel_set;
+
+static freq_class_setup fc;
+static eq_state master_state;
+static eq_state channel_state;
+
+
 /* accessed only in playback thread/setup */
-int pull_eq_feedback(float **peak,float **rms){
-  return pull_freq_feedback(&eq,peak,rms);
+int pull_eq_feedback_master(float **peak,float **rms){
+  return pull_freq_feedback(&master_state.eq,peak,rms);
 }
 
+int pull_eq_feedback_channel(float **peak,float **rms){
+  return pull_freq_feedback(&channel_state.eq,peak,rms);
+}
+
 /* called only by initial setup */
 int eq_load(void){
-  return freq_load(&eq,eq_freq_list,eq_freqs);
+  int i;
+
+  eq_channel_set=calloc(input_ch,sizeof(*eq_channel_set));
+
+  freq_class_load(&fc,eq_freq_list,eq_freqs);
+
+  freq_load(&master_state.eq,&fc);
+  freq_load(&channel_state.eq,&fc);
+
+  eq_master_set.curve_dirty=1;
+
+  for(i=0;i<input_ch;i++)
+    eq_channel_set[i].curve_dirty=1;
+
+  return 0;
 }
 
 /* called only in playback thread */
 int eq_reset(){
-  return freq_reset(&eq);
+  freq_reset(&master_state.eq);
+  freq_reset(&channel_state.eq);
+  return 0;
 }
 
-static sig_atomic_t settings[eq_freqs];
-
-void eq_set(int freq, float value){
-  settings[freq]=rint(value*10.);
-  curve_dirty=1;
+void eq_set(eq_settings *set, int freq, float value){
+  set->settings[freq]=rint(value*10.);
+  set->curve_dirty=1;
 }
  
-static float *curve_cache=0;
- 
-static void workfunc(freq_state *f,float **data,float **peak, float **rms){
-  int h,i,j;
-  float sq_mags[f->qblocksize*2+1];
+static void workfunc(float *data, eq_settings *set){
+  int i,j;
   
-  if(curve_dirty || !curve_cache){
-    curve_dirty=0;
+  if(set->curve_dirty || !set->curve_cache){
+    set->curve_dirty=0;
     
-    if(!curve_cache)curve_cache=malloc((f->qblocksize*2+1)*sizeof(*curve_cache));
-    memset(curve_cache,0,(f->qblocksize*2+1)*sizeof(*curve_cache));
+    if(!set->curve_cache)
+      set->curve_cache=malloc((fc.qblocksize*2+1)*sizeof(*set->curve_cache));
+    memset(set->curve_cache,0,(fc.qblocksize*2+1)*sizeof(*set->curve_cache));
     
     for(i=0;i<eq_freqs;i++){
-      float set=fromdB(settings[i]*.1);
-      for(j=0;j<f->qblocksize*2+1;j++)
-	curve_cache[j]+=f->ho_window[i][j]*set;
+      float v=fromdB_a(set->settings[i]*.1);
+      for(j=0;j<fc.qblocksize*2+1;j++)
+	set->curve_cache[j]+=fc.ho_window[i][j]*v;
     }
   }
   
-  for(h=0;h<input_ch;h++){
-    
-    if(eq_active){
-      
-      for(i=0;i<f->qblocksize*2+1;i++){
-	data[h][i*2]*=curve_cache[i];
-	data[h][i*2+1]*=curve_cache[i];
-      }
-    }
-    
-    freq_metric_work(data[h],f,sq_mags,peak[h],rms[h]);
+  for(i=0;i<fc.qblocksize*2+1;i++){
+    data[i*2]*=set->curve_cache[i];
+    data[i*2+1]*=set->curve_cache[i];
   }
-
+  
   return;
 }
 
+static void workfunc_ch(float *data, int ch){
+  workfunc(data,eq_channel_set+ch);
+}
+
+static void workfunc_m(float *data, int ch){
+  workfunc(data,&eq_master_set);
+}
+
 /* called only by playback thread */
-time_linkage *eq_read(time_linkage *in){
-  return freq_read(in,&eq,workfunc,!(eq_visible||eq_active));
+time_linkage *eq_read_master(time_linkage *in){
+  int active[input_ch];
+  int visible[input_ch];
+  int i;
+  
+  for(i=0;i<input_ch;i++){
+    active[i]=eq_master_set.panel_active;
+    visible[i]=eq_master_set.panel_visible;
+  }
+
+  return freq_read(in,&master_state.eq,visible,active,workfunc_m);
 }
+
+time_linkage *eq_read_channel(time_linkage *in){
+  int active[input_ch];
+  int visible[input_ch];
+  int i;
+  
+  for(i=0;i<input_ch;i++){
+    active[i]=eq_channel_set[i].panel_active;
+    visible[i]=eq_channel_set[i].panel_visible;
+  }
+
+  return freq_read(in,&master_state.eq,visible,active,workfunc_ch);
+}
+

Modified: trunk/postfish/eq.h
===================================================================
--- trunk/postfish/eq.h	2004-04-25 23:28:36 UTC (rev 6594)
+++ trunk/postfish/eq.h	2004-04-26 06:05:03 UTC (rev 6595)
@@ -25,6 +25,15 @@
 
 #define eq_freqs 30
 
+typedef struct {
+  sig_atomic_t settings[eq_freqs];
+  sig_atomic_t panel_active;
+  sig_atomic_t panel_visible;
+  sig_atomic_t curve_dirty;
+  float *curve_cache; 
+
+} eq_settings;
+
 static const float eq_freq_list[eq_freqs+1]={
   25,31.5,40,50,63,80,
   100,125,160,200,250,315,
@@ -40,8 +49,10 @@
   "8k","10k","12.5k","16k","20k"
 };
 
-extern int pull_eq_feedback(float **peak,float **rms);
+extern int pull_eq_feedback_master(float **peak,float **rms);
+extern int pull_eq_feedback_ch(float **peak,float **rms);
 extern int eq_load(void);
 extern int eq_reset();
-extern void eq_set(int freq, float value);
-extern time_linkage *eq_read(time_linkage *in);
+extern void eq_set(eq_settings *eq,int freq, float value);
+extern time_linkage *eq_read_master(time_linkage *in);
+extern time_linkage *eq_read_channel(time_linkage *in);

Modified: trunk/postfish/eqpanel.c
===================================================================
--- trunk/postfish/eqpanel.c	2004-04-25 23:28:36 UTC (rev 6594)
+++ trunk/postfish/eqpanel.c	2004-04-26 06:05:03 UTC (rev 6595)
@@ -32,12 +32,13 @@
 #include "freq.h"
 #include "eq.h"
 
-extern sig_atomic_t eq_active;
-extern sig_atomic_t eq_visible;
 extern int input_ch;
 extern int input_size;
 extern int input_rate;
 
+extern eq_settings eq_master_set;
+extern eq_settings *eq_channel_set;
+
 typedef struct {
   GtkWidget *slider;
   GtkWidget *readout;
@@ -54,7 +55,7 @@
   sprintf(buffer,"%+3.0fdB",val);
   readout_set(READOUT(b->readout),buffer);
   
-  eq_set(b->number,val);
+  eq_set(&eq_master_set,b->number,val);
 
 }
 
@@ -69,8 +70,8 @@
   char *shortcut[]={" e "};
 
   subpanel_generic *panel=subpanel_create(mp,windowbutton,&activebutton,
-					  &eq_active,
-					  &eq_visible,
+					  &eq_master_set.panel_active,
+					  &eq_master_set.panel_visible,
                                           "_Equalization filter",shortcut,
                                           0,1);
   
@@ -122,10 +123,10 @@
     }
   }
   
-  if(pull_eq_feedback(peakfeed,rmsfeed)==1)
+  if(pull_eq_feedback_master(peakfeed,rmsfeed)==1)
     for(i=0;i<eq_freqs;i++)
       multibar_set(MULTIBAR(bars[i].slider),rmsfeed[i],peakfeed[i],
-		   input_ch,(displayit && eq_visible));
+		   input_ch,(displayit && eq_master_set.panel_visible));
   
 }
 

Modified: trunk/postfish/freq.c
===================================================================
--- trunk/postfish/freq.c	2004-04-25 23:28:36 UTC (rev 6594)
+++ trunk/postfish/freq.c	2004-04-26 06:05:03 UTC (rev 6595)
@@ -41,10 +41,7 @@
 } freq_feedback;
 
 static feedback_generic *new_freq_feedback(void){
-  freq_feedback *ret=malloc(sizeof(*ret));
-  ret->peak=calloc(input_ch,sizeof(*ret->peak));
-  ret->rms=calloc(input_ch,sizeof(*ret->rms));
-
+  freq_feedback *ret=calloc(1,sizeof(*ret));
   return (feedback_generic *)ret;
 }
 
@@ -52,7 +49,7 @@
 
 int pull_freq_feedback(freq_state *ff,float **peak,float **rms){
   freq_feedback *f=(freq_feedback *)feedback_pull(&ff->feedpool);
-  int i,j;
+  int i;
   
   if(!f)return 0;
   
@@ -61,21 +58,17 @@
     return 2;
   }else{
     if(peak)
-      for(i=0;i<ff->bands;i++)
-	for(j=0;j<input_ch;j++)
-	  peak[i][j]=f->peak[j][i];
-    
+      for(i=0;i<ff->fc->bands;i++)
+	memcpy(peak[i],f->peak[i],sizeof(**peak)*input_ch);
     if(rms)
-      for(i=0;i<ff->bands;i++)
-	for(j=0;j<input_ch;j++)
-	  rms[i][j]=f->rms[j][i];
+      for(i=0;i<ff->fc->bands;i++)
+	memcpy(rms[i],f->rms[i],sizeof(**rms)*input_ch);
     feedback_old(&ff->feedpool,(feedback_generic *)f);
     return 1;
   }
 }
 
-/* called only by initial setup */
-int freq_load(freq_state *f,const float *frequencies, int bands){
+int freq_class_load(freq_class_setup *f,const float *frequencies, int bands){
   int i,j;
   int blocksize=input_size*2;
   memset(f,0,sizeof(*f));
@@ -83,22 +76,6 @@
   f->qblocksize=input_size;
   f->bands=bands;
 
-  f->fillstate=0;
-  f->cache_samples=0;
-  f->cache=malloc(input_ch*sizeof(*f->cache));
-  for(i=0;i<input_ch;i++)
-    f->cache[i]=calloc(input_size,sizeof(**f->cache));
-  f->lap=malloc(input_ch*sizeof(*f->lap));
-  for(i=0;i<input_ch;i++)
-    f->lap[i]=calloc(f->qblocksize*3,sizeof(**f->lap));
-
-  f->out.size=input_size;
-  f->out.channels=input_ch;
-  f->out.rate=input_rate;
-  f->out.data=malloc(input_ch*sizeof(*f->out.data));
-  for(i=0;i<input_ch;i++)
-    f->out.data[i]=malloc(input_size*sizeof(**f->out.data));
-
   /* fill in time window */
   f->window=malloc(blocksize*sizeof(*f->window)); 
   for(i=0;i<blocksize;i++)f->window[i]=sin(M_PIl*i/blocksize);
@@ -106,23 +83,18 @@
   for(i=0;i<blocksize;i++)f->window[i]=sin(f->window[i]*M_PIl*.5);
   for(i=0;i<blocksize;i++)f->window[i]*=f->window[i];
 
-  f->fftwf_buffer = fftwf_malloc(sizeof(*f->fftwf_buffer) * input_ch);
-  f->fftwf_backward = fftwf_malloc(sizeof(*f->fftwf_backward) * input_ch);
-  f->fftwf_forward = fftwf_malloc(sizeof(*f->fftwf_forward) * input_ch);
-  for(i=0;i<input_ch;i++){
-    f->fftwf_buffer[i] = fftwf_malloc(sizeof(**f->fftwf_buffer) * 
-				  (f->qblocksize*4+2));
+  f->fftwf_buffer = fftwf_malloc(sizeof(*f->fftwf_buffer) * 
+				 (f->qblocksize*4+2));
     
-    f->fftwf_forward[i]=fftwf_plan_dft_r2c_1d(f->qblocksize*4, 
-					      f->fftwf_buffer[i],
-					      (fftwf_complex *)(f->fftwf_buffer[i]), 
-					      FFTW_MEASURE);
-    
-    f->fftwf_backward[i]=fftwf_plan_dft_c2r_1d(f->qblocksize*4,
-					       (fftwf_complex *)(f->fftwf_buffer[i]), 
-					       f->fftwf_buffer[i], 
-					       FFTW_MEASURE);
-  }
+  f->fftwf_forward=fftwf_plan_dft_r2c_1d(f->qblocksize*4, 
+					 f->fftwf_buffer,
+					 (fftwf_complex *)(f->fftwf_buffer), 
+					 FFTW_MEASURE);
+  
+  f->fftwf_backward=fftwf_plan_dft_c2r_1d(f->qblocksize*4,
+					  (fftwf_complex *)(f->fftwf_buffer), 
+					  f->fftwf_buffer, 
+					  FFTW_MEASURE);
 
   /* unlike old postfish, we offer all frequencies via smoothly
      supersampling the spectrum */
@@ -167,38 +139,38 @@
 
       /* window this desired response in the time domain so that our
          convolution is properly padded against being circular */
-      memset(f->fftwf_buffer[0],0,sizeof(**f->fftwf_buffer)*
+      memset(f->fftwf_buffer,0,sizeof(*f->fftwf_buffer)*
              (f->qblocksize*4+2));
       for(j=0;j<f->qblocksize*2;j++)
-	f->fftwf_buffer[0][j*2]=working[j];
+	f->fftwf_buffer[j*2]=working[j];
       
-      fftwf_execute(f->fftwf_backward[0]);
+      fftwf_execute(f->fftwf_backward);
 
       /* window response in time */
       for(j=0;j<f->qblocksize;j++){
         float val=cos(j*M_PI/(f->qblocksize*2));
         val=sin(val*val*M_PIl*.5);
-	f->fftwf_buffer[0][j]*= sin(val*val*M_PIl*.5);
+	f->fftwf_buffer[j]*= sin(val*val*M_PIl*.5);
       }
 
       for(;j<f->qblocksize*3;j++)
-	f->fftwf_buffer[0][j]=0.;
+	f->fftwf_buffer[j]=0.;
       
       for(;j<f->qblocksize*4;j++){
         float val=sin((j-f->qblocksize*3)*M_PI/(f->qblocksize*2));
         val=sin(val*val*M_PIl*.5);
-	f->fftwf_buffer[0][j]*=sin(val*val*M_PIl*.5);
+	f->fftwf_buffer[j]*=sin(val*val*M_PIl*.5);
       }
 
       /* back to frequency; this is all-real data still */
-      fftwf_execute(f->fftwf_forward[0]);
+      fftwf_execute(f->fftwf_forward);
       for(j=0;j<f->qblocksize*4+2;j++)
-	f->fftwf_buffer[0][j]/=f->qblocksize*4;
+	f->fftwf_buffer[j]/=f->qblocksize*4;
       
       /* now take what we learned and distill it a bit */
       f->ho_window[i]=calloc((f->qblocksize*2+1),sizeof(**f->ho_window));
       for(j=0;j<f->qblocksize*2+1;j++){
-	f->ho_window[i][j]=f->fftwf_buffer[0][j*2];
+	f->ho_window[i][j]=f->fftwf_buffer[j*2];
         f->ho_area[i]+=fabs(f->ho_window[i][j]);
       }
       f->ho_area[i]=1./f->ho_area[i];
@@ -208,6 +180,54 @@
     }
   }
 
+  return 0;
+
+}
+
+/* called only by initial setup */
+int freq_load(freq_state *f,freq_class_setup *fc){
+  int i;
+  memset(f,0,sizeof(*f));
+
+  f->fc=fc;
+
+  f->fillstate=0;
+  f->cache_samples=0;
+  f->cache1=malloc(input_ch*sizeof(*f->cache1));
+  f->cache0=malloc(input_ch*sizeof(*f->cache0));
+  for(i=0;i<input_ch;i++){
+    f->cache1[i]=calloc(input_size,sizeof(**f->cache1));
+    f->cache0[i]=calloc(input_size,sizeof(**f->cache0));
+  }
+
+  f->activeP=malloc(input_ch*sizeof(*f->activeP));
+  f->active1=malloc(input_ch*sizeof(*f->active1));
+  f->active0=malloc(input_ch*sizeof(*f->active0));
+
+
+  f->lap1=malloc(input_ch*sizeof(*f->lap1));
+  f->lap0=malloc(input_ch*sizeof(*f->lap0));
+  f->lapC=malloc(input_ch*sizeof(*f->lapC));
+  for(i=0;i<input_ch;i++){
+    f->lap1[i]=calloc(fc->qblocksize,sizeof(**f->lap1));
+    f->lap0[i]=calloc(fc->qblocksize,sizeof(**f->lap0));
+    f->lapC[i]=calloc(fc->qblocksize,sizeof(**f->lapC));
+  }
+
+  f->peak=malloc(fc->bands*sizeof(*f->peak));
+  f->rms=malloc(fc->bands*sizeof(*f->rms));
+  for(i=0;i<fc->bands;i++){
+    f->peak[i]=malloc(input_ch*sizeof(**f->peak));
+    f->rms[i]=malloc(input_ch*sizeof(**f->rms));
+  }
+
+  f->out.size=input_size;
+  f->out.channels=input_ch;
+  f->out.rate=input_rate;
+  f->out.data=malloc(input_ch*sizeof(*f->out.data));
+  for(i=0;i<input_ch;i++)
+    f->out.data[i]=malloc(input_size*sizeof(**f->out.data));
+  
   return(0);
 }
 
@@ -219,140 +239,255 @@
   return 0;
 }
 
-void freq_metric_work(float *work,freq_state *f,
-		      float *sq_mags,float *peak,float *rms){
+static void freq_metric_work(float *x,freq_class_setup *c,
+			     float **peak,float **rms,int channel){
   int i,j;
-
-  /* fill in metrics */
-  memset(peak,0,sizeof(*peak)*f->bands);
-  memset(rms,0,sizeof(*rms)*f->bands);
-
-  for(i=0;i<f->qblocksize*2+1;i++)
-    sq_mags[i]=(work[i*2]*work[i*2]+work[i*2+1]*work[i*2+1])*64.;
+  float sq_mags[c->qblocksize*2+1];
   
-  for(i=0;i<f->bands;i++){
-    float *ho_window=f->ho_window[i];
-    for(j=0;j<f->qblocksize*2+1;j++){
+  for(i=0;i<c->qblocksize*2+1;i++)
+    sq_mags[i]=(x[i*2]*x[i*2]+x[i*2+1]*x[i*2+1])*64.;
+  
+  for(i=0;i<c->bands;i++){
+    float *ho_window=c->ho_window[i];
+    float lrms=0.;
+    float lpeak=0.;
+    for(j=0;j<c->qblocksize*2+1;j++){
       float val=fabs(sq_mags[j]*ho_window[j]);
-
-      rms[i]+=val*.5;
-      if(val>peak[i])peak[i]=val;
+      lrms+=val*.5;
+      if(val>lpeak)lpeak=val;
     }
-    rms[i]=sqrt(rms[i]*f->ho_area[i]);
-    peak[i]=sqrt(peak[i]);
+    rms[i][channel]=todB(lrms*c->ho_area[i])*.5;
+    peak[i][channel]=todB(lpeak)*.5;
   }
-
 }
 
-static void feedback_work(freq_state *f,float *peak,float *rms,
-			  float *feedback_peak,float *feedback_rms){
+static void fill_freq_buffer_helper(float *buffer,float *window,
+				    float *cache, float *in,
+				    int qblocksize,int muted0,int mutedC,
+				    float scale){
   int i;
-  for(i=0;i<f->bands;i++){
-    feedback_rms[i]+=rms[i]*rms[i];
-    if(feedback_peak[i]<peak[i])feedback_peak[i]=peak[i];
-  }
-}
+  
+  /* place data in fftwf buffer */
+  memset(buffer,0,sizeof(*buffer)*qblocksize);
 
-static void lap_bypass(float *cache,float *in,float *lap,float *out,freq_state *f){
-  int i,j;
-  if(out){
-    /* we're bypassing, so the input data hasn't spread from the half->block window.
-       The lap may well be spread though, so we can't cheat and ignore the last third */
-    for(i=0;i<f->qblocksize;i++)
-      out[i]=lap[i];
-  }
+  if(muted0)
+    memset(buffer+qblocksize,0,sizeof(*buffer)*qblocksize);
+  else
+    memcpy(buffer+qblocksize,cache,sizeof(*buffer)*qblocksize);
 
-  /* keep lap up to date; bypassed data has not spread from the half-block padded window */
-  for(i=0;i<f->qblocksize;i++)
-    lap[i]=lap[i+f->qblocksize]+cache[i]*f->window[i];
+  if(mutedC)
+    memset(buffer+qblocksize*2,0,sizeof(*buffer)*qblocksize);
+  else
+    memcpy(buffer+qblocksize*2,in,sizeof(*buffer)*qblocksize);
+  
+  memset(buffer+qblocksize*3,0,sizeof(*buffer)*qblocksize);
 
-  for(j=0;i<f->qblocksize*2;i++,j++)
-    lap[i]=lap[i+f->qblocksize]+in[j]*f->window[i];
-
-  memset(lap+f->qblocksize*2,0,f->qblocksize*sizeof(*lap));
+  /* window (if nonzero) */
+  if(!muted0 || !mutedC){
+    buffer+=qblocksize;
+    for(i=0;i<qblocksize*2;i++)
+      buffer[i] *= window[i]*scale;
+  }
 }
 
-static void lap_work(float *work,float *lap,float *out,freq_state *f){
+static void freq_work(freq_class_setup *fc,
+		      freq_state *f,
+		      time_linkage *in,
+		      time_linkage *out,
+		      int      *visible,
+		      int      *active,
+		      void (*func)(float *,int)){
+  
   int i,j;
+  int have_feedback=0;
   
-  /* lap and out */
-  if(out)
-    for(i=0;i<f->qblocksize;i++)
-      out[i]=lap[i]+work[i];
-  
-  for(i=f->qblocksize,j=0;i<f->qblocksize*3;i++,j++)
-    lap[j]=lap[i]+work[i];
-  
-  for(;i<f->qblocksize*4;i++,j++)
-    lap[j]=work[i];
-  
-}
+  f->cache_samples+=in->samples;
 
-static void freq_transwork(freq_state *f,time_linkage *in){
-  int i,j;
   for(i=0;i<input_ch;i++){
-    /* extrapolation mechanism; avoid harsh transients at edges */
-    if(f->fillstate==0)
-      preextrapolate_helper(in->data[i],input_size,
-			    f->cache[i],input_size);
+    int mutedC=mute_channel_muted(in->active,i);
+    int muted0=mute_channel_muted(f->mutemask0,i);
+
+    int activeC=active[i] && !(muted0 && mutedC);
+    int active0=f->active0[i];
+    int active1=f->active1[i];
+    int activeP=f->activeP[i];
     
-    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);
+    /* zero the feedback */
+    for(j=0;j<fc->bands;j++){
+      f->peak[j][i]=-150.;
+      f->rms[j][i]=-150.;
+    }
     
-    memset(f->fftwf_buffer[i],0,
-	   sizeof(**f->fftwf_buffer)*f->qblocksize);
+    /* processing pathway depends on active|visible.  If we're visible & !active, the transform 
+       data is thrown away without being manipulated or used in output (it is merely measured) */
+    int trans_active= (visible[i] || active[i]) && !(muted0 && mutedC);
+
+    if(trans_active){
+      
+      /* pre- and post-extrapolate to avoid harsh edge features.
+         Account for muting in previous or current frame */
+      if(f->fillstate==0){
+	if(mutedC)memset(in->data[i],0,sizeof(**in->data)*input_size);
+	if(muted0)memset(f->cache0[i],0,sizeof(**f->cache0)*input_size);
+	preextrapolate_helper(in->data[i],input_size,
+			      f->cache0[i],input_size);
+      }
     
-    memcpy(f->fftwf_buffer[i]+f->qblocksize,
-	   f->cache[i],
-	   sizeof(**f->fftwf_buffer)*f->qblocksize);
+      if(in->samples<in->size){
+	if(mutedC)memset(in->data[i],0,sizeof(**in->data)*input_size);
+	if(muted0)memset(f->cache0[i],0,sizeof(**f->cache0)*input_size);
+
+	postextrapolate_helper(f->cache0[i],input_size,
+			       in->data[i],in->samples,
+			       in->data[i]+in->samples,
+			       in->size-in->samples);
+      }
+
+      fill_freq_buffer_helper(fc->fftwf_buffer,
+			      fc->window,
+			      f->cache0[i],in->data[i],
+			      fc->qblocksize,muted0,mutedC,
+			      .25/fc->qblocksize);
+
+      /* transform the time data */
+      fftwf_execute(fc->fftwf_forward);
+
+      if(activeC)func(fc->fftwf_buffer,i);
+      
+      /* feedback and reverse transform */
+      have_feedback=1;
+      freq_metric_work(fc->fftwf_buffer,fc,f->peak,f->rms,i);
+      if(activeC)
+	fftwf_execute(fc->fftwf_backward);
+      else
+	trans_active=0;
+
+    }else{
+      if(visible[i]){
+	/* push zeroed feedback */
+	have_feedback=1;
+      } /* else bypass feedback */
+    }
+
+    /* output data pathway depends on activity over the past four
+       frames (including this one); draw from transform (if any) and
+       lap, cache and lap, or just cache? */
+    if(!activeP && !active1 && !active0 && !activeC){
+      /* bypass; rotate the cache */
+      
+      if(out){
+	float *temp=out->data[i];
+	out->data[i]=f->cache1[i];
+	f->cache1[i]=temp;
+      }
+    }else{
+      float *w2=fc->window+input_size;
+      float *l0=f->lap0[i];
+      float *l1=f->lap1[i];
+      float *lC=f->lapC[i];
+      float *c0=f->cache0[i];
+      float *c1=f->cache1[i];
+
+      float *t1=fc->fftwf_buffer;
+      float *t0=t1+input_size;
+      float *tC=t0+input_size;
+      float *tN=tC+input_size;
+
+      if(!trans_active){
+	/* lap the cache into the trasform vector */
+	fill_freq_buffer_helper(fc->fftwf_buffer,
+				fc->window,
+				f->cache0[i],in->data[i],
+				fc->qblocksize,muted0,mutedC,1.);
+      }
+
+      if(!activeP && !active1 && !active0){
+	/* previously in a bypassed/inactive state; the lapping cache
+           will need to be re-prepared */
+	
+	memcpy(l1,c1,sizeof(*l1)*input_size);
+	for(j=0;j<input_size;j++)
+	  l0[j]= c0[j]*w2[j];
+	memset(lC,0,sizeof(*lC)*input_size);
+	
+      }
+
+      if(out){
+	float *ox=out->data[i];
+	
+	for(j=0;j<input_size;j++)
+	  ox[j]= l1[j]+t1[j];
+      }
+
+      for(j=0;j<input_size;j++){
+	l1[j]= l0[j]+t0[j];
+	l0[j]= lC[j]+tC[j];
+	lC[j]= tN[j];
+      }
+    }
+
+    f->activeP[i]=active1;
+    f->active1[i]=active0;
+    f->active0[i]=activeC;
     
-    memcpy(f->fftwf_buffer[i]+f->qblocksize*2,
-	   in->data[i],
-	   sizeof(**f->fftwf_buffer)*f->qblocksize);
+    {
+      float *temp=f->cache1[i];
+      f->cache1[i]=f->cache0[i];
+      f->cache0[i]=in->data[i];
+      in->data[i]=temp;
+    }
+  }
+
+  /* log feedback metrics; this logs one for every call, rather than
+   every output; that's fine; nothing flushes until first output, and
+   any playback halt will kill off stragglers.  Sync is unaffected. */
+  if(have_feedback){
+    freq_feedback *ff=
+      (freq_feedback *)feedback_new(&f->feedpool,new_freq_feedback);
     
-    memset(f->fftwf_buffer[i]+f->qblocksize*3,0,
-	   sizeof(**f->fftwf_buffer)*f->qblocksize);
-    
-    for(j=0;j<f->qblocksize*2;j++)
-      f->fftwf_buffer[i][j+f->qblocksize]*=.25*f->window[j]/f->qblocksize;
-    /* transform the time data */
-    
-    fftwf_execute(f->fftwf_forward[i]);
+    if(!ff->peak){
+      ff->peak=calloc(fc->bands,sizeof(*ff->peak));
+      for(i=0;i<fc->bands;i++)
+	ff->peak[i]=malloc(input_ch*sizeof(**ff->peak));
+    }
+    if(!ff->rms){
+      ff->rms=calloc(fc->bands,sizeof(*ff->rms));
+      for(i=0;i<fc->bands;i++)
+	ff->rms[i]=malloc(input_ch*sizeof(**ff->rms));
+    }
+
+    for(i=0;i<fc->bands;i++){
+      memcpy(ff->peak[i],f->peak[i],input_ch*sizeof(**f->peak));
+      memcpy(ff->rms[i],f->rms[i],input_ch*sizeof(**f->rms));
+    } 
+    ff->bypass=0;
+    feedback_push(&f->feedpool,(feedback_generic *)ff);
+  }else{
+    freq_feedback *ff=
+      (freq_feedback *)feedback_new(&f->feedpool,new_freq_feedback);
+    ff->bypass=1;
+    feedback_push(&f->feedpool,(feedback_generic *)ff);
   }
+
+  /* complete output linkage */
+  if(out){
+    out->active=f->mutemask1;
+    f->out.samples=(f->cache_samples>input_size?input_size:f->cache_samples);
+    f->cache_samples-=f->out.samples;
+  }
+
+  f->mutemaskP=f->mutemask1;
+  f->mutemask1=f->mutemask0;
+  f->mutemask0=in->active;
 }
 
-
 /* called only by playback thread */
 time_linkage *freq_read(time_linkage *in, freq_state *f,
-			void (*func)(freq_state *f,float **data,
-				     float **peak, float **rms),
-			int bypass){
+			int *visible, int *active,
+			void (*func)(float *,int i)){
   int i;
+  freq_class_setup *fc=f->fc;
 
-  float feedback_peak[input_ch][f->bands];
-  float feedback_rms[input_ch][f->bands];
-
-  float peak[input_ch][f->bands];
-  float rms[input_ch][f->bands];
-
-  float *peakp[input_ch];
-  float *rmsp[input_ch];
-  
-  int blocks=0;
-
-  if(!bypass){
-    memset(feedback_peak,0,sizeof(feedback_peak));
-    memset(feedback_rms,0,sizeof(feedback_rms));
-  }
-
-  for(i=0;i<input_ch;i++){
-    peakp[i]=peak[i];
-    rmsp[i]=rms[i];
-  }
-  
   switch(f->fillstate){
   case 0: /* prime the lapping and cache */
     if(in->samples==0){
@@ -360,44 +495,22 @@
       return &f->out;
     }
 
-    /* zero out lapping and cacahe state */
+    /* zero out lapping and cache state */
     for(i=0;i<input_ch;i++){
-      memset(f->lap[i],0,sizeof(**f->lap)*f->qblocksize*3);
-      memset(f->cache[i],0,sizeof(**f->cache)*input_size);
+      memset(f->lap1[i],0,sizeof(**f->lap1)*fc->qblocksize);
+      memset(f->lap0[i],0,sizeof(**f->lap0)*fc->qblocksize);
+      memset(f->cache0[i],0,sizeof(**f->cache0)*input_size);
+      memset(f->cache1[i],0,sizeof(**f->cache1)*input_size);
+      f->activeP[i]=active[i];
+      f->active1[i]=active[i];
+      f->active0[i]=active[i];
     }
 
-    if(bypass){
-      /* no need to do extra work; the panel is invisible (so no need
-         to collect metrics) and the effect is inactive.  Just keep
-         lapping state up to date and pass the data through.  Why
-         bother with lapping?  We don't want a 'pop' when the effect
-         is activated/deactivated */
+    f->cache_samples=0;
+    f->mutemask0=f->mutemask1=f->mutemaskP=in->active;
+    
+    freq_work(fc,f,in,0,visible,active,func);
 
-      for(i=0;i<input_ch;i++)
-	lap_bypass(f->cache[i],in->data[i],f->lap[i],0,f);
-
-    }else{
-
-      freq_transwork(f,in);
-      func(f,f->fftwf_buffer,peakp,rmsp);
-      blocks++;	
-      
-      for(i=0;i<input_ch;i++){
-	feedback_work(f,peak[i],rms[i],feedback_peak[i],feedback_rms[i]);
-	fftwf_execute(f->fftwf_backward[i]);
-	lap_work(f->fftwf_buffer[i],f->lap[i],0,f);
-	
-      }
-    }
-
-    for(i=0;i<input_ch;i++){
-      float *temp=in->data[i];
-      memset(f->cache[i],0,sizeof(**f->cache)*input_size);
-      in->data[i]=f->cache[i];
-      f->cache[i]=temp;
-    }
-      
-    f->cache_samples=in->samples;
     f->fillstate=1;
     f->out.samples=0;
     if(in->samples==in->size)goto tidy_up;
@@ -409,31 +522,8 @@
     
   case 1: /* finish priming the lapping and cache */
 
-    if(bypass){
-      for(i=0;i<input_ch;i++)
-	lap_bypass(f->cache[i],in->data[i],f->lap[i],0,f);
-    }else{
-
-      freq_transwork(f,in);
-      func(f,f->fftwf_buffer,peakp,rmsp);
-      blocks++;	
-      
-      for(i=0;i<input_ch;i++){
-	feedback_work(f,peak[i],rms[i],feedback_peak[i],feedback_rms[i]);
-	fftwf_execute(f->fftwf_backward[i]);
-	lap_work(f->fftwf_buffer[i],f->lap[i],0,f);
-	
-      }
-    }
-
-    for(i=0;i<input_ch;i++){
-      float *temp=in->data[i];
-      memset(f->cache[i],0,sizeof(**f->cache)*input_size);
-      in->data[i]=f->cache[i];
-      f->cache[i]=temp;
-    }
-      
-    f->cache_samples+=in->samples;
+    freq_work(fc,f,in,0,visible,active,func);
+    
     f->fillstate=2;
     f->out.samples=0;
     if(in->samples==in->size)goto tidy_up;
@@ -445,72 +535,14 @@
     
   case 2: /* nominal processing */
 
-    if(bypass){
-      for(i=0;i<input_ch;i++)
-	lap_bypass(f->cache[i],in->data[i],f->lap[i],f->out.data[i],f);
+    freq_work(fc,f,in,&f->out,visible,active,func);
 
-    }else{
-
-      freq_transwork(f,in);
-      func(f,f->fftwf_buffer,peakp,rmsp);
-      blocks++;	
-      
-      for(i=0;i<input_ch;i++){
-	feedback_work(f,peak[i],rms[i],feedback_peak[i],feedback_rms[i]);
-	fftwf_execute(f->fftwf_backward[i]);
-	lap_work(f->fftwf_buffer[i],f->lap[i],f->out.data[i],f);
-	
-      }
-    }
-
-    for(i=0;i<input_ch;i++){
-      float *temp=f->cache[i];
-      f->cache[i]=in->data[i];
-      in->data[i]=temp;
-    }
-
-    f->cache_samples+=in->samples;
-    f->out.samples=(f->cache_samples>input_size?input_size:f->cache_samples);
-    f->cache_samples-=f->out.samples;
     if(f->out.samples<f->out.size)f->fillstate=3;
     break;
   case 3: /* we've pushed out EOF already */
     f->out.samples=0;
   }
   
-  /* finish up the state feedabck */
-  if(!bypass && blocks){
-    int j;
-    float scale=1./blocks;
-    freq_feedback *ff=
-      (freq_feedback *)feedback_new(&f->feedpool,new_freq_feedback);
-
-    if(!ff->peak[0])
-      for(i=0;i<input_ch;i++)
-	ff->peak[i]=malloc(f->bands*sizeof(**ff->peak));
-    if(!ff->rms[0])
-      for(i=0;i<input_ch;i++)
-	ff->rms[i]=malloc(f->bands*sizeof(**ff->rms));
-
-    for(i=0;i<input_ch;i++)
-      for(j=0;j<f->bands;j++){
-	feedback_rms[i][j]=todB(sqrt(feedback_rms[i][j]*scale));
-	feedback_peak[i][j]=todB(feedback_peak[i][j]);
-      }
-      
-    for(i=0;i<input_ch;i++){
-      memcpy(ff->peak[i],feedback_peak[i],f->bands*sizeof(**feedback_peak));
-      memcpy(ff->rms[i],feedback_rms[i],f->bands*sizeof(**feedback_rms));
-    } 
-    ff->bypass=0;
-    feedback_push(&f->feedpool,(feedback_generic *)ff);
-  }else{
-    freq_feedback *ff=
-      (freq_feedback *)feedback_new(&f->feedpool,new_freq_feedback);
-    ff->bypass=1;
-    feedback_push(&f->feedpool,(feedback_generic *)ff);
-  }
-
  tidy_up:
   {
     int tozero=f->out.size-f->out.samples;
@@ -518,6 +550,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/freq.h
===================================================================
--- trunk/postfish/freq.h	2004-04-25 23:28:36 UTC (rev 6594)
+++ trunk/postfish/freq.h	2004-04-26 06:05:03 UTC (rev 6595)
@@ -25,12 +25,9 @@
 #include <fftw3.h>
 
 typedef struct {
-  time_linkage out;
-  feedback_generic_pool feedpool;
-
-  float **fftwf_buffer; // need one for each channel
-  fftwf_plan *fftwf_forward;   // need one for each channel
-  fftwf_plan *fftwf_backward;  // need one for each channel
+  float       *fftwf_buffer; 
+  fftwf_plan  fftwf_forward; 
+  fftwf_plan  fftwf_backward;
   
   int qblocksize;
   int bands;
@@ -39,24 +36,45 @@
   float  *ho_area;
   
   float *window;
-  float **lap;
-  float **cache;
+} freq_class_setup;
+
+
+typedef struct {
+  time_linkage out;
+  feedback_generic_pool feedpool;
+  freq_class_setup *fc;
+
+  int *activeP;
+  int *active1;
+  int *active0;
+
+  u_int32_t mutemask0;
+  u_int32_t mutemask1;
+  u_int32_t mutemaskP;
+
+  float **lap1;
+  float **lap0;
+  float **lapC;
+
+  float **cache1;
+  float **cache0;
   int cache_samples;
   int fillstate;     /* 0: uninitialized
                         1: half-primed
                         2: nominal
                         3: eof processed */
+  float **peak;
+  float **rms;
 } freq_state;
 
-extern void freq_transform_work(float *work,freq_state *f);
+
+
 extern int pull_freq_feedback(freq_state *ff,float **peak,float **rms);
-extern int freq_load(freq_state *f,const float *frequencies, int bands);
+extern int freq_class_load(freq_class_setup *f,const float *frequencies, int bands);
+extern int freq_load(freq_state *f,freq_class_setup *fc);
+
 extern int freq_reset(freq_state *f);
-extern time_linkage *freq_read(time_linkage *in, freq_state *f,
-			       void (*func)(freq_state *f,
-					    float **data,
-					    float **peak, float **rms),
-			       int bypassp);
-
-extern void freq_metric_work(float *work,freq_state *f,
-			     float *sq_mags,float *peak,float *rms);
+extern time_linkage *freq_read(time_linkage *in, 
+			       freq_state *f, 
+			       int *visible, int *active,
+			       void (*func)(float *,int i));

Modified: trunk/postfish/multicompand.c
===================================================================
--- trunk/postfish/multicompand.c	2004-04-25 23:28:36 UTC (rev 6594)
+++ trunk/postfish/multicompand.c	2004-04-26 06:05:03 UTC (rev 6595)
@@ -526,12 +526,14 @@
 
 static void multicompand_work_master(void *vs){
   multicompand_state *ms=(multicompand_state *)vs;
-  int i,bypass_visible=1;
+  int i,j,bypass_visible=1;
   int maxmaxbands=0;
 
   for(i=0;i<multicomp_freqs_max;i++){
-    memset(ms->peak[i],0,input_ch*sizeof(**ms->peak));
-    memset(ms->rms[i],0,input_ch*sizeof(**ms->rms));
+    for(j=0;j<input_ch;j++){
+      ms->peak[i][j]=-150.;
+      ms->rms[i][j]=-150;
+    }
   }
  
   for(i=0;i<input_ch;i++){
@@ -546,12 +548,14 @@
 
 static void multicompand_work_channel(void *vs){
   multicompand_state *ms=(multicompand_state *)vs;
-  int i,bypass_visible=1;
+  int i,j,bypass_visible=1;
   int maxmaxbands=0;
 
   for(i=0;i<multicomp_freqs_max;i++){
-    memset(ms->peak[i],0,input_ch*sizeof(**ms->peak));
-    memset(ms->rms[i],0,input_ch*sizeof(**ms->rms));
+    for(j=0;j<input_ch;j++){
+      ms->peak[i][j]=-150.;
+      ms->rms[i][j]=-150;
+    }
   }
  
   for(i=0;i<input_ch;i++){

Modified: trunk/postfish/output.c
===================================================================
--- trunk/postfish/output.c	2004-04-25 23:28:36 UTC (rev 6594)
+++ trunk/postfish/output.c	2004-04-26 06:05:03 UTC (rev 6595)
@@ -250,11 +250,7 @@
     link=singlecomp_read_master(link);
     result|=link->samples;
 
-    for(i=0;i<input_ch;i++)
-      if(mute_channel_muted(link->active,i))
-	memset(link->data[i],0,sizeof(**link->data)*input_size);
-
-    link=eq_read(link);
+    link=eq_read_master(link);
     result|=link->samples;
     
     if(!result)break;
@@ -271,6 +267,10 @@
 
 
     /* the limiter is single-block zero additional latency */
+    for(i=0;i<input_ch;i++)
+      if(mute_channel_muted(link->active,i))
+	memset(link->data[i],0,sizeof(**link->data)*input_size);
+
     link=limit_read(link);
 
     /************/
@@ -392,6 +392,7 @@
     } 
     fclose(playback_fd);
   }
+  pipeline_reset();
   playback_active=0;
   playback_exit=0;
   if(audiobuf)free(audiobuf);

Modified: trunk/postfish/version.h
===================================================================
--- trunk/postfish/version.h	2004-04-25 23:28:36 UTC (rev 6594)
+++ trunk/postfish/version.h	2004-04-26 06:05:03 UTC (rev 6595)
@@ -1,2 +1,2 @@
 #define VERSION "$Id$ "
-/* DO NOT EDIT: Automated versioning hack [Sat Apr 24 01:12:30 EDT 2004] */
+/* DO NOT EDIT: Automated versioning hack [Mon Apr 26 02:02:47 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