diff --git a/Makefile b/Makefile index 887859b45fe54f485e885bd511a3352236583c94..cbd239a8aa2c235adc0e699c65b6445a381f6957 100644 --- a/Makefile +++ b/Makefile @@ -2,26 +2,34 @@ # Fuck the horse it rode in on # and Fuck its little dog Libtool too -ADD_DEF= -DUGLY_IEEE754_FLOAT32_HACK=1 + +ADD_DEF= -DUGLY_IEEE754_FLOAT32_HACK=1 -maltivec + +# use for PPC with altivec. IF YOU HAVE ALTIVEC, YOU MUST USE THIS +# LINE, otherwise FFTW3 will randomly crash whenever it uses Altivec +# and any math denormalizes. + +#ADD_DEF= -DUGLY_IEEE754_FLOAT32_HACK=1 -maltivec + CC=gcc LD=gcc INSTALL=install PREFIX=/usr/local BINDIR=$PREFIX/bin -ETCDIR=/etc +ETCDIR=/etc/postfish MANDIR=$PREFIX/man SRC = main.c mainpanel.c multibar.c readout.c input.c output.c clippanel.c \ declip.c reconstruct.c multicompand.c windowbutton.c subpanel.c \ feedback.c freq.c eq.c eqpanel.c compandpanel.c subband.c lpc.c \ bessel.c suppresspanel.c suppress.c singlecomp.c singlepanel.c \ - limit.c limitpanel.c mute.c mutedummy.c + limit.c limitpanel.c mute.c mixpanel.c mix.c reverb.c OBJ = main.o mainpanel.o multibar.o readout.o input.o output.o clippanel.o \ declip.o reconstruct.o multicompand.o windowbutton.o subpanel.o \ feedback.o freq.o eq.o eqpanel.o compandpanel.o subband.o lpc.o \ bessel.o suppresspanel.o suppress.o singlecomp.o singlepanel.o \ - limit.o limitpanel.o mute.o mutedummy.o -GCF = `pkg-config --cflags gtk+-2.0` -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED + limit.o limitpanel.o mute.o mixpanel.o mix.o reverb.o +GCF = -DETCDIR=\\\"$(ETCDIR)\\\" `pkg-config --cflags gtk+-2.0` -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED all: $(MAKE) target CFLAGS="-O3 -ffast-math -fomit-frame-pointer $(GCF) $(ADD_DEF)" @@ -30,27 +38,44 @@ debug: $(MAKE) target CFLAGS="-g -Wall -W -Wno-unused-parameter -D__NO_MATH_INLINES $(GCF) $(ADD_DEF)" profile: - $(MAKE) target CFLAGS="-pg -g -O3 -ffast-math $(GCF) $(ADD_DEF)" LIBS="-lgprof-helper" + $(MAKE) target CFLAGS="-pg -g -O3 -ffast-math $(GCF) $(ADD_DEF)" LIBS="-lgprof-helper " clean: - rm -f $(OBJ) *.d *.d.* gmon.out + rm -f $(OBJ) *.d *.d.* gmon.out postfish + +distclean: clean + rm -f postfish-wisdomrc %.d: %.c - $(CC) -M $(GCF) $< > $@.$$$$; sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; rm -f $@.$$$$ + $(CC) -M $(CFLAGS) $< > $@.$$$$; sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; rm -f $@.$$$$ + +postfish-wisdomrc: + fftwf-wisdom -v -o postfish-wisdomrc \ + rif32 rof32 rib32 rob32 \ + rif64 rof64 rib64 rob64 \ + rif128 rof128 rib128 rob128 \ + rif256 rof256 rib256 rob256 \ + rif512 rof512 rib512 rob512 \ + rif1024 rof1024 rib1024 rob1024 \ + rif2048 rof2048 rib2048 rob2048 \ + rif4096 rof4096 rib4096 rob4096 \ + rif8192 rof8192 rib8192 rob8192 \ + rif16384 rof16384 rib16384 rob16384 -ifneq ($(MAKECMDGOALS),clean) +ifeq ($(MAKECMDGOALS),target) include $(SRC:.c=.d) endif -target: $(OBJ) +target: $(OBJ) postfish-wisdomrc ./touch-version - $(LD) $(OBJ) $(CFLAGS) -o postfish $(LIBS) `pkg-config --libs gtk+-2.0` -lpthread -lfftw3f -lm + $(LD) $(OBJ) $(CFLAGS) -o postfish $(LIBS) `pkg-config --libs gtk+-2.0` -lpthread -lfftw3f -lm -install: +install: target $(INSTALL) -d -m 0755 $(BINDIR) $(INSTALL) -m 0755 postfish $(BINDIR) $(INSTALL) -d -m 0755 $(ETCDIR) $(INSTALL) -m 0644 postfish-gtkrc $(ETCDIR) + $(INSTALL) -m 0644 postfish-wisdomrc $(ETCDIR) # $(INSTALL) -d -m 0755 $(MANDIR) # $(INSTALL) -d -m 0755 $(MANDIR)/man1 # $(INSTALL) -m 0644 postfish.1 $(MANDIR)/man1 diff --git a/bessel.c b/bessel.c index 9813da8a7c46c548eac49274576f3352e699d2dc..87ca46c2d85c7998906e760f2cc015ee04b106cb 100644 --- a/bessel.c +++ b/bessel.c @@ -302,6 +302,39 @@ void compute_iir_freefall2(float *x, int n, iir_state *is, } +void compute_iir_decayonly2(float *x, int n, iir_state *is, + iir_filter *decay){ + double d_c0=decay->c[0]; + double d_c1=decay->c[1]; + double d_g=decay->g; + + double x0=is->x[0]; + double x1=is->x[1]; + double y0=is->y[0]; + double y1=is->y[1]; + int i=0; + + while(iyd)yd=x[i]; + + x1=x0;x0=x[i]; + y1=y0;x[i]=y0=yd; + i++; + } + + is->x[0]=x0; + is->x[1]=x1; + is->y[0]=y0; + is->y[1]=y1; + +} + void compute_iir_freefall3(float *x, int n, iir_state *is, iir_filter *decay){ double d_c0=decay->c[0]; diff --git a/bessel.h b/bessel.h index 5a0e58ab19deea6eeeace285b1a383ada97fa090..2f80b4d0c2ab49bca192096e7d92a9a3ae7ed56b 100644 --- a/bessel.h +++ b/bessel.h @@ -33,6 +33,7 @@ typedef struct { float alpha; float Hz; float ms; + int samples; } iir_filter; static inline long impulse_ahead2(float alpha){ @@ -84,6 +85,8 @@ extern void compute_iir_freefall1(float *x, int n, iir_state *is, iir_filter *decay); extern void compute_iir_freefall2(float *x, int n, iir_state *is, iir_filter *decay); +extern void compute_iir_decayonly2(float *x, int n, iir_state *is, + iir_filter *decay); extern void compute_iir_freefall3(float *x, int n, iir_state *is, iir_filter *decay); extern void compute_iir_freefall4(float *x, int n, iir_state *is, diff --git a/clippanel.c b/clippanel.c index deec750a0bbce734c5d99a8afeea39400a2d2bfd..e16f06b586acfe51a2f79f4d0ae0e9036790959c 100644 --- a/clippanel.c +++ b/clippanel.c @@ -116,7 +116,7 @@ void clippanel_create(postfish_mainpanel *mp, GtkWidget **windowbutton, GtkWidget **activebutton){ int i; - char *labels[2]={"10%","100%"}; + char *labels[3]={"","10%","100%"}; float levels[3]={0.,10.,100.}; int block_choices=0; @@ -151,13 +151,13 @@ void clippanel_create(postfish_mainpanel *mp, for(i=64;i<=input_size*2;i*=2)block_choices++; { float levels[9]={0,1,2,3,4,5,6,7,8}; - char *labels[8]={"128","256","512","1024","2048","4096","8192","16384"}; + char *labels[9]={"","128","256","512","1024","2048","4096","8192","16384"}; GtkWidget *table=gtk_table_new(4,2,0); GtkWidget *sliderbox=gtk_hbox_new(0,0); GtkWidget *fastlabel=gtk_label_new("fastest"); GtkWidget *qualitylabel=gtk_label_new("best"); - GtkWidget *slider=multibar_slider_new(block_choices-1,labels,levels,1); + GtkWidget *slider=multibar_slider_new(block_choices,labels,levels,1); GtkWidget *samplelabel=gtk_label_new("window sample width"); GtkWidget *mslabel=gtk_label_new("window time width"); GtkWidget *hzlabel=gtk_label_new("approximate lowest response"); @@ -193,12 +193,12 @@ void clippanel_create(postfish_mainpanel *mp, /* set up convergence config */ { float levels[7]={20,40,60,80,100,120,140}; - char *labels[6]={"40","60","80","100","120","140"}; + char *labels[7]={"","40","60","80","100","120","140"}; GtkWidget *table=gtk_table_new(2,2,0); GtkWidget *sliderbox=gtk_hbox_new(0,0); GtkWidget *fastlabel=gtk_label_new("fastest"); GtkWidget *qualitylabel=gtk_label_new("best"); - GtkWidget *slider=multibar_slider_new(6,labels,levels,1); + GtkWidget *slider=multibar_slider_new(7,labels,levels,1); GtkWidget *label=gtk_label_new("solution depth"); depth_readout=readout_new("000dB"); @@ -223,12 +223,12 @@ void clippanel_create(postfish_mainpanel *mp, /* set up limit config */ { float levels[7]={1,5,10,20,40,60,100}; - char *labels[6]={"5","10","20","40","60","100"}; + char *labels[7]={"","5","10","20","40","60","100"}; GtkWidget *table=gtk_table_new(2,2,0); GtkWidget *sliderbox=gtk_hbox_new(0,0); GtkWidget *fastlabel=gtk_label_new("fastest"); GtkWidget *qualitylabel=gtk_label_new("best"); - GtkWidget *slider=multibar_slider_new(6,labels,levels,1); + GtkWidget *slider=multibar_slider_new(7,labels,levels,1); GtkWidget *label=gtk_label_new("hard iteration limit"); limit_readout=readout_new("000%"); @@ -250,7 +250,7 @@ void clippanel_create(postfish_mainpanel *mp, } for(i=0;islider=slider; diff --git a/compandpanel.c b/compandpanel.c index aca90e6e86fffa26c0ea57cea4cc37e1037f524b..21a944bce3844690a364a1925d27b386f1dcba2f 100644 --- a/compandpanel.c +++ b/compandpanel.c @@ -495,19 +495,19 @@ static multi_panel_state *compandpanel_create(postfish_mainpanel *mp, subpanel_generic *panel, multicompand_settings *ms){ int i; - char *labels[14]={"130","120","110","100","90","80","70", + char *labels[15]={"","130","120","110","100","90","80","70", "60","50","40","30","20","10","0"}; float levels[15]={-140,-130,-120,-110,-100,-90,-80,-70,-60,-50,-40, -30,-20,-10,0}; float compand_levels[9]={.1,.25,.5,.6667,1,1.5,2,4,10}; - char *compand_labels[8]={"4:1","2:1","1:1.5","1:1","1:1.5","1:2","1:4","1:10"}; + char *compand_labels[89]={"","4:1","2:1","1:1.5","1:1","1:1.5","1:2","1:4","1:10"}; float timing_levels[6]={.5,1,10,100,1000,10000}; - char *timing_labels[5]={"1ms","10ms","100ms","1s","10s"}; + char *timing_labels[6]={"","1ms","10ms","100ms","1s","10s"}; float per_levels[9]={0,12.5,25,37.5,50,62.5,75,87.5,100}; - char *per_labels[8]={"","25%","","50%","","75%","","100%"}; + char *per_labels[9]={"0%","","25%","","50%","","75%","","100%"}; multi_panel_state *ps=calloc(1,sizeof(multi_panel_state)); ps->inactive_updatep=1; @@ -644,7 +644,7 @@ static multi_panel_state *compandpanel_create(postfish_mainpanel *mp, GtkWidget *label=gtk_label_new("compand ratio:"); GtkWidget *readout=readout_new("1.55:1"); - GtkWidget *slider=multibar_slider_new(8,compand_labels,compand_levels,1); + GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1); ps->under_compand.r=READOUT(readout); ps->under_compand.v=&ps->ms->under_ratio; @@ -667,7 +667,7 @@ static multi_panel_state *compandpanel_create(postfish_mainpanel *mp, GtkWidget *label=gtk_label_new("attack/decay:"); GtkWidget *readout0=readout_new(" 100ms"); GtkWidget *readout1=readout_new(" 100ms"); - GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2); + GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2); ps->under_timing.r0=READOUT(readout0); ps->under_timing.r1=READOUT(readout1); @@ -693,7 +693,7 @@ static multi_panel_state *compandpanel_create(postfish_mainpanel *mp, GtkWidget *label=gtk_label_new("lookahead:"); GtkWidget *readout=readout_new("100%"); - GtkWidget *slider=multibar_slider_new(8,per_labels,per_levels,1); + GtkWidget *slider=multibar_slider_new(9,per_labels,per_levels,1); ps->under_lookahead.r=READOUT(readout); ps->under_lookahead.v=&ps->ms->under_lookahead; @@ -740,7 +740,7 @@ static multi_panel_state *compandpanel_create(postfish_mainpanel *mp, GtkWidget *label=gtk_label_new("compand ratio:"); GtkWidget *readout=readout_new("1.55:1"); - GtkWidget *slider=multibar_slider_new(8,compand_labels,compand_levels,1); + GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1); ps->over_compand.r=READOUT(readout); ps->over_compand.v=&ps->ms->over_ratio; @@ -763,7 +763,7 @@ static multi_panel_state *compandpanel_create(postfish_mainpanel *mp, GtkWidget *label=gtk_label_new("attack/decay:"); GtkWidget *readout0=readout_new(" 100ms"); GtkWidget *readout1=readout_new(" 100ms"); - GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2); + GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2); ps->over_timing.r0=READOUT(readout0); ps->over_timing.r1=READOUT(readout1); @@ -789,7 +789,7 @@ static multi_panel_state *compandpanel_create(postfish_mainpanel *mp, GtkWidget *label=gtk_label_new("lookahead:"); GtkWidget *readout=readout_new("100%"); - GtkWidget *slider=multibar_slider_new(8,per_labels,per_levels,1); + GtkWidget *slider=multibar_slider_new(9,per_labels,per_levels,1); ps->over_lookahead.r=READOUT(readout); ps->over_lookahead.v=&ps->ms->over_lookahead; @@ -832,7 +832,7 @@ static multi_panel_state *compandpanel_create(postfish_mainpanel *mp, GtkWidget *label=gtk_label_new("compand ratio:"); GtkWidget *readout=readout_new("1.55:1"); - GtkWidget *slider=multibar_slider_new(8,compand_labels,compand_levels,1); + GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1); ps->base_compand.r=READOUT(readout); ps->base_compand.v=&ps->ms->base_ratio; @@ -855,7 +855,7 @@ static multi_panel_state *compandpanel_create(postfish_mainpanel *mp, GtkWidget *label=gtk_label_new("attack/decay:"); GtkWidget *readout0=readout_new(" 100ms"); GtkWidget *readout1=readout_new(" 100ms"); - GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2); + GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2); ps->base_timing.r0=READOUT(readout0); ps->base_timing.r1=READOUT(readout1); @@ -884,7 +884,7 @@ static multi_panel_state *compandpanel_create(postfish_mainpanel *mp, ps->bars[i].readoutu=readout_new(" +0"); ps->bars[i].readouto=readout_new(" +0"); - ps->bars[i].slider=multibar_new(14,labels,levels,2,HI_DECAY|LO_DECAY|LO_ATTACK); + ps->bars[i].slider=multibar_new(15,labels,levels,2,HI_DECAY|LO_DECAY|LO_ATTACK); ps->bars[i].number=i; ps->bars[i].mp=ps; ps->bars[i].label=label; @@ -911,7 +911,7 @@ static multi_panel_state *compandpanel_create(postfish_mainpanel *mp, { GtkWidget *label=gtk_label_new("average"); - ps->bars[multicomp_freqs_max].slider=multibar_slider_new(14,labels,levels,2); + ps->bars[multicomp_freqs_max].slider=multibar_slider_new(15,labels,levels,2); multibar_callback(MULTIBAR(ps->bars[multicomp_freqs_max].slider),average_change,ps); @@ -982,15 +982,15 @@ void compandpanel_feedback(int displayit){ rmsfeed=malloc(sizeof(*rmsfeed)*multicomp_freqs_max); for(i=0;ibars[i].slider),rmsfeed[i],peakfeed[i], - input_ch,(displayit && multi_master_set.panel_visible)); + OUTPUT_CHANNELS,(displayit && multi_master_set.panel_visible)); /* channel panels are a bit different; we want each in its native color */ if(pull_multicompand_feedback_channel(peakfeed,rmsfeed,&bands)==1){ diff --git a/declip.c b/declip.c index 5c3549b3f53b70d8bb2543ae2d6471ea1b280b69..a3fbae2d5c51bb82d2726b135773fb8a760bb67e 100644 --- a/declip.c +++ b/declip.c @@ -156,9 +156,7 @@ int declip_load(void){ for(i=0;isize;j+=blocksize/2){ + for(j=0;j+blocksize<=input_size;j+=blocksize/2){ memset(work,0,sizeof(*work)*blocksize); memcpy(work+blocksize/2,in->data[i]+j,sizeof(*work)*blocksize); memset(work+blocksize+blocksize/2,0,sizeof(*work)*blocksize/2); @@ -394,10 +392,10 @@ time_linkage *declip_read(time_linkage *in){ cache_active=in->active; fillstate=1; out.samples=0; - if(in->samples==in->size)break; + if(in->samples==input_size)break; for(i=0;idata[i],0,sizeof(**in->data)*in->size); + memset(in->data[i],0,sizeof(**in->data)*input_size); in->samples=0; /* fall through */ @@ -589,7 +587,7 @@ time_linkage *declip_read(time_linkage *in){ /* declip */ if(declip_prev_active[i]){ - for(j=0;j+blocksize<=in->size;j+=blocksize/2){ + for(j=0;j+blocksize<=input_size;j+=blocksize/2){ memset(work,0,sizeof(*work)*blocksize); memcpy(work+blocksize/2,cache[i]+j,sizeof(*work)*blocksize); memset(work+blocksize+blocksize/2,0,sizeof(*work)*blocksize/2); @@ -607,7 +605,7 @@ time_linkage *declip_read(time_linkage *in){ } } } - if(out.samplesch]; + int visible[eq->ch]; int i; - for(i=0;ich;i++){ active[i]=eq_master_set.panel_active; visible[i]=eq_master_set.panel_visible; } @@ -131,11 +134,12 @@ time_linkage *eq_read_master(time_linkage *in){ } time_linkage *eq_read_channel(time_linkage *in){ - int active[input_ch]; - int visible[input_ch]; + eq_state *eq=&channel_state; + int active[eq->ch]; + int visible[eq->ch]; int i; - for(i=0;ich;i++){ active[i]=eq_channel_set[i].panel_active; visible[i]=eq_channel_set[i].panel_visible; } diff --git a/eq.h b/eq.h index 8812e2ef8be02e16ea1208cebc8d11849e51ab9b..5ad194c6278e5380e362ba49bb32f33bd3f11809 100644 --- a/eq.h +++ b/eq.h @@ -51,7 +51,7 @@ static char * const eq_freq_labels[eq_freqs]={ extern int pull_eq_feedback_master(float **peak,float **rms); extern int pull_eq_feedback_channel(float **peak,float **rms); -extern int eq_load(void); +extern int eq_load(int ch); extern int eq_reset(); extern void eq_set(eq_settings *eq,int freq, float value); extern time_linkage *eq_read_master(time_linkage *in); diff --git a/eqpanel.c b/eqpanel.c index 29d3f0e3202579d5940dd12552d890388a5c8b84..f8c7f0551e29f806e0efbdb83a3b88eb5fe06e33 100644 --- a/eqpanel.c +++ b/eqpanel.c @@ -66,7 +66,7 @@ static bar *eqpanel_create_helper(postfish_mainpanel *mp, eq_settings *es){ int i; - char *labels[15]={"110","100","90","80","70","60","50","40", + char *labels[16]={"","110","100","90","80","70","60","50","40", "30","20","10","0","+10","+20","+30"}; float levels[16]={-120,-110,-100,-90,-80,-70,-60,-50,-40, -30,-20,-10,0,10,20,30}; @@ -81,7 +81,7 @@ static bar *eqpanel_create_helper(postfish_mainpanel *mp, gtk_widget_set_name(label,"smallmarker"); bars[i].readout=readout_new("+00dB"); - bars[i].slider=multibar_new(15,labels,levels,1, + bars[i].slider=multibar_new(16,labels,levels,1, LO_DECAY|HI_DECAY|LO_ATTACK|HI_ATTACK); bars[i].number=i; bars[i].s=es; @@ -125,7 +125,7 @@ void eqpanel_create_channel(postfish_mainpanel *mp, GtkWidget **windowbutton, GtkWidget **activebutton){ int i; - c_bars=malloc(input_ch*sizeof(*m_bars)); + c_bars=malloc(input_ch*sizeof(*c_bars)); /* a panel for each channel */ for(i=0;ifeedpool); - int i; + int i,ch=ff->out.channels; if(!f)return 0; @@ -59,10 +58,10 @@ int pull_freq_feedback(freq_state *ff,float **peak,float **rms){ }else{ if(peak) for(i=0;ifc->bands;i++) - memcpy(peak[i],f->peak[i],sizeof(**peak)*input_ch); + memcpy(peak[i],f->peak[i],sizeof(**peak)*ch); if(rms) for(i=0;ifc->bands;i++) - memcpy(rms[i],f->rms[i],sizeof(**rms)*input_ch); + memcpy(rms[i],f->rms[i],sizeof(**rms)*ch); feedback_old(&ff->feedpool,(feedback_generic *)f); return 1; } @@ -101,91 +100,101 @@ int freq_class_load(freq_class_setup *f,const float *frequencies, int bands){ /* I'm too lazy to figure out the integral symbolically, use this fancy CPU thingy for something */ - f->ho_window=malloc(bands*sizeof(*f->ho_window)); f->ho_area=calloc(bands,sizeof(*f->ho_area)); - { - float working[f->qblocksize*4+2]; - + f->ho_window=malloc(bands*sizeof(*f->ho_window)); + for(i=0;iho_window[i]=calloc((f->qblocksize*2+1),sizeof(**f->ho_window)); + + /* first, build the first-pass desired, supersampled response */ + for(j=0;j<(((f->qblocksize*2+1)/10)<<5);j++){ + float localf= .5*j*input_rate/(f->qblocksize<<6); + int localbin= j>>5; + for(i=0;i0?frequencies[i-1]:0); float thisf=frequencies[i]; float nextf=frequencies[i+1]; - memset(working,0,sizeof(working)); - - for(j=0;j<((f->qblocksize*2+1)<<5);j++){ - float localf= .5*j*input_rate/(f->qblocksize<<6); - int localbin= j>>5; - float localwin; - - if(localf>=lastf && localf=thisf && localffftwf_buffer,0,sizeof(*f->fftwf_buffer)* - (f->qblocksize*4+2)); - for(j=0;jqblocksize*2;j++) - f->fftwf_buffer[j*2]=working[j]; - - fftwf_execute(f->fftwf_backward); + if(localf>=lastf && localfqblocksize;j++){ - float val=cos(j*M_PI/(f->qblocksize*2)); - val=sin(val*val*M_PIl*.5); - f->fftwf_buffer[j]*= sin(val*val*M_PIl*.5); + localwin*=localwin; + f->ho_window[i][localbin]+=localwin*(1./32); } + } + } + j>>=5; + for(;jqblocksize*2+1;j++){ + float localf= .5*j*input_rate/(f->qblocksize<<1); - for(;jqblocksize*3;j++) - f->fftwf_buffer[j]=0.; - - for(;jqblocksize*4;j++){ - float val=sin((j-f->qblocksize*3)*M_PI/(f->qblocksize*2)); - val=sin(val*val*M_PIl*.5); - f->fftwf_buffer[j]*=sin(val*val*M_PIl*.5); - } + for(i=0;i0?frequencies[i-1]:0); + float thisf=frequencies[i]; + float nextf=frequencies[i+1]; - /* back to frequency; this is all-real data still */ - fftwf_execute(f->fftwf_forward); - for(j=0;jqblocksize*4+2;j++) - f->fftwf_buffer[j]/=f->qblocksize*4; - - /* now take what we learned and distill it a bit */ - f->ho_window[i]=calloc((f->qblocksize*2+1),sizeof(**f->ho_window)); - for(j=0;jqblocksize*2+1;j++){ - f->ho_window[i][j]=f->fftwf_buffer[j*2]; - f->ho_area[i]+=fabs(f->ho_window[i][j]); - } - f->ho_area[i]=1./f->ho_area[i]; + if(localf>=lastf && localfho_window[i][j]+=localwin*localwin; + } } } + for(i=0;ifftwf_buffer,0,sizeof(*f->fftwf_buffer)* + (f->qblocksize*4+2)); + for(j=0;jqblocksize*2;j++) + f->fftwf_buffer[j*2]=f->ho_window[i][j]; + + fftwf_execute(f->fftwf_backward); + + /* window response in time */ + for(j=0;jqblocksize;j++){ + float val=cos(j*M_PI/(f->qblocksize*2)); + val=sin(val*val*M_PIl*.5); + f->fftwf_buffer[j]*= sin(val*val*M_PIl*.5); + } + + for(;jqblocksize*3;j++) + f->fftwf_buffer[j]=0.; + + for(;jqblocksize*4;j++){ + float val=sin((j-f->qblocksize*3)*M_PI/(f->qblocksize*2)); + val=sin(val*val*M_PIl*.5); + f->fftwf_buffer[j]*=sin(val*val*M_PIl*.5); + } + + /* back to frequency; this is all-real data still */ + fftwf_execute(f->fftwf_forward); + for(j=0;jqblocksize*4+2;j++) + f->fftwf_buffer[j]/=f->qblocksize*4; + + /* now take what we learned and distill it a bit */ + for(j=0;jqblocksize*2+1;j++){ + f->ho_window[i][j]=f->fftwf_buffer[j*2]; + f->ho_area[i]+=fabs(f->ho_window[i][j]); + } + f->ho_area[i]=1./f->ho_area[i]; + } + return 0; - } /* called only by initial setup */ -int freq_load(freq_state *f,freq_class_setup *fc){ +int freq_load(freq_state *f,freq_class_setup *fc,int ch){ int i; memset(f,0,sizeof(*f)); @@ -193,22 +202,22 @@ int freq_load(freq_state *f,freq_class_setup *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;icache1=malloc(ch*sizeof(*f->cache1)); + f->cache0=malloc(ch*sizeof(*f->cache0)); + for(i=0;icache1[i]=calloc(input_size,sizeof(**f->cache1)); f->cache0[i]=calloc(input_size,sizeof(**f->cache0)); } - f->activeP=malloc(input_ch*sizeof(*f->activeP)); - f->active1=malloc(input_ch*sizeof(*f->active1)); - f->active0=malloc(input_ch*sizeof(*f->active0)); + f->activeP=malloc(ch*sizeof(*f->activeP)); + f->active1=malloc(ch*sizeof(*f->active1)); + f->active0=malloc(ch*sizeof(*f->active0)); - f->lap1=malloc(input_ch*sizeof(*f->lap1)); - f->lap0=malloc(input_ch*sizeof(*f->lap0)); - f->lapC=malloc(input_ch*sizeof(*f->lapC)); - for(i=0;ilap1=malloc(ch*sizeof(*f->lap1)); + f->lap0=malloc(ch*sizeof(*f->lap0)); + f->lapC=malloc(ch*sizeof(*f->lapC)); + for(i=0;ilap1[i]=calloc(fc->qblocksize,sizeof(**f->lap1)); f->lap0[i]=calloc(fc->qblocksize,sizeof(**f->lap0)); f->lapC[i]=calloc(fc->qblocksize,sizeof(**f->lapC)); @@ -217,15 +226,13 @@ int freq_load(freq_state *f,freq_class_setup *fc){ f->peak=malloc(fc->bands*sizeof(*f->peak)); f->rms=malloc(fc->bands*sizeof(*f->rms)); for(i=0;ibands;i++){ - f->peak[i]=malloc(input_ch*sizeof(**f->peak)); - f->rms[i]=malloc(input_ch*sizeof(**f->rms)); + f->peak[i]=malloc(ch*sizeof(**f->peak)); + f->rms[i]=malloc(ch*sizeof(**f->rms)); } - f->out.size=input_size; - f->out.channels=input_ch; - f->out.rate=input_rate; - f->out.data=malloc(input_ch*sizeof(*f->out.data)); - for(i=0;iout.channels=ch; + f->out.data=malloc(ch*sizeof(*f->out.data)); + for(i=0;iout.data[i]=malloc(input_size*sizeof(**f->out.data)); return(0); @@ -298,12 +305,12 @@ static void freq_work(freq_class_setup *fc, int *active, void (*func)(float *,int)){ - int i,j; + int i,j,ch=f->out.channels; int have_feedback=0; f->cache_samples+=in->samples; - for(i=0;iactive,i); int muted0=mute_channel_muted(f->mutemask0,i); @@ -333,14 +340,14 @@ static void freq_work(freq_class_setup *fc, f->cache0[i],input_size); } - if(in->samplessize){ + if(in->samplesdata[i],0,sizeof(**in->data)*input_size); if(muted0)memset(f->cache0[i],0,sizeof(**f->cache0)*input_size); postextrapolate_helper(f->cache0[i],input_size, in->data[i],in->samples, in->data[i]+in->samples, - in->size-in->samples); + input_size-in->samples); } fill_freq_buffer_helper(fc->fftwf_buffer, @@ -448,17 +455,17 @@ static void freq_work(freq_class_setup *fc, if(!ff->peak){ ff->peak=calloc(fc->bands,sizeof(*ff->peak)); for(i=0;ibands;i++) - ff->peak[i]=malloc(input_ch*sizeof(**ff->peak)); + ff->peak[i]=malloc(ch*sizeof(**ff->peak)); } if(!ff->rms){ ff->rms=calloc(fc->bands,sizeof(*ff->rms)); for(i=0;ibands;i++) - ff->rms[i]=malloc(input_ch*sizeof(**ff->rms)); + ff->rms[i]=malloc(ch*sizeof(**ff->rms)); } for(i=0;ibands;i++){ - memcpy(ff->peak[i],f->peak[i],input_ch*sizeof(**f->peak)); - memcpy(ff->rms[i],f->rms[i],input_ch*sizeof(**f->rms)); + memcpy(ff->peak[i],f->peak[i],ch*sizeof(**f->peak)); + memcpy(ff->rms[i],f->rms[i],ch*sizeof(**f->rms)); } ff->bypass=0; feedback_push(&f->feedpool,(feedback_generic *)ff); @@ -485,7 +492,7 @@ static void freq_work(freq_class_setup *fc, time_linkage *freq_read(time_linkage *in, freq_state *f, int *visible, int *active, void (*func)(float *,int i)){ - int i; + int i,ch=f->out.channels; freq_class_setup *fc=f->fc; switch(f->fillstate){ @@ -496,7 +503,7 @@ time_linkage *freq_read(time_linkage *in, freq_state *f, } /* zero out lapping and cache state */ - for(i=0;ilap1[i],0,sizeof(**f->lap1)*fc->qblocksize); memset(f->lap0[i],0,sizeof(**f->lap0)*fc->qblocksize); memset(f->cache0[i],0,sizeof(**f->cache0)*input_size); @@ -513,10 +520,10 @@ time_linkage *freq_read(time_linkage *in, freq_state *f, f->fillstate=1; f->out.samples=0; - if(in->samples==in->size)goto tidy_up; + if(in->samples==input_size)goto tidy_up; - for(i=0;idata[i],0,sizeof(**in->data)*in->size); + for(i=0;idata[i],0,sizeof(**in->data)*input_size); in->samples=0; /* fall through */ @@ -526,10 +533,10 @@ time_linkage *freq_read(time_linkage *in, freq_state *f, f->fillstate=2; f->out.samples=0; - if(in->samples==in->size)goto tidy_up; + if(in->samples==input_size)goto tidy_up; - for(i=0;idata[i],0,sizeof(**in->data)*in->size); + for(i=0;idata[i],0,sizeof(**in->data)*input_size); in->samples=0; /* fall through */ @@ -537,7 +544,7 @@ time_linkage *freq_read(time_linkage *in, freq_state *f, freq_work(fc,f,in,&f->out,visible,active,func); - if(f->out.samplesout.size)f->fillstate=3; + if(f->out.samplesfillstate=3; break; case 3: /* we've pushed out EOF already */ f->out.samples=0; @@ -545,7 +552,7 @@ time_linkage *freq_read(time_linkage *in, freq_state *f, tidy_up: { - int tozero=f->out.size-f->out.samples; + int tozero=input_size-f->out.samples; if(tozero) for(i=0;iout.channels;i++) memset(f->out.data[i]+f->out.samples,0,sizeof(**f->out.data)*tozero); diff --git a/freq.h b/freq.h index 0347f61ae52145740f2e29cf8ebae1540a18259f..4ee75e7a7fbf8a26b16c2a439f5c2dda34bfa828 100644 --- a/freq.h +++ b/freq.h @@ -71,7 +71,7 @@ typedef struct { extern int pull_freq_feedback(freq_state *ff,float **peak,float **rms); extern int freq_class_load(freq_class_setup *f,const float *frequencies, int bands); -extern int freq_load(freq_state *f,freq_class_setup *fc); +extern int freq_load(freq_state *f,freq_class_setup *fc,int ch); extern int freq_reset(freq_state *f); extern time_linkage *freq_read(time_linkage *in, diff --git a/input.c b/input.c index 15b1da063c1796275dd8b50ea7334fe388542008..5aff0356ad64fb465baaf5d934dca658f43b4a73 100644 --- a/input.c +++ b/input.c @@ -327,23 +327,23 @@ int input_load(int n,char *list[]){ 4000: 256 */ if(rate<6000){ - input_size=out.size=256; + input_size=256; }else if(rate<15000){ - input_size=out.size=512; + input_size=512; }else if(rate<25000){ - input_size=out.size=1024; + input_size=1024; }else if(rate<50000){ - input_size=out.size=2048; + input_size=2048; }else if(rate<100000){ - input_size=out.size=4096; + input_size=4096; }else - input_size=out.size=8192; + input_size=8192; input_ch=out.channels=ch; - input_rate=out.rate=rate; + input_rate=rate; out.data=malloc(sizeof(*out.data)*ch); for(i=0;ipeak,sizeof(*peak)*input_ch); + memcpy(peak,f->peak,sizeof(*peak)*limitstate.out.channels); if(att) - memcpy(att,f->att,sizeof(*att)*input_ch); + memcpy(att,f->att,sizeof(*att)*limitstate.out.channels); feedback_old(&limitstate.feedpool,(feedback_generic *)f); return 1; } /* called only by initial setup */ -int limit_load(void){ +int limit_load(int ch){ int i; memset(&limitstate,0,sizeof(limitstate)); - limitstate.iir=calloc(input_ch,sizeof(*limitstate.iir)); - limitstate.out.size=input_size; - limitstate.out.channels=input_ch; - limitstate.out.rate=input_rate; - limitstate.out.data=malloc(input_ch*sizeof(*limitstate.out.data)); - for(i=0;isamples;k++) @@ -225,10 +222,10 @@ time_linkage *limit_read(time_linkage *in){ (limit_feedback *)feedback_new(&limitstate.feedpool,new_limit_feedback); if(!ff->peak) - ff->peak=malloc(input_ch*sizeof(*ff->peak)); + ff->peak=malloc(ch*sizeof(*ff->peak)); if(!ff->att) - ff->att=malloc(input_ch*sizeof(*ff->att)); + ff->att=malloc(ch*sizeof(*ff->att)); memcpy(ff->peak,peakfeed,sizeof(peakfeed)); memcpy(ff->att,attfeed,sizeof(attfeed)); @@ -237,7 +234,7 @@ time_linkage *limit_read(time_linkage *in){ } { - int tozero=limitstate.out.size-limitstate.out.samples; + int tozero=input_size-limitstate.out.samples; if(tozero) for(i=0;i // Thank you C99! #include #include "input.h" #include "output.h" @@ -38,25 +39,116 @@ #include "singlecomp.h" #include "limit.h" #include "mute.h" +#include "mix.h" pthread_mutex_t master_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; int outfileno=-1; int eventpipe[2]; +int look_for_wisdom(char *filename){ + int ret; + FILE *f=fopen(filename,"r"); + if(!f)return 0; + ret=fftwf_import_wisdom_from_file(f); + fclose(f); + + if(ret) + fprintf(stderr,"Found valid postfish-wisdomrc file at %s\n",filename); + else + fprintf(stderr,"WARNING: corrupt, invalid or obsolete postfish-wisdomrc file at %s\n",filename); + return(ret); +} + int main(int argc, char **argv){ int configfd=-1; + int wisdom=0; + + /* We do not care about FPEs; rather, underflow is nominal case, and + its better to ignore other traps in production than to crash the + app. Please inform the FPU of this. */ + fedisableexcept(FE_INEXACT); + fedisableexcept(FE_UNDERFLOW); + fedisableexcept(FE_OVERFLOW); + + /* Linux Altivec support has a very annoying problem; by default, + math on denormalized floats will simply crash the program. FFTW3 + uses Altivec, so boom. + + By the C99 spec, the above exception configuration is also + supposed to handle Altivec config, but doesn't. So we use the + below ugliness. */ + +#ifdef __PPC +#include +#if (defined __GNUC__) && (__GNUC__ == 3) && ! (defined __APPLE_CC__) + __vector unsigned short noTrap = + (__vector unsigned short){0,0,0,0,0,0,0x1,0}; +#else + vector unsigned short noTrap = + (vector unsigned short)(0,0,0,0,0,0,0x1,0); +#endif + + vec_mtvscr(noTrap); +#endif + + /* check for fftw wisdom file in order: + ./postfish-wisdomrc + $(POSTFISHDIR)/postfish-wisdomrc + ~/.postfish/postfish-wisdomrc + ETCDIR/postfish-wisdomrc + system wisdom */ + + + wisdom=look_for_wisdom("./postfish-wisdomrc"); + if(!wisdom){ + char *rcdir=getenv("POSTFISH_RCDIR"); + if(rcdir){ + char *rcfile="/postfish-wisdomrc"; + char *homerc=calloc(1,strlen(rcdir)+strlen(rcfile)+1); + strcat(homerc,rcdir); + strcat(homerc,rcfile); + wisdom=look_for_wisdom(homerc); + } + } + if(!wisdom){ + char *rcdir=getenv("HOME"); + if(rcdir){ + char *rcfile="/.postfish/postfish-wisdomrc"; + char *homerc=calloc(1,strlen(rcdir)+strlen(rcfile)+1); + strcat(homerc,rcdir); + strcat(homerc,rcfile); + wisdom=look_for_wisdom(homerc); + } + } + if(!wisdom)wisdom=look_for_wisdom(ETCDIR"/postfish-wisdomrc"); + if(!wisdom){ + fftwf_import_system_wisdom(); + + fprintf(stderr,"Postfish could not find the postfish-wisdom configuration file normally built\n" + "or installed with Postfish and located in one of the following places:\n" + + "\t./postfish-wisdomrc\n" + "\t$(POSTFISHDIR)/postfish-wisdomrc\n" + "\t~/.postfish/postfish-wisdomrc\n\t" + ETCDIR"/postfish-wisdomrc\n" + "This configuration file is used to reduce the startup time Postfish uses to \n" + "pre-calculate Fourier transform tables for the FFTW3 library. Postfish will start\n" + "and operate normally, but it will take additional time before popping the main\n" + "window because this information must be regenerated each time Postfish runs.\n"); + } /* parse command line and open all the input files */ if(input_load(argc-1,argv+1))exit(1); /* set up filter chains */ if(declip_load())exit(1); - if(eq_load())exit(1); + if(eq_load(OUTPUT_CHANNELS))exit(1); if(suppress_load())exit(1); - if(multicompand_load())exit(1); - if(singlecomp_load())exit(1); - if(limit_load())exit(1); + if(multicompand_load(OUTPUT_CHANNELS))exit(1); + if(singlecomp_load(OUTPUT_CHANNELS))exit(1); + if(limit_load(OUTPUT_CHANNELS))exit(1); if(mute_load())exit(1); + if(mix_load(OUTPUT_CHANNELS))exit(1); /* look at stdout... do we have a file or device? */ if(!isatty(STDOUT_FILENO)){ diff --git a/mainpanel.c b/mainpanel.c index 50aa790f545d49eab098c11eb8cf2525c92176ab..678fd5ad0eba506f871d577576393b4ef6e13cd1 100644 --- a/mainpanel.c +++ b/mainpanel.c @@ -57,6 +57,7 @@ static void action_zero(GtkWidget *widget,postfish_mainpanel *p){ compandpanel_reset(); singlepanel_reset(); limitpanel_reset(); + mixpanel_reset(); meterhold_reset(p); } @@ -75,6 +76,7 @@ static void action_end(GtkWidget *widget,postfish_mainpanel *p){ compandpanel_reset(); singlepanel_reset(); limitpanel_reset(); + mixpanel_reset(); meterhold_reset(p); } @@ -452,14 +454,15 @@ static void mainpanel_chentry(postfish_mainpanel *p, GtkWidget *table, char *label, int i, - int masterwinp, - int channelwinp, - void (*panel_create) + void (*single_create) + (postfish_mainpanel *, + GtkWidget **, GtkWidget **), + void (*multi_create) (postfish_mainpanel *, GtkWidget **, GtkWidget **)){ int j; - GtkWidget *wm[input_ch]; + GtkWidget *wm[input_ch+1]; GtkWidget *wa[input_ch]; for(j=0;jchannel_wa[i][j]=wa[j]=gtk_toggle_button_new_with_label(buffer); - if(channelwinp){ + if(multi_create){ /* a panel button per channel, multiple accellerated labels */ GtkWidget *l=gtk_label_new_with_mnemonic(label); GtkWidget *a=gtk_alignment_new(0,.5,0,0); @@ -477,7 +480,7 @@ static void mainpanel_chentry(postfish_mainpanel *p, gtk_container_add(GTK_CONTAINER(a),wm[j]); gtk_table_attach_defaults(GTK_TABLE(table),a,2+j*2,4+j*2,i+1,i+2); gtk_table_attach(GTK_TABLE(table),l,1,2,i+1,i+2,GTK_FILL,0,0,0); - if(j>0)gtk_widget_set_size_request(l,0,0); + if(j>0 || single_create)gtk_widget_set_size_request(l,0,0); gtk_label_set_mnemonic_widget(GTK_LABEL(l),wm[j]); { @@ -494,28 +497,30 @@ static void mainpanel_chentry(postfish_mainpanel *p, } } - if(masterwinp){ + if(single_create){ /* one master windowbutton, one label */ - wm[0]=windowbutton_new(label); - gtk_table_attach_defaults(GTK_TABLE(table),wm[0],0,2,i+1,i+2); + wm[input_ch]=windowbutton_new(label); + gtk_table_attach_defaults(GTK_TABLE(table),wm[input_ch],0,2,i+1,i+2); + + (*single_create)(p,wm+input_ch,wa); }else{ - if (!channelwinp){ - GtkWidget *l=gtk_label_new(label); + GtkWidget *b=windowbutton_new(NULL); - gtk_widget_set_name(l,"windowbuttonlike"); - gtk_misc_set_alignment(GTK_MISC(l),0,.5); - gtk_table_attach_defaults(GTK_TABLE(table),l,1,2,i+1,i+2); - } - { - GtkWidget *b=windowbutton_new(NULL); - - gtk_widget_set_sensitive(b,FALSE); - gtk_table_attach_defaults(GTK_TABLE(table),b,0,1,i+1,i+2); - } + gtk_widget_set_sensitive(b,FALSE); + gtk_table_attach_defaults(GTK_TABLE(table),b,0,1,i+1,i+2); + } + if(multi_create) + (*multi_create)(p,wm,wa); + + if (!single_create && !multi_create){ + GtkWidget *l=gtk_label_new(label); + + gtk_widget_set_name(l,"windowbuttonlike"); + gtk_misc_set_alignment(GTK_MISC(l),0,.5); + gtk_table_attach_defaults(GTK_TABLE(table),l,1,2,i+1,i+2); } - if(panel_create)(*panel_create)(p,wm,wa); } static void mainpanel_masterentry(postfish_mainpanel *p, @@ -687,7 +692,7 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){ /* left side of main panel */ { - char *labels[12]={"-96","-72","-60","-48","-36","-24", + char *labels[13]={"","-96","-72","-60","-48","-36","-24", "-16","-8","-3","0","+3","+6"}; float levels[13]={-140.,-96.,-72.,-60.,-48.,-36.,-24., -16.,-8.,-3.,0.,+3.,+6.}; @@ -700,9 +705,9 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){ GtkWidget *inbox=gtk_hbox_new(0,0); GtkWidget *outbox=gtk_hbox_new(0,0); - panel->inbar=multibar_new(12,labels,levels, 0, + panel->inbar=multibar_new(13,labels,levels, 0, LO_ATTACK|LO_DECAY|HI_DECAY|PEAK_FOLLOW ); - panel->outbar=multibar_new(12,labels,levels, 0, + panel->outbar=multibar_new(13,labels,levels, 0, LO_ATTACK|LO_DECAY|HI_DECAY|PEAK_FOLLOW ); panel->inreadout=readout_new("------"); panel->outreadout=readout_new("------"); @@ -748,7 +753,7 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){ /* master dB slider */ { - char *sliderlabels[10]={"-40","-30","-20","-10","0","+10","+20","+30","+40","+50"}; + char *sliderlabels[11]={"","-40","-30","-20","-10","0","+10","+20","+30","+40","+50"}; float sliderlevels[11]={-50,-40,-30,-20,-10,0,10,20,30,40,50}; GtkWidget *box=gtk_hbox_new(0,0); @@ -756,7 +761,7 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){ GtkWidget *masterlabel=gtk_label_new("master:"); panel->masterdB_a=gtk_toggle_button_new_with_label("a[t]ten"); panel->masterdB_r=readout_new(" 0.0dB"); - panel->masterdB_s=multibar_slider_new(10,sliderlabels,sliderlevels,1); + panel->masterdB_s=multibar_slider_new(11,sliderlabels,sliderlevels,1); multibar_thumb_set(MULTIBAR(panel->masterdB_s),0.,0); multibar_thumb_increment(MULTIBAR(panel->masterdB_s),.1,1.); @@ -952,13 +957,14 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){ gtk_table_attach_defaults(GTK_TABLE(channeltable),temp,1,2+input_ch*2,0,1); } - mainpanel_chentry(panel,channeltable,"Mute ",0,0,0,mutedummy_create); - mainpanel_chentry(panel,channeltable,"_Declip ",1,1,0,clippanel_create); - mainpanel_chentry(panel,channeltable,"_Multicomp ",2,0,1,compandpanel_create_channel); - mainpanel_chentry(panel,channeltable,"_Singlecomp ",3,0,1,singlepanel_create_channel); - mainpanel_chentry(panel,channeltable,"De_verb ",4,1,0,suppresspanel_create_channel); - mainpanel_chentry(panel,channeltable,"_Reverb ",5,1,0,0); - mainpanel_chentry(panel,channeltable,"_EQ ",6,0,1,eqpanel_create_channel); + mainpanel_chentry(panel,channeltable,"_Declip ",0,clippanel_create,0); + mainpanel_chentry(panel,channeltable,"_Multicomp ",1,0,compandpanel_create_channel); + mainpanel_chentry(panel,channeltable,"_Singlecomp ",2,0,singlepanel_create_channel); + mainpanel_chentry(panel,channeltable,"De_verb ",3,suppresspanel_create_channel,0); + mainpanel_chentry(panel,channeltable,"_EQ ",4,0,eqpanel_create_channel); + mainpanel_chentry(panel,channeltable,"_Reverb ",5,0,0); + mainpanel_chentry(panel,channeltable,"Atten/Mi_x ",6,attenpanel_create, + mixpanel_create_channel); /* master panel */ { @@ -981,13 +987,46 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){ gtk_table_attach_defaults(GTK_TABLE(mastertable),temp,1,2,0,1); } - mainpanel_masterentry(panel,mastertable,"_Crossmix "," c ",GDK_c,0,0); - mainpanel_masterentry(panel,mastertable,"_Multicomp "," m ",GDK_m,1,compandpanel_create_master); - mainpanel_masterentry(panel,mastertable,"_Singlecomp "," s ",GDK_s,2,singlepanel_create_master); - mainpanel_masterentry(panel,mastertable,"_Reverb "," r ",GDK_r,3,0); - mainpanel_masterentry(panel,mastertable,"_EQ "," e ",GDK_e,4,eqpanel_create_master); - mainpanel_masterentry(panel,mastertable,"_Limit "," l ",GDK_l,5,limitpanel_create); - mainpanel_masterentry(panel,mastertable,"_Output ",NULL,GDK_l,6,0); + mainpanel_masterentry(panel,mastertable,"_Multicomp "," m ",GDK_m,0,compandpanel_create_master); + mainpanel_masterentry(panel,mastertable,"_Singlecomp "," s ",GDK_s,1,singlepanel_create_master); + mainpanel_masterentry(panel,mastertable,"_Reverb "," r ",GDK_r,2,0); + mainpanel_masterentry(panel,mastertable,"_EQ "," e ",GDK_e,3,eqpanel_create_master); + mainpanel_masterentry(panel,mastertable,"_Limit "," l ",GDK_l,4,limitpanel_create); + + /* output has three activity buttons not in the main grid */ + { + GtkWidget *ww=windowbutton_new("_Output "); + + GtkWidget *std=gtk_toggle_button_new_with_label("o"); + GtkWidget *ply=gtk_toggle_button_new_with_label("p"); + GtkWidget *fil=gtk_toggle_button_new_with_label("f"); + GtkWidget *box=gtk_hbox_new(0,0); + GtkWidget *box2=gtk_hbox_new(1,0); + + GtkWidget *fw=windowbutton_new(NULL); + GtkWidget *fr=gtk_frame_new(NULL); + + gtk_frame_set_shadow_type(GTK_FRAME(fr),GTK_SHADOW_ETCHED_IN); + gtk_widget_set_sensitive(fw,FALSE); + + gtk_widget_add_accelerator (std, "activate", panel->group, GDK_o, 0, 0); + gtk_widget_add_accelerator (ply, "activate", panel->group, GDK_p, 0, 0); + gtk_widget_add_accelerator (fil, "activate", panel->group, GDK_f, 0, 0); + + gtk_box_pack_start(GTK_BOX(box),ww,0,0,0); + gtk_box_pack_start(GTK_BOX(box),box2,1,1,2); + gtk_box_pack_start(GTK_BOX(box2),ply,1,1,0); + gtk_box_pack_start(GTK_BOX(box2),fil,1,1,0); + + + gtk_table_attach_defaults(GTK_TABLE(mastertable),fw,0,1,6,7); + gtk_table_attach_defaults(GTK_TABLE(mastertable),fr,1,2,6,7); + + gtk_table_attach_defaults(GTK_TABLE(mastertable),box,0,1,7,8); + gtk_table_attach_defaults(GTK_TABLE(mastertable),std,1,2,7,8); + + //if(panel_create)(*panel_create)(p,ww,(shortcut?wa:0)); + } g_signal_connect (G_OBJECT (panel->toplevel), "delete_event", G_CALLBACK (shutdown), NULL); @@ -1074,6 +1113,7 @@ static void feedback_process(postfish_mainpanel *panel){ compandpanel_feedback(current_p); singlepanel_feedback(current_p); limitpanel_feedback(current_p); + mixpanel_feedback(current_p); } } @@ -1090,6 +1130,14 @@ static gboolean async_event_handle(GIOChannel *channel, return TRUE; } +static int look_for_gtkrc(char *filename){ + FILE *f=fopen(filename,"r"); + if(!f)return 0; + fprintf(stderr,"Loading postfish-gtkrc file found at %s\n",filename); + gtk_rc_add_default_file(filename); + return 1; +} + #include void mainpanel_go(int argc,char *argv[], int ch){ postfish_mainpanel p; @@ -1097,9 +1145,48 @@ void mainpanel_go(int argc,char *argv[], int ch){ char *labels[11]; char buffer[20]; int i; - + int found=0; memset(&p,0,sizeof(p)); - gtk_rc_add_default_file("/etc/postfish/postfish-gtkrc"); + + found|=look_for_gtkrc(ETCDIR"/postfish-gtkrc"); + { + char *rcdir=getenv("HOME"); + if(rcdir){ + char *rcfile="/.postfish/postfish-gtkrc"; + char *homerc=calloc(1,strlen(rcdir)+strlen(rcfile)+1); + strcat(homerc,homedir); + strcat(homerc,rcfile); + found|=look_for_gtkrc(homerc); + } + } + { + char *rcdir=getenv("POSTFISH_RCDIR"); + if(rcdir){ + char *rcfile="/postfish-gtkrc"; + char *homerc=calloc(1,strlen(rcdir)+strlen(rcfile)+1); + strcat(homerc,homedir); + strcat(homerc,rcfile); + found|=look_for_gtkrc(homerc); + } + } + found|=look_for_gtkrc("./postfish-gtkrc"); + + if(!found){ + + fprintf(stderr,"Postfish could not find the postfish-gtkrc configuration file normally\n" + "installed with Postfish and located in one of the following places:\n" + + "\t./postfish-gtkrc\n" + "\t$(POSTFISHDIR)/postfish-gtkrc\n" + "\t~/.postfish/postfish-gtkrc\n\t" + ETCDIR"/postfish-gtkrc\n" + "This configuration file is used to tune the color, font and other detail aspects\n" + "of the Postfish user interface. Although Postfish will work without it, the UI\n" + "appearence will likely make the application harder to use due to missing visual\n" + "cues.\n"); + } + + gtk_rc_add_default_file(ETCDIR"/postfish-gtkrc"); if(homedir){ char *rcfile="/.postfish-gtkrc"; char *homerc=calloc(1,strlen(homedir)+strlen(rcfile)+1); @@ -1114,13 +1201,13 @@ void mainpanel_go(int argc,char *argv[], int ch){ memset(labels,0,sizeof(labels)); switch(ch){ case 1: - labels[0]="_0 mono"; + labels[0]="_1 mono"; break; case 2: - labels[0]="_0 left"; - labels[1]="_1 right"; - labels[2]="_2 mid"; - labels[3]="_3 side"; + labels[0]="_1 left"; + labels[1]="_2 right"; + labels[2]="_y mid"; + labels[3]="_z side"; break; case 3: case 4: @@ -1136,14 +1223,17 @@ void mainpanel_go(int argc,char *argv[], int ch){ case 14: case 15: case 16: - for(i=0;ibypass){ + feedback_old(&ms.feedpool,(feedback_generic *)f); + return 2; + }else{ + if(peak) + for(i=0;ipeak[i],sizeof(**peak)*input_ch); + if(rms) + for(i=0;irms[i],sizeof(**rms)*input_ch); + feedback_old(&ms.feedpool,(feedback_generic *)f); + return 1; + } +} + +/* called only by initial setup */ +int mix_load(int outch){ + int i; + + mix_set=calloc(input_ch,sizeof(*mix_set)); + mixpanel_active=calloc(input_ch,sizeof(*mixpanel_active)); + mixpanel_visible=calloc(input_ch,sizeof(*mixpanel_visible)); + + memset(&ms,0,sizeof(ms)); + ms.prev=calloc(input_ch,sizeof(*ms.prev)); + ms.curr=calloc(input_ch,sizeof(*ms.curr)); + + ms.cacheP=malloc(input_ch*sizeof(*ms.cacheP)); + ms.cachePP=malloc(input_ch*sizeof(*ms.cachePP)); + ms.cachePA=malloc(input_ch*sizeof(*ms.cachePA)); + ms.cachePPA=malloc(input_ch*sizeof(*ms.cachePPA)); + ms.cachePB=malloc(input_ch*sizeof(*ms.cachePB)); + ms.cachePPB=malloc(input_ch*sizeof(*ms.cachePPB)); + for(i=0;iinput_size*2)del= -input_size*2; + if(-delP>input_size*2)delP= -input_size*2; + + if(inv)att*=-1.; + if(invP)attP*=-1.; + + if(att==attP && del==delP){ + + /* straight copy from cache with attenuation */ + i=input_size*2+del; + while(isamples==0){ + ms.out.samples=0; + return &ms.out; + } + memset(outactive,0,sizeof(outactive)); + memset(peak,0,sizeof(peak)); + memset(rms,0,sizeof(rms)); + + /* fillstate here is only used for lazy initialization/reset */ + if(ms.fillstate==0){ + /* zero the cache */ + for(i=0;iactive,i)) + memset(in->data[i],0,sizeof(**in->data)*input_size); + + /* input-by-input */ + for(i=0;iactive,i)){ + memset(mix,0,sizeof(mix)); + mixwork(in->data[i],ms.cacheP[i],ms.cachePP[i], + mix,att,del,0,att,del,0); + + bypass=0; + for(j=0;jpeak[0][i])peak[0][i]=val; + acc+=val; + } + + peak[0][i]=peak[0][i]; + rms[0][i]=acc/input_size; + } + + if(inA && !mute_channel_muted(inA->active,i)){ + memset(mix,0,sizeof(mix)); + mixwork(inA->data[i],ms.cacheP[i],ms.cachePP[i], + mix,att,del,0,att,del,0); + + bypass=0; + for(j=0;jpeak[0][i])peak[0][i]=val; + acc+=val; + } + + peak[1][i]=peak[0][i]; + rms[1][i]=acc/input_size; + } + + if(inB && !mute_channel_muted(inB->active,i)){ + memset(mix,0,sizeof(mix)); + mixwork(inB->data[i],ms.cacheP[i],ms.cachePP[i], + mix,att,del,0,att,del,0); + + bypass=0; + for(j=0;jpeak[0][i])peak[0][i]=val; + acc+=val; + } + + peak[2][i]=peak[0][i]; + rms[2][i]=acc/input_size; + } + } + + /* placer settings; translate to final numbers */ + int placer=ms.curr[i].placer_place; + int placerP=ms.prev[i].placer_place; + + float relA=(placer>100 ? placer*.01-1. : 0.); + float relB=(placer<100 ? 1.-placer*.01 : 0.); + float relAP=(placerP>100 ? placerP*.01-1. : 0.); + float relBP=(placerP<100 ? 1.-placerP*.01 : 0.); + + float attA= + fromdB((ms.curr[i].master_att + + ms.curr[i].placer_att * relA)*.1); + + float attB= + fromdB((ms.curr[i].master_att + + ms.curr[i].placer_att * relB)*.1); + + int delA= + rint((ms.curr[i].master_delay + + ms.curr[i].placer_delay * relA)*.00001*input_rate); + + int delB= + rint((ms.curr[i].master_delay + + ms.curr[i].placer_delay * relB)*.00001*input_rate); + + float attAP= + fromdB((ms.prev[i].master_att + + ms.prev[i].placer_att * relAP)*.1); + + float attBP= + fromdB((ms.prev[i].master_att + + ms.prev[i].placer_att * relBP)*.1); + + int delAP= + rint((ms.prev[i].master_delay + + ms.prev[i].placer_delay * relAP)*.00001*input_rate); + + int delBP= + rint((ms.prev[i].master_delay + + ms.prev[i].placer_delay * relBP)*.00001*input_rate); + + /* place mix */ + { + int mixedA=0,mixedB=0; + float mixA[input_size],mixB[input_size]; + + for(j=0;jdata[i],ms.cacheP[i],ms.cachePP[i], + mixA,attA,delA,0,attAP,delAP,0); + mixedA=1; + } + mixadd(mixA,ms.out.data[j],destA,destAP); + } + if(destB || destBP){ + outactive[j]=1; + + if(!mixedB){ + memset(mixB,0,sizeof(mixB)); + mixwork(in->data[i],ms.cacheP[i],ms.cachePP[i], + mixB,attB,delB,0,attBP,delBP,0); + mixedB=1; + } + mixadd(mixB,ms.out.data[j],destB,destBP); + } + } + + /* feedback for A */ + if(feedit){ + float acc=0.; + bypass=0; + if(mixedA){ + for(j=0;jpeak[3][i])peak[3][i]=val; + acc+=val; + } + + peak[3][i]=peak[3][i]; + rms[3][i]=acc/input_size; + } + } + + /* feedback for B */ + if(feedit){ + float acc=0.; + bypass=0; + if(mixedB){ + for(j=0;jpeak[4][i])peak[4][i]=val; + acc+=val; + } + + peak[4][i]=peak[4][i]; + rms[4][i]=acc/input_size; + } + } + } + + /* direct block mix */ + for(k=0;kdata[i],ms.cacheP[i],ms.cachePP[i], + mix, + att,del,ms.curr[i].insert_invert[k], + attP,delP,ms.prev[i].insert_invert[k]); + + /* reverbA */ + if(sourceA || sourceAP) + if(inA) + mixwork(inA->data[i],ms.cachePA[i],ms.cachePPA[i], + mix, + att,del,ms.curr[i].insert_invert[k], + attP,delP,ms.prev[i].insert_invert[k]); + + /* reverbB */ + if(sourceB || sourceBP) + if(inB) + mixwork(inB->data[i],ms.cachePB[i],ms.cachePPB[i], + mix, + att,del,ms.curr[i].insert_invert[k], + attP,delP,ms.prev[i].insert_invert[k]); + + /* mix into output */ + for(j=0;jpeak[5+k][i])peak[5+k][i]=val; + acc+=val; + } + + peak[5+k][i]=peak[5+k][i]; + rms[5+k][i]=acc/input_size; + + } + } + } + /* rotate data cache */ + { + float *temp=ms.cachePP[i]; + ms.cachePP[i]=ms.cacheP[i]; + ms.cacheP[i]=in->data[i]; + in->data[i]=temp; + + if(inA){ + temp=ms.cachePPA[i]; + ms.cachePPA[i]=ms.cachePA[i]; + ms.cachePA[i]=inA->data[i]; + inA->data[i]=temp; + } + + if(inB){ + temp=ms.cachePPB[i]; + ms.cachePPB[i]=ms.cachePB[i]; + ms.cachePB[i]=inB->data[i]; + inB->data[i]=temp; + } + } + } + + /* finish output data */ + ms.out.samples=in->samples; + ms.out.active=0; + for(i=0;ibypass=1; + feedback_push(&ms.feedpool,(feedback_generic *)mf); + }else{ + mix_feedback *mf= + (mix_feedback *)feedback_new(&ms.feedpool,new_mix_feedback); + + if(!mf->peak){ + mf->peak=malloc((MIX_BLOCKS+5)*sizeof(*mf->peak)); + mf->rms=malloc((MIX_BLOCKS+5)*sizeof(*mf->rms)); + + for(i=0;irms[i]=malloc(input_ch*sizeof(**mf->rms)); + for(i=0;ipeak[i]=malloc(input_ch*sizeof(**mf->peak)); + } + + for(i=0;ipeak[i],peak[i],input_ch*sizeof(**peak)); + memcpy(mf->rms[i],rms[i],input_ch*sizeof(**rms)); + } + mf->bypass=0; + feedback_push(&ms.feedpool,(feedback_generic *)mf); + } + + return &ms.out; +} + diff --git a/mix.h b/mix.h new file mode 100644 index 0000000000000000000000000000000000000000..ae99ad3ab35ca27a0d24f55b88eab0dc6174ca08 --- /dev/null +++ b/mix.h @@ -0,0 +1,51 @@ +/* + * + * postfish + * + * Copyright (C) 2002-2004 Monty + * + * Postfish is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * Postfish is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Postfish; see the file COPYING. If not, write to the + * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +#include "postfish.h" + +#define MIX_BLOCKS 4 + +typedef struct { + sig_atomic_t master_att; + sig_atomic_t master_delay; + + sig_atomic_t placer_destA[OUTPUT_CHANNELS]; + sig_atomic_t placer_destB[OUTPUT_CHANNELS]; + sig_atomic_t placer_place; + sig_atomic_t placer_att; + sig_atomic_t placer_delay; + + sig_atomic_t insert_source[MIX_BLOCKS][3]; + sig_atomic_t insert_invert[MIX_BLOCKS]; + sig_atomic_t insert_att[MIX_BLOCKS]; + sig_atomic_t insert_delay[MIX_BLOCKS]; + sig_atomic_t insert_dest[MIX_BLOCKS][OUTPUT_CHANNELS]; +} mix_settings; + +extern int mix_load(int outch); +extern int mix_reset(void); +extern time_linkage *mix_read(time_linkage *in, + time_linkage *inA, // reverb channel + time_linkage *inB); // reverb channel +extern int pull_mix_feedback(float **peak,float **rms); + diff --git a/mixpanel.c b/mixpanel.c new file mode 100644 index 0000000000000000000000000000000000000000..437166ddf54ff346ff413aa35f80a6e105b3299b --- /dev/null +++ b/mixpanel.c @@ -0,0 +1,545 @@ +/* + * + * postfish + * + * Copyright (C) 2002-2004 Monty + * + * Postfish is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * Postfish is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Postfish; see the file COPYING. If not, write to the + * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +#include "postfish.h" +#include +#include +#include "readout.h" +#include "multibar.h" +#include "mainpanel.h" +#include "subpanel.h" +#include "feedback.h" +#include "mix.h" + +extern int input_ch; +extern int input_size; +extern int input_rate; + +extern mix_settings *mix_set; +extern sig_atomic_t atten_visible; +extern sig_atomic_t *mixpanel_active; +extern sig_atomic_t *mixpanel_visible; + +typedef struct { + GtkWidget *s; + GtkWidget *r; + sig_atomic_t *val; +} slider_readout_pair; + +/* only the sliders we need to save for feedback */ +typedef struct { + GtkWidget **master; +} atten_panelsave; + +typedef struct { + GtkWidget *place[2]; + GtkWidget *sub[MIX_BLOCKS]; +} mix_panelsave; + +static atten_panelsave atten_panel; +static mix_panelsave **mix_panels; + +static void dB_slider_change(GtkWidget *w,gpointer in){ + char buffer[80]; + slider_readout_pair *p=(slider_readout_pair *)in; + float val=multibar_get_value(MULTIBAR(p->s),0); + + sprintf(buffer,"%+4.1fdB",val); + readout_set(READOUT(p->r),buffer); + + *p->val=rint(val*10); +} + +static void ms_slider_change(GtkWidget *w,gpointer in){ + char buffer[80]; + slider_readout_pair *p=(slider_readout_pair *)in; + float val=multibar_get_value(MULTIBAR(p->s),0); + + if(val>-1. && val<1.){ + sprintf(buffer,"%+4.2fms",val); + }else{ + sprintf(buffer,"%+4.1fms",val); + } + readout_set(READOUT(p->r),buffer); + *p->val=rint(val*100); +} + +static void AB_slider_change(GtkWidget *w,gpointer in){ + char buffer[80]; + slider_readout_pair *p=(slider_readout_pair *)in; + float val=multibar_get_value(MULTIBAR(p->s),0); + + if(val==100){ + sprintf(buffer,"center"); + }else if(val<100){ + sprintf(buffer,"A+%d%%",(int)(100-val)); + }else{ + sprintf(buffer,"B+%d%%",(int)(val-100)); + } + readout_set(READOUT(p->r),buffer); + + *p->val=rint(val); +} + +static void toggle_callback(GtkWidget *w,gpointer in){ + GtkToggleButton *b=GTK_TOGGLE_BUTTON(w); + sig_atomic_t *val=(sig_atomic_t *)in; + + *val=gtk_toggle_button_get_active(b); +} + +static char *labels_dB[11]={""," 60","40","20","10","0","10","20","40","60","80"}; +static float levels_dB[11]={-80,-60,-40,-20,-10,0,10,20,40,60,80}; + +static char *labels_dBn[6]={"","-40","-20","-10","0","+10"}; +static float levels_dBn[6]={-80,-40,-20,-10,0,10}; + +static char *labels_del[6]={"","-20","-10","-5","-1","-0"}; +static float levels_del[6]={-50,-20,-10,-5,-1,0}; + + +static mix_panelsave *mixpanel_create_helper(postfish_mainpanel *mp, + subpanel_generic *panel, + mix_settings *m){ + + int i,j; + + char *labels_dBnn[6]={"","-40","-20","-10","-3","0"}; + float levels_dBnn[6]={-80,-40,-20,-10,-3,0}; + + char *labels_AB[3]={"A","center","B"}; + float levels_AB[3]={0,100,200}; + + GtkWidget *table=gtk_table_new(12+MIX_BLOCKS*3,6,0); + mix_panelsave *ps=calloc(1,sizeof(*ps)); + + /* crossplace marker */ + { + GtkWidget *box=gtk_hbox_new(0,0); + GtkWidget *l=gtk_label_new("Crossplace "); + GtkWidget *h=gtk_hseparator_new(); + + gtk_widget_set_name(l,"framelabel"); + + gtk_box_pack_start(GTK_BOX(box),l,0,0,0); + gtk_box_pack_start(GTK_BOX(box),h,1,1,0); + gtk_table_attach(GTK_TABLE(table),box,0,6,2,3, + GTK_FILL,0,0,2); + gtk_table_set_row_spacing(GTK_TABLE(table),1,10); + } + + /* crossplace controls */ + { + slider_readout_pair *AB=calloc(1,sizeof(AB)); + slider_readout_pair *att=calloc(1,sizeof(att)); + slider_readout_pair *del=calloc(1,sizeof(del)); + GtkWidget *boxA=gtk_hbox_new(1,0); + GtkWidget *boxB=gtk_hbox_new(1,0); + + GtkWidget *lA=gtk_label_new("output A"); + GtkWidget *lB=gtk_label_new("output B"); + + GtkWidget *latt=gtk_label_new("crossatten "); + GtkWidget *ldel=gtk_label_new("crossdelay "); + gtk_misc_set_alignment(GTK_MISC(latt),1,.5); + gtk_misc_set_alignment(GTK_MISC(ldel),1,.5); + + AB->s=multibar_slider_new(3,labels_AB,levels_AB,1); + att->s=multibar_slider_new(6,labels_dBnn,levels_dBnn,1); + del->s=multibar_slider_new(6,labels_del,levels_del,1); + AB->r=readout_new("A+000"); + att->r=readout_new("+00.0dB"); + del->r=readout_new("+00.0ms"); + AB->val=&m->placer_place; + att->val=&m->placer_att; + del->val=&m->placer_delay; + + multibar_callback(MULTIBAR(AB->s),AB_slider_change,AB); + multibar_thumb_set(MULTIBAR(AB->s),100,0); + multibar_callback(MULTIBAR(att->s),dB_slider_change,att); + multibar_thumb_set(MULTIBAR(att->s),0,0); + multibar_callback(MULTIBAR(del->s),ms_slider_change,del); + multibar_thumb_set(MULTIBAR(del->s),0,0); + + ps->place[0]=multibar_new(6,labels_dBn,levels_dBn,0, + LO_ATTACK|LO_DECAY|HI_DECAY); + ps->place[1]=multibar_new(6,labels_dBn,levels_dBn,0, + LO_ATTACK|LO_DECAY|HI_DECAY); + + for(i=0;iplacer_destA[i]); + g_signal_connect (G_OBJECT (bB), "clicked", + G_CALLBACK (toggle_callback), + (gpointer)&m->placer_destB[i]); + + } + + gtk_table_attach(GTK_TABLE(table),lA,0,2,6,7, + 0,0,0,0); + gtk_table_attach(GTK_TABLE(table),lB,5,6,6,7, + 0,0,0,0); + + gtk_table_attach(GTK_TABLE(table),ps->place[0],0,2,4,5, + GTK_FILL|GTK_EXPAND,0,0,0); + gtk_table_attach(GTK_TABLE(table),ps->place[1],5,6,4,5, + GTK_FILL|GTK_EXPAND,0,0,0); + + gtk_table_attach(GTK_TABLE(table),boxA,0,2,5,6, + GTK_FILL|GTK_EXPAND,0,0,0); + gtk_table_attach(GTK_TABLE(table),boxB,5,6,5,6, + GTK_FILL|GTK_EXPAND,0,0,0); + gtk_table_attach(GTK_TABLE(table),AB->s,2,4,4,5, + GTK_FILL|GTK_EXPAND,0,2,0); + gtk_table_attach(GTK_TABLE(table),att->s,3,4,5,6, + GTK_FILL|GTK_EXPAND,0,2,0); + gtk_table_attach(GTK_TABLE(table),del->s,3,4,6,7, + GTK_FILL|GTK_EXPAND,0,2,0); + gtk_table_attach(GTK_TABLE(table),AB->r,4,5,4,5, + GTK_FILL|GTK_EXPAND,0,0,0); + gtk_table_attach(GTK_TABLE(table),att->r,4,5,5,6, + GTK_FILL|GTK_EXPAND,0,0,0); + gtk_table_attach(GTK_TABLE(table),del->r,4,5,6,7, + GTK_FILL|GTK_EXPAND,0,0,0); + + gtk_table_attach(GTK_TABLE(table),latt,2,3,5,6, + GTK_FILL,0,0,0); + gtk_table_attach(GTK_TABLE(table),ldel,2,3,6,7, + GTK_FILL,0,0,0); + + + } + + /* Direct Mix marker */ + { + GtkWidget *box=gtk_hbox_new(0,0); + GtkWidget *l=gtk_label_new("Direct Mixdown Blocks "); + GtkWidget *h=gtk_hseparator_new(); + + GtkWidget *ls=gtk_label_new("source"); + GtkWidget *lo=gtk_label_new("output"); + + gtk_widget_set_name(l,"framelabel"); + + gtk_box_pack_start(GTK_BOX(box),l,0,0,0); + gtk_box_pack_start(GTK_BOX(box),h,1,1,0); + + gtk_table_attach(GTK_TABLE(table),box,0,6,7,8, + GTK_FILL,0,0,2); + gtk_table_attach(GTK_TABLE(table),ls,0,2,11+MIX_BLOCKS*3,12+MIX_BLOCKS*3, + GTK_FILL,0,0,2); + gtk_table_attach(GTK_TABLE(table),lo,5,6,11+MIX_BLOCKS*3,12+MIX_BLOCKS*3, + GTK_FILL,0,0,2); + gtk_table_set_row_spacing(GTK_TABLE(table),6,10); + + } + + for(i=0;is=multibar_slider_new(11,labels_dB,levels_dB,1); + del->s=multibar_slider_new(6,labels_del,levels_del,1); + att->r=readout_new("+00.0dB"); + del->r=readout_new("+00.0ms"); + att->val=&m->insert_att[i]; + del->val=&m->insert_delay[i]; + + ps->sub[i]=multibar_new(6,labels_dBn,levels_dBn,0, + LO_ATTACK|LO_DECAY|HI_DECAY); + + multibar_callback(MULTIBAR(att->s),dB_slider_change,att); + multibar_callback(MULTIBAR(del->s),ms_slider_change,del); + + gtk_box_pack_start(GTK_BOX(boxA),bM,1,1,0); + gtk_box_pack_start(GTK_BOX(boxA),bA,1,1,0); + gtk_box_pack_start(GTK_BOX(boxA),bB,1,1,0); + + g_signal_connect (G_OBJECT (bI), "clicked", + G_CALLBACK (toggle_callback), + (gpointer)&m->insert_invert[i]); + + g_signal_connect (G_OBJECT (bM), "clicked", + G_CALLBACK (toggle_callback), + (gpointer)&m->insert_source[i][0]); + g_signal_connect (G_OBJECT (bA), "clicked", + G_CALLBACK (toggle_callback), + (gpointer)&m->insert_source[i][1]); + g_signal_connect (G_OBJECT (bB), "clicked", + G_CALLBACK (toggle_callback), + (gpointer)&m->insert_source[i][2]); + + + + for(j=0;jinsert_dest[i][j]); + + gtk_box_pack_start(GTK_BOX(boxB),b,1,1,0); + } + + gtk_table_attach(GTK_TABLE(table),boxA,0,2,9+i*3,10+i*3, + GTK_FILL|GTK_EXPAND,0,0,0); + gtk_table_attach(GTK_TABLE(table),boxB,5,6,9+i*3,10+i*3, + GTK_FILL|GTK_EXPAND,0,0,0); + gtk_table_attach(GTK_TABLE(table),att->s,3,4,8+i*3,9+i*3, + GTK_FILL|GTK_EXPAND,0,2,0); + gtk_table_attach(GTK_TABLE(table),del->s,3,4,9+i*3,10+i*3, + GTK_FILL|GTK_EXPAND,0,2,0); + gtk_table_attach(GTK_TABLE(table),att->r,4,5,8+i*3,9+i*3, + GTK_FILL|GTK_EXPAND,0,0,0); + gtk_table_attach(GTK_TABLE(table),del->r,4,5,9+i*3,10+i*3, + GTK_FILL|GTK_EXPAND,0,0,0); + + gtk_table_attach(GTK_TABLE(table),bI,0,2,8+i*3,9+i*3, + 0,0,0,0); + gtk_table_attach(GTK_TABLE(table),ps->sub[i],5,6,8+i*3,9+i*3, + GTK_FILL,0,0,0); + + gtk_table_attach(GTK_TABLE(table),latt,2,3,8+i*3,9+i*3, + GTK_FILL,0,0,0); + gtk_table_attach(GTK_TABLE(table),ldel,2,3,9+i*3,10+i*3, + GTK_FILL,0,0,0); + + gtk_table_attach(GTK_TABLE(table),h,0,6,10+i*3,11+i*3, + GTK_FILL,0,0,2); + + + } + + gtk_box_pack_start(GTK_BOX(panel->subpanel_box),table,1,1,4); + subpanel_show_all_but_toplevel(panel); + + return ps; +} + +void mixpanel_create_channel(postfish_mainpanel *mp, + GtkWidget **windowbutton, + GtkWidget **activebutton){ + int i; + mix_panels=malloc(input_ch*sizeof(*mix_panels)); + + /* a panel for each channel */ + for(i=0;is=multibar_slider_new(11,labels_dB,levels_dB,1); + att->r=readout_new("+00.0dB"); + att->val=&mix_set[i].master_att; + + del->s=multibar_slider_new(6,labels_del,levels_del,1); + del->r=readout_new("+00.0ms"); + del->val=&mix_set[i].master_delay; + + multibar_callback(MULTIBAR(att->s),dB_slider_change,att); + multibar_callback(MULTIBAR(del->s),ms_slider_change,del); + + multibar_thumb_set(MULTIBAR(att->s),0,0); + multibar_thumb_set(MULTIBAR(del->s),0,0); + + gtk_misc_set_alignment(GTK_MISC(lN),1,.5); + gtk_misc_set_alignment(GTK_MISC(l1),1,.5); + gtk_misc_set_alignment(GTK_MISC(l2),1,.5); + + gtk_table_attach(GTK_TABLE(table),lN,0,1,0+i*3,2+i*3, + 0,0,15,0); + + gtk_table_attach(GTK_TABLE(table),h,0,5,2+i*3,3+i*3, + GTK_FILL|GTK_EXPAND,0,0,2); + + gtk_table_attach(GTK_TABLE(table),l1,1,2,0+i*3,1+i*3, + GTK_FILL|GTK_EXPAND,0,0,0); + gtk_table_attach(GTK_TABLE(table),att->s,2,3,0+i*3,1+i*3, + GTK_FILL|GTK_EXPAND,0,0,0); + gtk_table_attach(GTK_TABLE(table),att->r,3,4,0+i*3,1+i*3, + GTK_FILL|GTK_EXPAND,0,0,0); + gtk_table_attach(GTK_TABLE(table),atten_panel.master[i],4,5,0+i*3,1+i*3, + GTK_FILL,0,0,0); + gtk_table_attach(GTK_TABLE(table),lV,4,5,1+i*3,2+i*3, + GTK_FILL,0,0,0); + + gtk_table_attach(GTK_TABLE(table),l2,1,2,1+i*3,2+i*3, + GTK_FILL|GTK_EXPAND,0,0,0); + gtk_table_attach(GTK_TABLE(table),del->s,2,3,1+i*3,2+i*3, + GTK_FILL|GTK_EXPAND,0,0,0); + gtk_table_attach(GTK_TABLE(table),del->r,3,4,1+i*3,2+i*3, + GTK_FILL|GTK_EXPAND,0,0,0); + } + + gtk_box_pack_start(GTK_BOX(panel->subpanel_box),table,1,1,4); + subpanel_show_all_but_toplevel(panel); +} + + +static float **peakfeed=0; +static float **rmsfeed=0; + +void mixpanel_feedback(int displayit){ + int i,j; + if(!peakfeed){ + peakfeed=malloc(sizeof(*peakfeed)*(MIX_BLOCKS+5)); + rmsfeed=malloc(sizeof(*rmsfeed)*(MIX_BLOCKS+5)); + + for(i=0;i<(MIX_BLOCKS+5);i++){ + peakfeed[i]=malloc(sizeof(**peakfeed)*input_ch); + rmsfeed[i]=malloc(sizeof(**rmsfeed)*input_ch); + } + } + + if(pull_mix_feedback(peakfeed,rmsfeed)==1){ + for(j=0;jplace[i-1]),rms,peak, + input_ch,(displayit && mixpanel_visible[j])); + break; + default: + rms[j]=todB(rmsfeed[i+2][j])*.5; + peak[j]=todB(peakfeed[i+2][j])*.5; + multibar_set(MULTIBAR(mix_panels[j]->sub[i-3]),rms,peak, + input_ch,(displayit && mixpanel_visible[j])); + break; + } + } + } + } +} + +void mixpanel_reset(void){ + int i,j; + + for(j=0;jplace[0])); + multibar_reset(MULTIBAR(mix_panels[j]->place[1])); + + for(i=0;isub[i])); + + } +} + diff --git a/mutedummy.c b/mixpanel.h similarity index 51% rename from mutedummy.c rename to mixpanel.h index 10802dfc5fe6b4876fee973b1a95a4b7fa2d61ec..21ccc0a2a01c8947998f0dd5e77b0e289acd44bc 100644 --- a/mutedummy.c +++ b/mixpanel.h @@ -22,32 +22,12 @@ */ #include "postfish.h" -#include -#include -#include "readout.h" -#include "multibar.h" -#include "mainpanel.h" -#include "mutedummy.h" -extern sig_atomic_t *mute_active; -extern int input_ch; - -static int activebutton_action(GtkWidget *widget,gpointer in){ - int num=(int)in; - int active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - mute_active[num]=active; - - return FALSE; -} - -void mutedummy_create(postfish_mainpanel *mp, - GtkWidget **windowbutton, - GtkWidget **activebutton){ - int i; - - /* nothing to do here but slap an activation callback on each activebutton */ - for(i=0;ilabels+1;i++){ + for(i=0;i<=m->labels;i++){ int x=rint(((float)i)/m->labels*(widget->allocation.width-xpad*2-1))+xpad; int y=widget->allocation.height-lpad-upad; int px,py; @@ -367,17 +367,22 @@ static void draw(GtkWidget *widget,int n){ widget->style->text_gc[gc], x, y/4+upad, x, y+upad); - if(i>0){ - pango_layout_get_pixel_size(m->layout[i-1],&px,&py); + pango_layout_get_pixel_size(m->layout[i],&px,&py); + + if(i==0){ + x+=2; + y-=py; + y/=2; + }else{ x-=px+2; y-=py; y/=2; - - gdk_draw_layout (m->backing, - widget->style->text_gc[gc], - x, y+upad, - m->layout[i-1]); } + gdk_draw_layout (m->backing, + widget->style->text_gc[gc], + x, y+upad, + m->layout[i]); + } /* draw frame */ @@ -1079,18 +1084,18 @@ GtkWidget* multibar_new (int n, char **labels, float *levels, int thumbs, /* not the *proper* way to do it, but this is a one-shot */ m->levels=calloc((n+1),sizeof(*m->levels)); - m->labels=n; - memcpy(m->levels,levels,(n+1)*sizeof(*levels)); + m->labels=n-1; + memcpy(m->levels,levels,n*sizeof(*levels)); - m->layout=calloc(m->labels,sizeof(*m->layout)); - for(i=0;ilabels;i++) + m->layout=calloc(n,sizeof(*m->layout)); + for(i=0;ilayout[i]=gtk_widget_create_pango_layout(ret,labels[i]); m->dampen_flags=flags; m->thumbfocus=-1; m->thumbgrab=-1; m->thumblo=levels[0]; - m->thumbhi=levels[n]; + m->thumbhi=levels[n-1]; m->thumblo_x=val_to_pixel(m,m->thumblo); m->thumbhi_x=val_to_pixel(m,m->thumbhi); diff --git a/multicompand.c b/multicompand.c index 691155d249b5b4f4097296ad1133701f6dbb6958..f65a9bc1ad2116c84382b9192bc9dbb05f92e12f 100644 --- a/multicompand.c +++ b/multicompand.c @@ -69,7 +69,7 @@ typedef struct { float **peak; float **rms; - + int ch; } multicompand_state; multicompand_settings multi_master_set; @@ -81,17 +81,7 @@ static multicompand_state channel_state; static subband_window sw[multicomp_banks]; static feedback_generic *new_multicompand_feedback(void){ - int i; multicompand_feedback *ret=calloc(1,sizeof(*ret)); - - ret->peak=malloc(multicomp_freqs_max*sizeof(*ret->peak)); - for(i=0;ipeak[i]=malloc(input_ch*sizeof(**ret->peak)); - - ret->rms=malloc(multicomp_freqs_max*sizeof(*ret->rms)); - for(i=0;irms[i]=malloc(input_ch*sizeof(**ret->rms)); - return (feedback_generic *)ret; } @@ -109,10 +99,10 @@ static int pull_multicompand_feedback(multicompand_state *ms,float **peak,float }else{ if(peak) for(i=0;ifreq_bands;i++) - memcpy(peak[i],f->peak[i],sizeof(**peak)*input_ch); + memcpy(peak[i],f->peak[i],sizeof(**peak)*ms->ch); if(rms) for(i=0;ifreq_bands;i++) - memcpy(rms[i],f->rms[i],sizeof(**rms)*input_ch); + memcpy(rms[i],f->rms[i],sizeof(**rms)*ms->ch); if(b)*b=f->freq_bands; feedback_old(&ms->feedpool,(feedback_generic *)f); return 1; @@ -130,7 +120,7 @@ int pull_multicompand_feedback_channel(float **peak,float **rms,int *b){ static void reset_filters(multicompand_state *ms){ int i,j; for(i=0;ich;j++){ memset(&ms->over_peak[i][j],0,sizeof(peak_state)); memset(&ms->under_peak[i][j],0,sizeof(peak_state)); memset(&ms->base_peak[i][j],0,sizeof(peak_state)); @@ -151,44 +141,45 @@ void multicompand_reset(){ } -static int multicompand_load_helper(multicompand_state *ms){ +static int multicompand_load_helper(multicompand_state *ms,int ch){ int i; int qblocksize=input_size/8; memset(ms,0,sizeof(ms)); - subband_load(&ms->ss,multicomp_freqs_max,qblocksize); + ms->ch=ch; + subband_load(&ms->ss,multicomp_freqs_max,qblocksize,ch); - ms->over_attack=calloc(input_ch,sizeof(*ms->over_attack)); - ms->over_decay=calloc(input_ch,sizeof(*ms->over_decay)); + ms->over_attack=calloc(ms->ch,sizeof(*ms->over_attack)); + ms->over_decay=calloc(ms->ch,sizeof(*ms->over_decay)); - ms->under_attack=calloc(input_ch,sizeof(*ms->under_attack)); - ms->under_decay=calloc(input_ch,sizeof(*ms->under_decay)); + ms->under_attack=calloc(ms->ch,sizeof(*ms->under_attack)); + ms->under_decay=calloc(ms->ch,sizeof(*ms->under_decay)); - ms->base_attack=calloc(input_ch,sizeof(*ms->base_attack)); - ms->base_decay=calloc(input_ch,sizeof(*ms->base_decay)); + ms->base_attack=calloc(ms->ch,sizeof(*ms->base_attack)); + ms->base_decay=calloc(ms->ch,sizeof(*ms->base_decay)); for(i=0;iover_peak[i]=calloc(input_ch,sizeof(peak_state)); - ms->under_peak[i]=calloc(input_ch,sizeof(peak_state)); - ms->base_peak[i]=calloc(input_ch,sizeof(peak_state)); - ms->over_iir[i]=calloc(input_ch,sizeof(iir_state)); - ms->under_iir[i]=calloc(input_ch,sizeof(iir_state)); - ms->base_iir[i]=calloc(input_ch,sizeof(iir_state)); + ms->over_peak[i]=calloc(ms->ch,sizeof(peak_state)); + ms->under_peak[i]=calloc(ms->ch,sizeof(peak_state)); + ms->base_peak[i]=calloc(ms->ch,sizeof(peak_state)); + ms->over_iir[i]=calloc(ms->ch,sizeof(iir_state)); + ms->under_iir[i]=calloc(ms->ch,sizeof(iir_state)); + ms->base_iir[i]=calloc(ms->ch,sizeof(iir_state)); } ms->peak=calloc(multicomp_freqs_max,sizeof(*ms->peak)); ms->rms=calloc(multicomp_freqs_max,sizeof(*ms->rms)); - for(i=0;ipeak[i]=malloc(input_ch*sizeof(**ms->peak)); - for(i=0;irms[i]=malloc(input_ch*sizeof(**ms->rms)); + for(i=0;ipeak[i]=malloc(ms->ch*sizeof(**ms->peak)); + for(i=0;irms[i]=malloc(ms->ch*sizeof(**ms->rms)); return 0; } -int multicompand_load(void){ +int multicompand_load(int outch){ int i; multi_channel_set=calloc(input_ch,sizeof(*multi_channel_set)); - multicompand_load_helper(&master_state); - multicompand_load_helper(&channel_state); + multicompand_load_helper(&master_state,outch); + multicompand_load_helper(&channel_state,input_ch); for(i=0;ich;i++) filter_set(ms,msec,filter+i,attackp); } @@ -513,10 +504,20 @@ static void push_feedback(multicompand_state *ms,int bypass,int maxmaxbands){ multicompand_feedback *ff= (multicompand_feedback *) feedback_new(&ms->feedpool,new_multicompand_feedback); + + if(!ff->peak){ + ff->peak=malloc(multicomp_freqs_max*sizeof(*ff->peak)); + ff->rms=malloc(multicomp_freqs_max*sizeof(*ff->rms)); + + for(i=0;irms[i]=malloc(ms->ch*sizeof(**ff->rms)); + for(i=0;ipeak[i]=malloc(ms->ch*sizeof(**ff->peak)); + } for(i=0;ipeak[i],ms->peak[i],input_ch*sizeof(**ms->peak)); - memcpy(ff->rms[i],ms->rms[i],input_ch*sizeof(**ms->rms)); + memcpy(ff->peak[i],ms->peak[i],ms->ch*sizeof(**ms->peak)); + memcpy(ff->rms[i],ms->rms[i],ms->ch*sizeof(**ms->rms)); } ff->bypass=0; ff->freq_bands=maxmaxbands; @@ -530,13 +531,13 @@ static void multicompand_work_master(void *vs){ int maxmaxbands=0; for(i=0;ich;j++){ ms->peak[i][j]=-150.; ms->rms[i][j]=-150; } } - for(i=0;ich;i++){ int maxbands=find_maxbands(&ms->ss,i); if(maxbands>maxmaxbands)maxmaxbands=maxbands; if(multicompand_work_perchannel(ms, ms->peak, ms->rms, maxbands, i, &multi_master_set)) @@ -552,13 +553,13 @@ static void multicompand_work_channel(void *vs){ int maxmaxbands=0; for(i=0;ich;j++){ ms->peak[i][j]=-150.; ms->rms[i][j]=-150; } } - for(i=0;ich;i++){ int maxbands=find_maxbands(&ms->ss,i); if(maxbands>maxmaxbands)maxmaxbands=maxbands; if(multicompand_work_perchannel(ms, ms->peak, ms->rms, maxbands, i, multi_channel_set+i)) @@ -569,12 +570,13 @@ static void multicompand_work_channel(void *vs){ } time_linkage *multicompand_read_master(time_linkage *in){ - int visible[input_ch]; - int active[input_ch]; - subband_window *w[input_ch]; + multicompand_state *ms=&master_state; + int visible[ms->ch]; + int active[ms->ch]; + subband_window *w[ms->ch]; int i,ab=multi_master_set.active_bank; - for(i=0;ich;i++){ visible[i]=multi_master_set.panel_visible; active[i]=multi_master_set.panel_active; w[i]=&sw[ab]; @@ -609,12 +611,13 @@ time_linkage *multicompand_read_master(time_linkage *in){ } time_linkage *multicompand_read_channel(time_linkage *in){ - int visible[input_ch]; - int active[input_ch]; - subband_window *w[input_ch]; + multicompand_state *ms=&channel_state; + int visible[ms->ch]; + int active[ms->ch]; + subband_window *w[ms->ch]; int i; - for(i=0;ich;i++){ /* do any filters need updated from UI changes? */ float o_attackms=multi_channel_set[i].over_attack*.1; diff --git a/multicompand.h b/multicompand.h index 0b4f9d658abe98effd2c83a14b3a8164d98d7bf6..8621203cabb8a474d3df515beb2263ee8071e5ff 100644 --- a/multicompand.h +++ b/multicompand.h @@ -82,7 +82,7 @@ typedef struct { } multicompand_settings; extern void multicompand_reset(); -extern int multicompand_load(void); +extern int multicompand_load(int outch); extern time_linkage *multicompand_read_channel(time_linkage *in); extern time_linkage *multicompand_read_master(time_linkage *in); diff --git a/mute.c b/mute.c index 39e6231fa914276f40189aae96142c81868ae151..15aaa1dad267697eab16082b68ef3edcdad783bd 100644 --- a/mute.c +++ b/mute.c @@ -23,14 +23,13 @@ #include #include "postfish.h" +#include "mix.h" #include "mute.h" - -sig_atomic_t *mute_active; extern int input_ch; +extern sig_atomic_t *mixpanel_active; int mute_load(void){ - mute_active=calloc(input_ch,sizeof(*mute_active)); return 0; } @@ -43,7 +42,7 @@ time_linkage *mute_read(time_linkage *in){ int i; for(i=0;iactive=val; diff --git a/output.c b/output.c index de24f7796af71648fc74da6265ad4d4a70ad1a32..acf7c50ff90da9b37441b7c57c81be2ce6907e06 100644 --- a/output.c +++ b/output.c @@ -35,8 +35,10 @@ #include "suppress.h" #include "limit.h" #include "mute.h" +#include "mix.h" extern int input_size; +extern int input_rate; sig_atomic_t playback_active=0; sig_atomic_t playback_exit=0; sig_atomic_t playback_seeking=0; @@ -64,6 +66,7 @@ void pipeline_reset(){ suppress_reset(); /* clear any persistent lapping state */ limit_reset(); /* clear any persistent lapping state */ output_reset(); /* clear any persistent lapping state */ + mix_reset(); } typedef struct output_feedback{ @@ -247,6 +250,9 @@ void *playback_thread(void *dummy){ link=eq_read_channel(link); result|=link->samples; + link=mix_read(link,0,0); + result|=link->samples; + link=multicompand_read_master(link); result|=link->samples; link=singlecomp_read_master(link); @@ -267,11 +273,6 @@ void *playback_thread(void *dummy){ } - /* the limiter is single-block zero additional latency */ - for(i=0;iactive,i)) - memset(link->data[i],0,sizeof(**link->data)*input_size); - link=limit_read(link); /************/ @@ -281,7 +282,10 @@ void *playback_thread(void *dummy){ memset(rms,0,sizeof(*rms)*(input_ch+2)); memset(peak,0,sizeof(*peak)*(input_ch+2)); ch=link->channels; - rate=link->rate; + rate=input_rate; + + /* temporary! */ + if(ch>2)ch=2; /* lazy playbak setup; we couldn't do it until we had rate and channel information from the pipeline */ @@ -295,8 +299,8 @@ void *playback_thread(void *dummy){ setupp=1; } - if(audiobufsizechannels*link->samples*outbytes){ - audiobufsize=link->channels*link->samples*outbytes; + if(audiobufsizesamples*outbytes){ + audiobufsize=ch*link->samples*outbytes; if(audiobuf) audiobuf=realloc(audiobuf,sizeof(*audiobuf)*audiobufsize); else @@ -309,7 +313,7 @@ void *playback_thread(void *dummy){ float mean=0.; float divrms=0.; - for(j=0;jchannels;j++){ + for(j=0;jdata[j][i]; switch(outbytes){ @@ -358,12 +362,12 @@ void *playback_thread(void *dummy){ rms[input_ch]+= mean*mean; /* div */ - for(j=0;jchannels;j++){ + for(j=0;jdata[j][i]; if(fabs(dval)>peak[input_ch+1])peak[input_ch+1]=fabs(dval); divrms+=dval*dval; } - rms[input_ch+1]+=divrms/link->channels; + rms[input_ch+1]+=divrms/ch; } @@ -372,7 +376,7 @@ void *playback_thread(void *dummy){ rms[j]=sqrt(rms[j]); } - count+=fwrite(audiobuf,1,link->channels*link->samples*outbytes,playback_fd); + count+=fwrite(audiobuf,1,ch*link->samples*outbytes,playback_fd); /* inform Lord Vader his shuttle is ready */ push_output_feedback(peak,rms); diff --git a/postfish.h b/postfish.h index d0f8df27a3632875c00457450b307f94dbebfabb..a46aaa0ed898b15c5b97f8393842625f0de84ef5 100644 --- a/postfish.h +++ b/postfish.h @@ -50,6 +50,8 @@ #include #include +#define OUTPUT_CHANNELS 6 + static inline float todB(float x){ return logf((x)*(x)+1e-30f)*4.34294480f; } @@ -65,7 +67,7 @@ static inline float todB_a(const float *x){ } static inline float fromdB_a(float x){ - int y=1.39331762961e+06f*(x+764.6161886f); + int y=1.39331762961e+06f*((x<-400?-400:x)+764.6161886f); return *(float *)&y; } @@ -81,16 +83,19 @@ static inline float fromdB_a(float x){ #endif +#ifndef max +#define max(x,y) ((x)>(y)?(x):(y)) +#endif + + #define toOC(n) (log(n)*1.442695f-5.965784f) #define fromOC(o) (exp(((o)+5.965784f)*.693147f)) #define toBark(n) (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n)) #define fromBark(z) (102.f*(z)-2.f*pow(z,2.f)+.4f*pow(z,3.f)+pow(1.46f,z)-1.f) typedef struct time_linkage { - int size; int samples; /* normally same as size; exception is EOF */ int channels; - int rate; float **data; u_int32_t active; /* active channel bitmask */ } time_linkage; diff --git a/reverb.c b/reverb.c new file mode 100644 index 0000000000000000000000000000000000000000..3d3c5d1581dce3a242f0d9f8487ac79d5241aa8b --- /dev/null +++ b/reverb.c @@ -0,0 +1,409 @@ +/* + * + * postfish + * + * Copyright (C) 2002-2004 Monty + * + * Postfish is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * Postfish is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Postfish; see the file COPYING. If not, write to the + * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +/* The plate reverb implementation in this file is originally the work + of Steve Harris, released under the GPL2 as part of the SWH plugins + package. In the interests of proper attribution, the 'AUTHORS' file + from SWH is reproduced here: + + "[Authors] In no particular order: + + Steve Harris - general stuff + Frank Neumann - documentation, proofreading, DSP code + Juhana Sadeharju - DSP code + Joern Nettingsmeier - DSP code, bug reports and inspiration + Mark Knecht - testesting, docuementation + Pascal Haakmat - bugfixes, testing + Marcus Andersson - DSP code + Paul Winkler - documentation + Matthias Nagorni - testing, inspiration + Nathaniel Virgo - bugfixes + Patrick Shirkey - testing, inspiration + + Project maintainted by Steve Harris, Southampton UK. + steve@plugin.org.uk or swh@ecs.soton.ac.uk + + Plugin website at http://plugin.org.uk/" */ + +#include "postfish.h" +#include "reverb.h" + +typedef struct { + int size; + float *buffer[2]; + int ptr; + int delay; + float fc; + float lp[2]; + float a1a; + float a1b; + float zm1[2]; +} waveguide_nl; + +typedef struct { + float *outbuffer; + waveguide_nl w[8]; +} plate; + +typedef struct { + time_linkage out; + time_linkage outA; + time_linkage outB; + + plate *plates; + int *prevactive; + int fillstate; +} plate_state; + +extern int input_size; +extern int input_ch; + +extern float *frame_window; +plate_set *plate_channel_set; +plate_set plate_master_set; + +static plate_state channel; +static plate_state master; + +/* linear waveguide model */ + +static void waveguide_init(waveguide_nl *wg, + int size, float fc, float da, float db){ + wg->size = size; + wg->delay = size; + wg->buffer[0] = calloc(size, sizeof(float)); + wg->buffer[1] = calloc(size, sizeof(float)); + wg->ptr = 0; + wg->fc = fc; + wg->lp[0] = 0.0f; + wg->lp[1] = 0.0f; + wg->zm1[0] = 0.0f; + wg->zm1[1] = 0.0f; + wg->a1a = (1.0f - da) / (1.0f + da); + wg->a1b = (1.0f - db) / (1.0f + db); +} + +static void waveguide_nl_reset(waveguide_nl *wg){ + memset(wg->buffer[0], 0, wg->size * sizeof(float)); + memset(wg->buffer[1], 0, wg->size * sizeof(float)); + wg->lp[0] = 0.0f; + wg->lp[1] = 0.0f; + wg->zm1[0] = 0.0f; + wg->zm1[1] = 0.0f; +} + +static void waveguide_nl_set_delay(waveguide_nl *wg, int delay){ + if (delay > wg->size) { + wg->delay = wg->size; + } else if (delay < 1) { + wg->delay = 1; + } else { + wg->delay = delay; + } +} + +static void waveguide_nl_set_fc(waveguide_nl *wg, float fc){ + wg->fc = fc; +} + +static void waveguide_nl_process_lin(waveguide_nl *wg, float in0, float in1, + float *out0, float *out1){ + float tmp; + + *out0 = wg->buffer[0][(wg->ptr + wg->delay) % wg->size]; + *out0 = wg->lp[0] * (wg->fc - 1.0f) + wg->fc * *out0; + wg->lp[0] = *out0; + tmp = *out0 * -(wg->a1a) + wg->zm1[0]; + wg->zm1[0] = tmp * wg->a1a + *out0; + *out0 = tmp; + + *out1 = wg->buffer[1][(wg->ptr + wg->delay) % wg->size]; + *out1 = wg->lp[1] * (wg->fc - 1.0f) + wg->fc * *out1; + wg->lp[1] = *out1; + tmp = *out1 * -(wg->a1a) + wg->zm1[1]; + wg->zm1[1] = tmp * wg->a1a + *out1; + *out1 = tmp; + + wg->buffer[0][wg->ptr] = in0; + wg->buffer[1][wg->ptr] = in1; + wg->ptr--; + if (wg->ptr < 0) wg->ptr += wg->size; +} + +/* model the plate reverb as a set of eight linear waveguides */ + +#define LP_INNER 0.96f +#define LP_OUTER 0.983f + +#define RUN_WG(n, junct_a, junct_b) waveguide_nl_process_lin(&w[n], junct_a - out[n*2+1], junct_b - out[n*2], out+n*2, out+n*2+1) + +static void plate_reset_helper(plate_state *ps){ + int i,j; + + for(i=0;iout.channels;i++){ + for (j = 0; j < 8; j++) + waveguide_nl_reset(&ps->plates[i].w[j]); + memset(ps->plates[i].outbuffer,0, + 32*sizeof(*ps->plates[i].outbuffer)); + } + ps->fillstate=0; +} + +void plate_reset(void){ + plate_reset_helper(&master); + plate_reset_helper(&channel); +} + +static void plate_init(plate *p){ + memset(p,0,sizeof(*p)); + p->outbuffer = calloc(32, sizeof(*p->outbuffer)); + + waveguide_init(&p->w[0], 2389, LP_INNER, 0.04f, 0.0f); + waveguide_init(&p->w[1], 4742, LP_INNER, 0.17f, 0.0f); + waveguide_init(&p->w[2], 4623, LP_INNER, 0.52f, 0.0f); + waveguide_init(&p->w[3], 2142, LP_INNER, 0.48f, 0.0f); + waveguide_init(&p->w[4], 5597, LP_OUTER, 0.32f, 0.0f); + waveguide_init(&p->w[5], 3692, LP_OUTER, 0.89f, 0.0f); + waveguide_init(&p->w[6], 5611, LP_OUTER, 0.28f, 0.0f); + waveguide_init(&p->w[7], 3703, LP_OUTER, 0.29f, 0.0f); + +} + +int plate_load(int outch){ + int i; + + /* setting storage */ + memset(&plate_master_set,0,sizeof(plate_master_set)); + plate_channel_set=calloc(input_ch,sizeof(*plate_channel_set)); + + /* output linkages for master and channels */ + + master.out.channels=outch; + master.out.data=malloc(outch*sizeof(*master.out.data)); + for(i=0;iw; + float *out=ps->outbuffer; + + int pos; + const float scale = powf(p->time*.0009999f, 1.34f); + const float lpscale = 1.0f - p->damping*.001f * 0.93f; + const float wet = p->wet*.001f; + + /* waveguide reconfig */ + for (pos=0; pos<8; pos++) + waveguide_nl_set_delay(&w[pos], w[pos].size * scale); + for (pos=0; pos<4; pos++) + waveguide_nl_set_fc(&w[pos], LP_INNER * lpscale); + for (; pos<8; pos++) + waveguide_nl_set_fc(&w[pos], LP_OUTER * lpscale); + + for (pos = 0; pos < count; pos++) { + const float alpha = (out[0] + out[2] + out[4] + out[6]) * 0.5f + in[pos]; + const float beta = (out[1] + out[9] + out[14]) * 0.666666666f; + const float gamma = (out[3] + out[8] + out[11]) * 0.666666666f; + const float delta = (out[5] + out[10] + out[13]) * 0.666666666f; + const float epsilon = (out[7] + out[12] + out[15]) * 0.666666666f; + + RUN_WG(0, beta, alpha); + RUN_WG(1, gamma, alpha); + RUN_WG(2, delta, alpha); + RUN_WG(3, epsilon, alpha); + RUN_WG(4, beta, gamma); + RUN_WG(5, gamma, delta); + RUN_WG(6, delta, epsilon); + RUN_WG(7, epsilon, beta); + + if(!outB || !outC){ + outA[pos]=in[pos] * (1.0f - wet) + beta * wet; + }else{ + outA[pos]=in[pos] * (1.0f - wet); + outB[pos]= beta * wet; + outC[pos]= gamma * wet; + } + } +} + +time_linkage *plate_read_channel(time_linkage *in, + time_linkage **revA, + time_linkage **revB){ + int i,j,ch=in->channels; + plate_state *ps=&channel; + + *revA=&ps->outA; + *revB=&ps->outB; + + if(in->samples==0){ + ps->out.samples=0; + ps->outA.samples=0; + ps->outB.samples=0; + } + + ps->outA.active=0; + ps->outB.active=0; + + if(ps->fillstate==0){ + for(i=0;iprevactive[i]=plate_channel_set[i].panel_active; + ps->fillstate=1; + } + + for(i=0;iprevactive[i]){ + float *x=in->data[i]; + float *y=ps->out.data[i]; + float *yA=ps->outA.data[i]; + float *yB=ps->outB.data[i]; + + /* clear the waveguides of old state if they were inactive */ + if (!ps->prevactive[i]){ + for (j = 0; j < 8; j++) + waveguide_nl_reset(&ps->plates[i].w[j]); + memset(ps->plates[i].outbuffer,0, + 32*sizeof(*ps->plates[i].outbuffer)); + } + + /* process this plate */ + plate_compute(&plate_channel_set[i], &ps->plates[i], + x,y,yA,yB,input_size); + + if(!plate_channel_set[i].panel_active){ + /* transition to inactive */ + for(j=0;jprevactive[i]){ + /* transition to active */ + for(j=0;joutA.active |= 1<outB.active |= 1<out.data[i]; + ps->out.data[i]=in->data[i]; + in->data[i]=temp; + } + ps->prevactive[i]=plate_channel_set[i].panel_active; + } + + ps->out.active=in->active; + ps->out.samples=in->samples; + ps->outA.samples=in->samples; + ps->outB.samples=in->samples; + return &ps->out; +} + +time_linkage *plate_read_master(time_linkage *in){ + int i,j,ch=in->channels; + plate_state *ps=&master; + + if(in->samples==0){ + ps->out.samples=0; + } + + if(ps->fillstate==0){ + ps->prevactive[0]=plate_master_set.panel_active; + ps->fillstate=1; + } + + for(i=0;iprevactive[0]){ + float *x=in->data[i]; + float *y=ps->out.data[i]; + + /* clear the waveguides of old state if they were inactive */ + if (!ps->prevactive[0]){ + for (j = 0; j < 8; j++) + waveguide_nl_reset(&ps->plates[i].w[j]); + memset(ps->plates[i].outbuffer,0, + 32*sizeof(*ps->plates[i].outbuffer)); + } + + /* process this plate */ + plate_compute(&plate_master_set, &ps->plates[i], + x,y,0,0,input_size); + + if(!plate_master_set.panel_active){ + /* transition to inactive */ + for(j=0;jprevactive[0]){ + /* transition to active */ + for(j=0;jout.data[i]; + ps->out.data[i]=in->data[i]; + in->data[i]=temp; + } + } + ps->prevactive[0]=plate_master_set.panel_active; + + ps->out.active=in->active; + ps->out.samples=in->samples; + return &ps->out; +} diff --git a/reverb.h b/reverb.h new file mode 100644 index 0000000000000000000000000000000000000000..c2e47b971740aad0ada58f645a52e8f874fd6280 --- /dev/null +++ b/reverb.h @@ -0,0 +1,38 @@ +/* + * + * postfish + * + * Copyright (C) 2002-2004 Monty + * + * Postfish is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * Postfish is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Postfish; see the file COPYING. If not, write to the + * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +typedef struct { + sig_atomic_t panel_active; + sig_atomic_t panel_visible; + + sig_atomic_t time; /* 1-1000 */ + sig_atomic_t damping; /* 0.-1. * 1000 */ + sig_atomic_t wet; /* 0.-1. * 1000 */ +} plate_set; + +extern void plate_reset(void); +extern int plate_load(int outch); +extern time_linkage *plate_read_channel(time_linkage *in, + time_linkage **revA, + time_linkage **revB); +extern time_linkage *plate_read_master(time_linkage *in); diff --git a/singlecomp.c b/singlecomp.c index 355093bd7b1d1c42490d6e8c2dd9e2d75cfd4fdf..f9c92c6445d2afe353dd943627decb5b5f7b8f4e 100644 --- a/singlecomp.c +++ b/singlecomp.c @@ -63,10 +63,10 @@ typedef struct{ int mutemaskP; int mutemask0; - + int ch; } singlecomp_state; -float *window; +static float *window; singlecomp_settings singlecomp_master_set; singlecomp_settings *singlecomp_channel_set; @@ -95,9 +95,9 @@ static int pull_singlecomp_feedback(singlecomp_state *scs, float *peak,float *rm if(!f)return 0; if(peak) - memcpy(peak,f->peak,sizeof(*peak)*input_ch); + memcpy(peak,f->peak,sizeof(*peak)*scs->ch); if(rms) - memcpy(rms,f->rms,sizeof(*rms)*input_ch); + memcpy(rms,f->rms,sizeof(*rms)*scs->ch); feedback_old(&scs->feedpool,(feedback_generic *)f); return 1; } @@ -110,47 +110,46 @@ int pull_singlecomp_feedback_channel(float *peak,float *rms){ return pull_singlecomp_feedback(&channel_state,peak,rms); } -static void singlecomp_load_helper(singlecomp_state *scs){ +static void singlecomp_load_helper(singlecomp_state *scs,int ch){ int i; memset(scs,0,sizeof(scs)); - scs->activeP=calloc(input_ch,sizeof(*scs->activeP)); - scs->active0=calloc(input_ch,sizeof(*scs->active0)); + scs->ch=ch; + scs->activeP=calloc(scs->ch,sizeof(*scs->activeP)); + scs->active0=calloc(scs->ch,sizeof(*scs->active0)); - scs->o_attack=calloc(input_ch,sizeof(*scs->o_attack)); - scs->o_decay=calloc(input_ch,sizeof(*scs->o_decay)); - scs->u_attack=calloc(input_ch,sizeof(*scs->u_attack)); - scs->u_decay=calloc(input_ch,sizeof(*scs->u_decay)); - scs->b_attack=calloc(input_ch,sizeof(*scs->b_attack)); - scs->b_decay=calloc(input_ch,sizeof(*scs->b_decay)); + scs->o_attack=calloc(scs->ch,sizeof(*scs->o_attack)); + scs->o_decay=calloc(scs->ch,sizeof(*scs->o_decay)); + scs->u_attack=calloc(scs->ch,sizeof(*scs->u_attack)); + scs->u_decay=calloc(scs->ch,sizeof(*scs->u_decay)); + scs->b_attack=calloc(scs->ch,sizeof(*scs->b_attack)); + scs->b_decay=calloc(scs->ch,sizeof(*scs->b_decay)); - scs->o_iir=calloc(input_ch,sizeof(*scs->o_iir)); - scs->b_iir=calloc(input_ch,sizeof(*scs->b_iir)); - scs->u_iir=calloc(input_ch,sizeof(*scs->u_iir)); + scs->o_iir=calloc(scs->ch,sizeof(*scs->o_iir)); + scs->b_iir=calloc(scs->ch,sizeof(*scs->b_iir)); + scs->u_iir=calloc(scs->ch,sizeof(*scs->u_iir)); - scs->o_peak=calloc(input_ch,sizeof(*scs->o_peak)); - scs->b_peak=calloc(input_ch,sizeof(*scs->b_peak)); - scs->u_peak=calloc(input_ch,sizeof(*scs->u_peak)); + scs->o_peak=calloc(scs->ch,sizeof(*scs->o_peak)); + scs->b_peak=calloc(scs->ch,sizeof(*scs->b_peak)); + scs->u_peak=calloc(scs->ch,sizeof(*scs->u_peak)); - scs->out.size=input_size; - scs->out.channels=input_ch; - scs->out.rate=input_rate; - scs->out.data=malloc(input_ch*sizeof(*scs->out.data)); - for(i=0;iout.channels=scs->ch; + scs->out.data=malloc(scs->ch*sizeof(*scs->out.data)); + for(i=0;ich;i++) scs->out.data[i]=malloc(input_size*sizeof(**scs->out.data)); scs->fillstate=0; - scs->cache=malloc(input_ch*sizeof(*scs->cache)); - for(i=0;icache=malloc(scs->ch*sizeof(*scs->cache)); + for(i=0;ich;i++) scs->cache[i]=malloc(input_size*sizeof(**scs->cache)); } /* called only by initial setup */ -int singlecomp_load(void){ +int singlecomp_load(int outch){ int i; - singlecomp_load_helper(&master_state); - singlecomp_load_helper(&channel_state); + singlecomp_load_helper(&master_state,outch); + singlecomp_load_helper(&channel_state,input_ch); window=malloc(input_size/2*sizeof(*window)); for(i=0;io_peak,0,input_ch*sizeof(&scs->o_peak)); - memset(scs->u_peak,0,input_ch*sizeof(&scs->u_peak)); - memset(scs->b_peak,0,input_ch*sizeof(&scs->b_peak)); - memset(scs->o_iir,0,input_ch*sizeof(&scs->o_iir)); - memset(scs->u_iir,0,input_ch*sizeof(&scs->u_iir)); - memset(scs->b_iir,0,input_ch*sizeof(&scs->b_iir)); + memset(scs->o_peak,0,scs->ch*sizeof(&scs->o_peak)); + memset(scs->u_peak,0,scs->ch*sizeof(&scs->u_peak)); + memset(scs->b_peak,0,scs->ch*sizeof(&scs->b_peak)); + memset(scs->o_iir,0,scs->ch*sizeof(&scs->o_iir)); + memset(scs->u_iir,0,scs->ch*sizeof(&scs->u_iir)); + memset(scs->b_iir,0,scs->ch*sizeof(&scs->b_iir)); } /* called only in playback thread */ @@ -374,12 +373,12 @@ static void work_and_lapping(singlecomp_state *scs, u_int32_t mutemask0=scs->mutemask0; u_int32_t mutemaskP=scs->mutemaskP; - float peakfeed[input_ch]; - float rmsfeed[input_ch]; + float peakfeed[scs->ch]; + float rmsfeed[scs->ch]; memset(peakfeed,0,sizeof(peakfeed)); memset(rmsfeed,0,sizeof(rmsfeed)); - for(i=0;ich;i++){ int activeC= active[i] && !mute_channel_muted(mutemaskC,i); int active0= scs->active0[i]; @@ -551,10 +550,10 @@ static void work_and_lapping(singlecomp_state *scs, (singlecomp_feedback *)feedback_new(&scs->feedpool,new_singlecomp_feedback); if(!ff->peak) - ff->peak=malloc(input_ch*sizeof(*ff->peak)); + ff->peak=malloc(scs->ch*sizeof(*ff->peak)); if(!ff->rms) - ff->rms=malloc(input_ch*sizeof(*ff->rms)); + ff->rms=malloc(scs->ch*sizeof(*ff->rms)); memcpy(ff->peak,peakfeed,sizeof(peakfeed)); memcpy(ff->rms,rmsfeed,sizeof(rmsfeed)); @@ -583,7 +582,7 @@ time_linkage *singlecomp_read_helper(time_linkage *in, return &scs->out; } - for(i=0;ich;i++){ memset(scs->o_iir+i,0,sizeof(*scs->o_iir)); memset(scs->u_iir+i,0,sizeof(*scs->u_iir)); memset(scs->b_iir+i,0,sizeof(*scs->b_iir)); @@ -599,17 +598,17 @@ time_linkage *singlecomp_read_helper(time_linkage *in, scs->fillstate=1; scs->out.samples=0; - if(in->samples==in->size)goto tidy_up; + if(in->samples==input_size)goto tidy_up; - for(i=0;idata[i],0,sizeof(**in->data)*in->size); + for(i=0;ich;i++) + memset(in->data[i],0,sizeof(**in->data)*input_size); in->samples=0; /* fall through */ case 1: /* nominal processing */ work_and_lapping(scs,scset,in,&scs->out,active); - if(scs->out.samplesout.size)scs->fillstate=2; + if(scs->out.samplesfillstate=2; break; case 2: /* we've pushed out EOF already */ scs->out.samples=0; @@ -617,7 +616,7 @@ time_linkage *singlecomp_read_helper(time_linkage *in, tidy_up: { - int tozero=scs->out.size-scs->out.samples; + int tozero=input_size-scs->out.samples; if(tozero) for(i=0;iout.channels;i++) memset(scs->out.data[i]+scs->out.samples,0,sizeof(**scs->out.data)*tozero); @@ -627,20 +626,20 @@ time_linkage *singlecomp_read_helper(time_linkage *in, } time_linkage *singlecomp_read_master(time_linkage *in){ - int active[input_ch],i; + int active[master_state.ch],i; /* local copy required to avoid concurrency problems */ - for(i=0;ims=scset; @@ -300,7 +300,7 @@ static singlecomp_panel_state *singlepanel_create_helper (postfish_mainpanel *mp GtkWidget *label=gtk_label_new("compand ratio:"); GtkWidget *readout=readout_new("1.55:1"); - GtkWidget *slider=multibar_slider_new(8,compand_labels,compand_levels,1); + GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1); ps->under_compand.r=READOUT(readout); ps->under_compand.v=&ps->ms->u_ratio; @@ -323,7 +323,7 @@ static singlecomp_panel_state *singlepanel_create_helper (postfish_mainpanel *mp GtkWidget *label=gtk_label_new("attack/decay:"); GtkWidget *readout0=readout_new(" 100ms"); GtkWidget *readout1=readout_new(" 100ms"); - GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2); + GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2); ps->under_timing.r0=READOUT(readout0); ps->under_timing.r1=READOUT(readout1); @@ -349,7 +349,7 @@ static singlecomp_panel_state *singlepanel_create_helper (postfish_mainpanel *mp GtkWidget *label=gtk_label_new("lookahead:"); GtkWidget *readout=readout_new("100%"); - GtkWidget *slider=multibar_slider_new(8,per_labels,per_levels,1); + GtkWidget *slider=multibar_slider_new(9,per_labels,per_levels,1); ps->under_lookahead.r=READOUT(readout); ps->under_lookahead.v=&ps->ms->u_lookahead; @@ -397,7 +397,7 @@ static singlecomp_panel_state *singlepanel_create_helper (postfish_mainpanel *mp GtkWidget *label=gtk_label_new("compand ratio:"); GtkWidget *readout=readout_new("1.55:1"); - GtkWidget *slider=multibar_slider_new(8,compand_labels,compand_levels,1); + GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1); ps->over_compand.r=READOUT(readout); ps->over_compand.v=&ps->ms->o_ratio; @@ -420,7 +420,7 @@ static singlecomp_panel_state *singlepanel_create_helper (postfish_mainpanel *mp GtkWidget *label=gtk_label_new("attack/decay:"); GtkWidget *readout0=readout_new(" 100ms"); GtkWidget *readout1=readout_new(" 100ms"); - GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2); + GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2); ps->over_timing.r0=READOUT(readout0); ps->over_timing.r1=READOUT(readout1); @@ -446,7 +446,7 @@ static singlecomp_panel_state *singlepanel_create_helper (postfish_mainpanel *mp GtkWidget *label=gtk_label_new("lookahead:"); GtkWidget *readout=readout_new("100%"); - GtkWidget *slider=multibar_slider_new(8,per_labels,per_levels,1); + GtkWidget *slider=multibar_slider_new(9,per_labels,per_levels,1); ps->over_lookahead.r=READOUT(readout); ps->over_lookahead.v=&ps->ms->o_lookahead; @@ -490,7 +490,7 @@ static singlecomp_panel_state *singlepanel_create_helper (postfish_mainpanel *mp GtkWidget *label=gtk_label_new("compand ratio:"); GtkWidget *readout=readout_new("1.55:1"); - GtkWidget *slider=multibar_slider_new(8,compand_labels,compand_levels,1); + GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1); ps->base_compand.r=READOUT(readout); ps->base_compand.v=&ps->ms->b_ratio; @@ -513,7 +513,7 @@ static singlecomp_panel_state *singlepanel_create_helper (postfish_mainpanel *mp GtkWidget *label=gtk_label_new("attack/decay:"); GtkWidget *readout0=readout_new(" 100ms"); GtkWidget *readout1=readout_new(" 100ms"); - GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2); + GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2); ps->base_timing.r0=READOUT(readout0); ps->base_timing.r1=READOUT(readout1); @@ -539,7 +539,7 @@ static singlecomp_panel_state *singlepanel_create_helper (postfish_mainpanel *mp { ps->bar.readoutu=readout_new(" +0"); ps->bar.readouto=readout_new(" +0"); - ps->bar.slider=multibar_new(14,labels,levels,2,HI_DECAY|LO_DECAY|LO_ATTACK); + ps->bar.slider=multibar_new(15,labels,levels,2,HI_DECAY|LO_DECAY|LO_ATTACK); ps->bar.vu=&ps->ms->u_thresh; ps->bar.vo=&ps->ms->o_thresh; @@ -569,13 +569,13 @@ static float *rmsfeed=0; void singlepanel_feedback(int displayit){ int j; if(!peakfeed){ - peakfeed=malloc(sizeof(*peakfeed)*input_ch); - rmsfeed=malloc(sizeof(*rmsfeed)*input_ch); + peakfeed=malloc(sizeof(*peakfeed)*max(input_ch,OUTPUT_CHANNELS)); + rmsfeed=malloc(sizeof(*rmsfeed)*max(input_ch,OUTPUT_CHANNELS)); } if(pull_singlecomp_feedback_master(peakfeed,rmsfeed)==1) multibar_set(MULTIBAR(master_panel->bar.slider),rmsfeed,peakfeed, - input_ch,(displayit && singlecomp_master_set.panel_visible)); + OUTPUT_CHANNELS,(displayit && singlecomp_master_set.panel_visible)); /* channel panels are a bit different; we want each in its native color */ if(pull_singlecomp_feedback_channel(peakfeed,rmsfeed)==1){ diff --git a/subband.c b/subband.c index 1bfcc1fa888710ce5fb4b7d752de9edc630303de..08d5c0997853a865cf2e8630abb0684bea88e4ba 100644 --- a/subband.c +++ b/subband.c @@ -28,10 +28,9 @@ extern int input_size; extern int input_rate; -extern int input_ch; /* called only by initial setup */ -int subband_load(subband_state *f,int bands,int qblocksize){ +int subband_load(subband_state *f,int bands,int qblocksize,int ch){ int i,j; memset(f,0,sizeof(*f)); @@ -40,44 +39,42 @@ int subband_load(subband_state *f,int bands,int qblocksize){ f->fillstate=0; f->lap_samples=0; f->lap=malloc(bands*sizeof(*f->lap)); - f->cache0=malloc(input_ch*sizeof(*f->cache0)); - f->cache1=malloc(input_ch*sizeof(*f->cache1)); + f->cache0=malloc(ch*sizeof(*f->cache0)); + f->cache1=malloc(ch*sizeof(*f->cache1)); - f->lap_activeP=malloc(input_ch*sizeof(*f->lap_activeP)); - f->lap_active1=malloc(input_ch*sizeof(*f->lap_active1)); - f->lap_active0=malloc(input_ch*sizeof(*f->lap_active0)); - f->lap_activeC=malloc(input_ch*sizeof(*f->lap_activeC)); + f->lap_activeP=malloc(ch*sizeof(*f->lap_activeP)); + f->lap_active1=malloc(ch*sizeof(*f->lap_active1)); + f->lap_active0=malloc(ch*sizeof(*f->lap_active0)); + f->lap_activeC=malloc(ch*sizeof(*f->lap_activeC)); - f->visible1=malloc(input_ch*sizeof(*f->visible1)); - f->visible0=malloc(input_ch*sizeof(*f->visible0)); - f->visibleC=malloc(input_ch*sizeof(*f->visibleC)); + f->visible1=malloc(ch*sizeof(*f->visible1)); + f->visible0=malloc(ch*sizeof(*f->visible0)); + f->visibleC=malloc(ch*sizeof(*f->visibleC)); - f->effect_activeP=malloc(input_ch*sizeof(*f->effect_activeP)); - f->effect_active1=malloc(input_ch*sizeof(*f->effect_active1)); - f->effect_active0=malloc(input_ch*sizeof(*f->effect_active0)); - f->effect_activeC=malloc(input_ch*sizeof(*f->effect_activeC)); + f->effect_activeP=malloc(ch*sizeof(*f->effect_activeP)); + f->effect_active1=malloc(ch*sizeof(*f->effect_active1)); + f->effect_active0=malloc(ch*sizeof(*f->effect_active0)); + f->effect_activeC=malloc(ch*sizeof(*f->effect_activeC)); - f->wP=calloc(input_ch,sizeof(*f->wP)); - f->w1=calloc(input_ch,sizeof(*f->w1)); - f->w0=calloc(input_ch,sizeof(*f->w0)); - f->wC=calloc(input_ch,sizeof(*f->wC)); + f->wP=calloc(ch,sizeof(*f->wP)); + f->w1=calloc(ch,sizeof(*f->w1)); + f->w0=calloc(ch,sizeof(*f->w0)); + f->wC=calloc(ch,sizeof(*f->wC)); - for(i=0;icache0[i]=malloc(input_size*sizeof(**f->cache0)); - for(i=0;icache1[i]=malloc(input_size*sizeof(**f->cache1)); for(i=0;ilap[i]=malloc(input_ch*sizeof(**f->lap)); - for(j=0;jlap[i]=malloc(ch*sizeof(**f->lap)); + for(j=0;jlap[i][j]=malloc(input_size*3*sizeof(***f->lap)); } - f->out.size=input_size; - f->out.channels=input_ch; - f->out.rate=input_rate; - f->out.data=malloc(input_ch*sizeof(*f->out.data)); - for(i=0;iout.channels=ch; + f->out.data=malloc(ch*sizeof(*f->out.data)); + for(i=0;iout.data[i]=malloc(input_size*sizeof(**f->out.data)); /* fill in time window */ @@ -116,83 +113,98 @@ int subband_load_freqs(subband_state *f,subband_window *w, w->freq_bands=bands; - /* supersample the spectrum */ + /* unlike old postfish, we offer all frequencies via smoothly + supersampling the spectrum */ + /* I'm too lazy to figure out the integral symbolically, use this + fancy CPU thingy for something */ + w->ho_window=malloc(bands*sizeof(*w->ho_window)); - { - float working[f->qblocksize*4+2]; - + for(i=0;iho_window[i]=calloc((f->qblocksize*2+1),sizeof(**w->ho_window)); + + /* first, build the first-pass desired, supersampled response */ + for(j=0;j<(((f->qblocksize*2+1)/10)<<5);j++){ + float localf= .5*j*input_rate/(f->qblocksize<<6); + int localbin= j>>5; + for(i=0;i0?freq_list[i-1]:0); float thisf=freq_list[i]; float nextf=freq_list[i+1]; - memset(working,0,sizeof(working)); - - for(j=0;j<((f->qblocksize*2+1)<<5);j++){ - float localf= .5*j*input_rate/(f->qblocksize<<6); - int localbin= j>>5; - float localwin; - - if(localf>=lastf && localf=thisf && localffftwf_backward_in,0,sizeof(*f->fftwf_backward_in)* - (f->qblocksize*4+2)); - for(j=0;jqblocksize*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)); - for(j=0;jqblocksize;j++){ - float val=cos(j*M_PI/(f->qblocksize*2)); - val=sin(val*val*M_PIl*.5); - f->fftwf_forward_in[j]*= sin(val*val*M_PIl*.5); + if(localf>=lastf && localfho_window[i][localbin]+=localwin*(1./32); } - - for(;jqblocksize*3;j++) - f->fftwf_forward_in[j]=0.; - - for(;jqblocksize*4;j++){ - float val=sin((j-f->qblocksize*3)*M_PI/(f->qblocksize*2)); - val=sin(val*val*M_PIl*.5); - f->fftwf_forward_in[j]*=sin(val*val*M_PIl*.5); + } + } + j>>=5; + for(;jqblocksize*2+1;j++){ + float localf= .5*j*input_rate/(f->qblocksize<<1); + + for(i=0;i0?freq_list[i-1]:0); + float thisf=freq_list[i]; + float nextf=freq_list[i+1]; + + if(localf>=lastf && localfho_window[i][j]+=localwin*localwin; } - - /* back to frequency; this is all-real data still */ - fftwf_execute(f->fftwf_forward); - for(j=0;jqblocksize*4+2;j++) - f->fftwf_forward_out[j]/=f->qblocksize*4; - - /* now take what we learned and distill it a bit */ - w->ho_window[i]=calloc((f->qblocksize*2+1),sizeof(**w->ho_window)); - for(j=0;jqblocksize*2+1;j++) - w->ho_window[i][j]=f->fftwf_forward_out[j*2]; - - lastf=thisf; - } } + + for(i=0;ifftwf_backward_in,0,sizeof(*f->fftwf_backward_in)* + (f->qblocksize*4+2)); + for(j=0;jqblocksize*2+1;j++) + f->fftwf_backward_in[j*2]=w->ho_window[i][j]; + + fftwf_execute(f->fftwf_backward); + + /* window response in time */ + memcpy(f->fftwf_forward_in,f->fftwf_backward_out, + f->qblocksize*4*sizeof(*f->fftwf_forward_in)); + for(j=0;jqblocksize;j++){ + float val=cos(j*M_PI/(f->qblocksize*2)); + val=sin(val*val*M_PIl*.5); + f->fftwf_forward_in[j]*= sin(val*val*M_PIl*.5); + } + + for(;jqblocksize*3;j++) + f->fftwf_forward_in[j]=0.; + + for(;jqblocksize*4;j++){ + float val=sin((j-f->qblocksize*3)*M_PI/(f->qblocksize*2)); + val=sin(val*val*M_PIl*.5); + f->fftwf_forward_in[j]*=sin(val*val*M_PIl*.5); + } + + /* back to frequency; this is all-real data still */ + fftwf_execute(f->fftwf_forward); + for(j=0;jqblocksize*4+2;j++) + f->fftwf_forward_out[j]/=f->qblocksize*4; + + /* now take what we learned and distill it a bit */ + for(j=0;jqblocksize*2+1;j++) + w->ho_window[i][j]=f->fftwf_forward_out[j*2]; + + } return(0); } @@ -215,13 +227,13 @@ static void subband_work(subband_state *f, int *active){ - int i,j,k,l,off; + int i,j,k,l,off,ch=f->out.channels; float *workoff=f->fftwf_forward_in+f->qblocksize; u_int32_t mutemask=in->active; f->mutemaskC=mutemask; - for(i=0;ilap_activeC[i]= (visible[i]||active[i]) && !mute_channel_muted(mutemask,i); int content_p0= f->lap_active0[i]; @@ -320,10 +332,10 @@ static void subband_work(subband_state *f, } static void unsubband_work(subband_state *f,time_linkage *in, time_linkage *out){ - int i,j,k; + int i,j,k,ch=f->out.channels; f->lap_samples+=in->samples; - for(i=0;ilap_activeP[i]; int content_p1= f->lap_active1[i]; @@ -466,20 +478,20 @@ static void unsubband_work(subband_state *f,time_linkage *in, time_linkage *out) /* rotate full-frame data for next frame */ - memcpy(f->effect_activeP,f->effect_active1,input_ch*sizeof(*f->effect_active1)); - memcpy(f->effect_active1,f->effect_active0,input_ch*sizeof(*f->effect_active0)); - memcpy(f->effect_active0,f->effect_activeC,input_ch*sizeof(*f->effect_activeC)); + memcpy(f->effect_activeP,f->effect_active1,ch*sizeof(*f->effect_active1)); + memcpy(f->effect_active1,f->effect_active0,ch*sizeof(*f->effect_active0)); + memcpy(f->effect_active0,f->effect_activeC,ch*sizeof(*f->effect_activeC)); - memcpy(f->visible1,f->visible0,input_ch*sizeof(*f->visible0)); - memcpy(f->visible0,f->visibleC,input_ch*sizeof(*f->visibleC)); + memcpy(f->visible1,f->visible0,ch*sizeof(*f->visible0)); + memcpy(f->visible0,f->visibleC,ch*sizeof(*f->visibleC)); f->mutemaskP=f->mutemask1; f->mutemask1=f->mutemask0; f->mutemask0=f->mutemaskC; - memcpy(f->wP,f->w1,input_ch*sizeof(*f->w1)); - memcpy(f->w1,f->w0,input_ch*sizeof(*f->w0)); - memcpy(f->w0,f->wC,input_ch*sizeof(*f->wC)); + memcpy(f->wP,f->w1,ch*sizeof(*f->w1)); + memcpy(f->w1,f->w0,ch*sizeof(*f->w0)); + memcpy(f->w0,f->wC,ch*sizeof(*f->wC)); f->lap_samples-=(out?f->out.samples:0); @@ -489,7 +501,7 @@ static void unsubband_work(subband_state *f,time_linkage *in, time_linkage *out) time_linkage *subband_read(time_linkage *in, subband_state *f, subband_window **w,int *visible, int *active, void (*workfunc)(void *),void *arg){ - int i,j; + int i,j,ch=f->out.channels; switch(f->fillstate){ case 0: /* begin priming the lapping and cache */ @@ -499,7 +511,7 @@ time_linkage *subband_read(time_linkage *in, subband_state *f, } /* initially zero the lapping and cache */ - for(i=0;ibands;j++) memset(f->lap[j][i],0,sizeof(***f->lap)*input_size*2); memset(f->cache1[i],0,sizeof(**f->cache1)*input_size); @@ -511,12 +523,12 @@ time_linkage *subband_read(time_linkage *in, subband_state *f, /* 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;iactive,i); - memset(f->lap_activeP,set,sizeof(*f->lap_activeP)*input_ch); - memset(f->lap_active1,set,sizeof(*f->lap_active1)*input_ch); - memset(f->lap_active0,set,sizeof(*f->lap_active0)*input_ch); - //memset(f->lap_activeC,1,sizeof(*f->lap_activeC)*input_ch); + memset(f->lap_activeP,set,sizeof(*f->lap_activeP)*ch); + memset(f->lap_active1,set,sizeof(*f->lap_active1)*ch); + memset(f->lap_active0,set,sizeof(*f->lap_active0)*ch); + //memset(f->lap_activeC,1,sizeof(*f->lap_activeC)*ch); f->wP[i]=w[i]; f->w1[i]=w[i]; @@ -524,13 +536,13 @@ time_linkage *subband_read(time_linkage *in, subband_state *f, } - memcpy(f->effect_activeP,active,sizeof(*f->effect_activeP)*input_ch); - memcpy(f->effect_active1,active,sizeof(*f->effect_active1)*input_ch); - memcpy(f->effect_active0,active,sizeof(*f->effect_active0)*input_ch); - //memset(f->effect_activeC,1,sizeof(*f->effect_activeC)*input_ch); + memcpy(f->effect_activeP,active,sizeof(*f->effect_activeP)*ch); + memcpy(f->effect_active1,active,sizeof(*f->effect_active1)*ch); + memcpy(f->effect_active0,active,sizeof(*f->effect_active0)*ch); + //memset(f->effect_activeC,1,sizeof(*f->effect_activeC)*ch); - memset(f->visible1,0,sizeof(*f->visible1)*input_ch); - memset(f->visible0,0,sizeof(*f->visible0)*input_ch); + memset(f->visible1,0,sizeof(*f->visible1)*ch); + memset(f->visible0,0,sizeof(*f->visible0)*ch); f->mutemaskP=in->active; f->mutemask1=in->active; @@ -540,17 +552,17 @@ time_linkage *subband_read(time_linkage *in, subband_state *f, memset(f->fftwf_forward_in,0,f->qblocksize*4*sizeof(*f->fftwf_forward_in)); /* extrapolation mechanism; avoid harsh transients at edges */ - for(i=0;ilap_active0[i]){ preextrapolate_helper(in->data[i],input_size, f->cache0[i],input_size); - if(in->samplessize) + if(in->samplescache0[i],input_size, in->data[i],in->samples, in->data[i]+in->samples, - in->size-in->samples); + input_size-in->samples); } } @@ -560,10 +572,10 @@ time_linkage *subband_read(time_linkage *in, subband_state *f, f->fillstate=1; f->out.samples=0; - if(in->samples==in->size)goto tidy_up; + if(in->samples==input_size)goto tidy_up; - for(i=0;idata[i],0,sizeof(**in->data)*in->size); + for(i=0;idata[i],0,sizeof(**in->data)*input_size); in->samples=0; /* fall through */ @@ -571,13 +583,13 @@ time_linkage *subband_read(time_linkage *in, subband_state *f, /* extrapolation mechanism; avoid harsh transients at edges */ - if(in->samplessize) - for(i=0;isamplesactive,i)) postextrapolate_helper(f->cache0[i],input_size, in->data[i],in->samples, in->data[i]+in->samples, - in->size-in->samples); + input_size-in->samples); } subband_work(f,in,w,visible,active); @@ -586,29 +598,29 @@ time_linkage *subband_read(time_linkage *in, subband_state *f, f->fillstate=2; f->out.samples=0; - if(in->samples==in->size)goto tidy_up; + if(in->samples==input_size)goto tidy_up; - for(i=0;idata[i],0,sizeof(**in->data)*in->size); + for(i=0;idata[i],0,sizeof(**in->data)*input_size); in->samples=0; /* fall through */ case 2: /* nominal processing */ - if(in->samplessize) - for(i=0;isamplesactive,i)) postextrapolate_helper(f->cache0[i],input_size, in->data[i],in->samples, in->data[i]+in->samples, - in->size-in->samples); + input_size-in->samples); } subband_work(f,in,w,visible,active); workfunc(arg); unsubband_work(f,in,&f->out); - if(f->out.samplesout.size)f->fillstate=3; + if(f->out.samplesfillstate=3; break; case 3: /* we've pushed out EOF already */ @@ -618,7 +630,7 @@ time_linkage *subband_read(time_linkage *in, subband_state *f, tidy_up: { - int tozero=f->out.size-f->out.samples; + int tozero=input_size-f->out.samples; if(tozero) for(i=0;iout.channels;i++) memset(f->out.data[i]+f->out.samples,0,sizeof(**f->out.data)*tozero); diff --git a/subband.h b/subband.h index d59c9453493719ab67b1dbf626526b0a837ae249..5daeef307ded2593ef82265a6d7c786c514773a3 100644 --- a/subband.h +++ b/subband.h @@ -80,7 +80,7 @@ typedef struct { -extern int subband_load(subband_state *f,int bands, int qb); +extern int subband_load(subband_state *f,int bands, int qb,int ch); extern int subband_load_freqs(subband_state *f,subband_window *w, const float *freq_list,int bands); diff --git a/suppress.c b/suppress.c index 6bc8e3e6fa8249ae649bb39182b2bb79c05f6f55..9ecc92c88f53da1de6402363ef634ada05b66573 100644 --- a/suppress.c +++ b/suppress.c @@ -104,7 +104,7 @@ int suppress_load(void){ suppress_channel_set.active=calloc(input_ch,sizeof(*suppress_channel_set.active)); - subband_load(&channel_state.ss,suppress_freqs,qblocksize); + subband_load(&channel_state.ss,suppress_freqs,qblocksize,input_ch); subband_load_freqs(&channel_state.ss,&sw,suppress_freq_list,suppress_freqs); for(i=0;itiming.r0=READOUT(readout_new("10.0ms")); ps->timing.r1=READOUT(readout_new("10.0ms")); @@ -230,7 +230,7 @@ static suppress_panel_state *suppresspanel_create_helper(postfish_mainpanel *mp, gtk_widget_set_name(label,"scalemarker"); ps->bars[i].readoutc=READOUT(readout_new("1.55:1")); - ps->bars[i].cslider=multibar_slider_new(4,compand_labels,compand_levels,1); + ps->bars[i].cslider=multibar_slider_new(5,compand_labels,compand_levels,1); ps->bars[i].sp=ps; ps->bars[i].v=sset->ratio+i; ps->bars[i].number=i; diff --git a/version.h b/version.h index 33c5d2a752e6361f058af1cf866dd7c6624922be..a37e71b61672d799c39f7a674fece6ead7134ce2 100644 --- a/version.h +++ b/version.h @@ -1,2 +1,2 @@ #define VERSION "$Id$ " -/* DO NOT EDIT: Automated versioning hack [Mon Apr 26 03:35:14 EDT 2004] */ +/* DO NOT EDIT: Automated versioning hack [Mon May 17 04:15:01 EDT 2004] */