[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