From 592708487c925df6702d5892414276caa20a3a23 Mon Sep 17 00:00:00 2001 From: Christopher Montgomery Date: Wed, 14 Apr 2004 04:50:38 +0000 Subject: [PATCH] Must... get... changes... under... source... control... Subversion is not scary, and there are no monsters under my bed. Monty git-svn-id: https://svn.xiph.org/trunk/postfish@6506 0101bb08-14d6-0310-b084-bc0e0c8e3800 --- Makefile | 25 +- bessel.c | 351 ++++++++++++++++++++++- bessel.h | 69 ++++- compandpanel.c | 556 +++++++++++++++--------------------- compandpanel.h | 6 +- declip.c | 9 +- eq.c | 2 +- eq.h | 5 +- freq.c | 6 +- freq.h | 3 +- input.c | 5 +- limit.c | 244 ++++++++++++++++ limit.h | 33 +++ limitpanel.c | 190 +++++++++++++ limitpanel.h | 30 ++ main.c | 9 + mainpanel.c | 438 ++++++++++++++++------------ mainpanel.h | 8 + multibar.c | 17 +- multicompand.c | 738 +++++++++++++++--------------------------------- multicompand.h | 28 +- output.c | 22 +- postfish-gtkrc | 12 +- postfish.h | 33 ++- readout.c | 2 +- readout.h | 1 + reconstruct.c | 3 +- rexperiment.c | 295 +++++++++++++++++++ singlecomp.c | 521 ++++++++++++++++++++++++++++++++++ singlecomp.h | 54 ++++ singlepanel.c | 582 ++++++++++++++++++++++++++++++++++++++ singlepanel.h | 30 ++ subband.c | 18 +- subband.h | 3 +- subpanel.c | 1 - suppress.c | 204 +++++++++++++ suppress.h | 46 +++ suppresspanel.c | 242 ++++++++++++++++ suppresspanel.h | 26 ++ version.h | 2 +- windowbutton.c | 5 + 41 files changed, 3749 insertions(+), 1125 deletions(-) create mode 100644 limit.c create mode 100644 limit.h create mode 100644 limitpanel.c create mode 100644 limitpanel.h create mode 100644 rexperiment.c create mode 100644 singlecomp.c create mode 100644 singlecomp.h create mode 100644 singlepanel.c create mode 100644 singlepanel.h create mode 100644 suppress.c create mode 100644 suppress.h create mode 100644 suppresspanel.c create mode 100644 suppresspanel.h diff --git a/Makefile b/Makefile index f1ecb9b..aba50b3 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,8 @@ # Fuck the horse it rode in on # and Fuck its little dog Libtool too -CC=gcc +ADD_DEF= -DUGLY_IEEE754_FLOAT32_HACK=1 +CC=gcc LD=gcc INSTALL=install PREFIX=/usr/local @@ -10,34 +11,26 @@ BINDIR=$PREFIX/bin ETCDIR=/etc MANDIR=$PREFIX/man -# is this a platform that uses IEEE 754/854 32 bit floats? The -# following is good for a speedup on most of these systems, otherwise -# comment it out. Using this define on a system where a 'float' is -# *not* an IEEE 32 bit float will destroy, destroy, destroy the audio. - -IEEE=-DNASTY_IEEE_FLOAT32_HACK_IS_FASTER_THAN_LOG=1 - - - - 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 + bessel.c suppresspanel.c suppress.c singlecomp.c singlepanel.c \ + limit.c limitpanel.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 + bessel.o suppresspanel.o suppress.o singlecomp.o singlepanel.o \ + limit.o limitpanel.o GCF = `pkg-config --cflags gtk+-2.0` -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED all: - $(MAKE) target CFLAGS="-W -O3 -ffast-math $(GCF) $(IEEE)" + $(MAKE) target CFLAGS="-O3 -ffast-math -fomit-frame-pointer $(GCF) $(ADD_DEF)" debug: - $(MAKE) target CFLAGS="-g -W -D__NO_MATH_INLINES $(GCF) $(IEEE)" + $(MAKE) target CFLAGS="-g -Wall -W -Wno-unused-parameter -D__NO_MATH_INLINES $(GCF) $(ADD_DEF)" profile: - $(MAKE) target CFLAGS="-W -pg -g -O3 -ffast-math $(GCF) $(IEEE)" LIBS="-lgprof-helper" + $(MAKE) target CFLAGS="-pg -g -O3 -ffast-math $(GCF) $(ADD_DEF)" LIBS="-lgprof-helper" clean: rm -f $(OBJ) *.d gmon.out diff --git a/bessel.c b/bessel.c index 31ee6b3..9813da8 100644 --- a/bessel.c +++ b/bessel.c @@ -23,20 +23,52 @@ /* code derived directly from mkfilter by the late A.J. Fisher, University of York September 1992; this - is only the minimum code needed to build an arbitrary 2nd order - Bessel filter */ + is only the minimum code needed to build an arbitrary Bessel filter */ #include "postfish.h" - -#define TWOPI (2.0 * M_PIl) -#define EPS 1e-10 -#define MAXORDER 2 -#define MAXPZ 4 +#include "bessel.h" typedef struct { double re, im; } complex; +static complex bessel_poles[] = { + { -1.00000000000e+00, 0.00000000000e+00}, + { -1.10160133059e+00, 6.36009824757e-01}, + { -1.32267579991e+00, 0.00000000000e+00}, + { -1.04740916101e+00, 9.99264436281e-01}, + { -1.37006783055e+00, 4.10249717494e-01}, + { -9.95208764350e-01, 1.25710573945e+00}, + { -1.50231627145e+00, 0.00000000000e+00}, + { -1.38087732586e+00, 7.17909587627e-01}, + { -9.57676548563e-01, 1.47112432073e+00}, + { -1.57149040362e+00, 3.20896374221e-01}, + { -1.38185809760e+00, 9.71471890712e-01}, + { -9.30656522947e-01, 1.66186326894e+00}, + { -1.68436817927e+00, 0.00000000000e+00}, + { -1.61203876622e+00, 5.89244506931e-01}, + { -1.37890321680e+00, 1.19156677780e+00}, + { -9.09867780623e-01, 1.83645135304e+00}, + { -1.75740840040e+00, 2.72867575103e-01}, + { -1.63693941813e+00, 8.22795625139e-01}, + { -1.37384121764e+00, 1.38835657588e+00}, + { -8.92869718847e-01, 1.99832584364e+00}, + { -1.85660050123e+00, 0.00000000000e+00}, + { -1.80717053496e+00, 5.12383730575e-01}, + { -1.65239648458e+00, 1.03138956698e+00}, + { -1.36758830979e+00, 1.56773371224e+00}, + { -8.78399276161e-01, 2.14980052431e+00}, + { -1.92761969145e+00, 2.41623471082e-01}, + { -1.84219624443e+00, 7.27257597722e-01}, + { -1.66181024140e+00, 1.22110021857e+00}, + { -1.36069227838e+00, 1.73350574267e+00}, + { -8.65756901707e-01, 2.29260483098e+00}, +}; + +#define TWOPI (2.0 * M_PIl) +#define EPS 1e-10 +#define MAXPZ 8 + typedef struct { complex poles[MAXPZ], zeros[MAXPZ]; int numpoles, numzeros; @@ -66,6 +98,11 @@ static complex csub(complex z1, complex z2){ return z1; } +static complex cconj(complex z){ + z.im = -z.im; + return z; +} + static complex eval(complex coeffs[], int npz, complex z){ complex sum = (complex){0.0,0.0}; int i; @@ -105,8 +142,8 @@ static void expand(complex pz[], int npz, complex coeffs[]){ } } -double mkbessel_2(double raw_alpha,double *ycoeff0,double *ycoeff1){ - int i; +double mkbessel(double raw_alpha,int order,double *ycoeff){ + int i,p= (order*order)/4; pzrep splane, zplane; complex topcoeffs[MAXPZ+1], botcoeffs[MAXPZ+1]; double warped_alpha; @@ -115,8 +152,11 @@ double mkbessel_2(double raw_alpha,double *ycoeff0,double *ycoeff1){ memset(&splane,0,sizeof(splane)); memset(&zplane,0,sizeof(zplane)); - splane.poles[splane.numpoles++] = (complex){ -1.10160133059e+00, 6.36009824757e-01}; - splane.poles[splane.numpoles++] = (complex){ -1.10160133059e+00, -6.36009824757e-01}; + if (order & 1) splane.poles[splane.numpoles++] = bessel_poles[p++]; + for (i = 0; i < order/2; i++){ + splane.poles[splane.numpoles++] = bessel_poles[p]; + splane.poles[splane.numpoles++] = cconj(bessel_poles[p++]); + } warped_alpha = tan(M_PIl * raw_alpha) / M_PIl; for (i = 0; i < splane.numpoles; i++){ @@ -137,11 +177,296 @@ double mkbessel_2(double raw_alpha,double *ycoeff0,double *ycoeff1){ expand(zplane.poles, zplane.numpoles, botcoeffs); dc_gain = evaluate(topcoeffs, zplane.numzeros, botcoeffs, zplane.numpoles, (complex){1.0,0.0}); - *ycoeff0 = -(botcoeffs[0].re / botcoeffs[zplane.numpoles].re); - *ycoeff1 = -(botcoeffs[1].re / botcoeffs[zplane.numpoles].re); + for(i=0;ic[0],d_c0=decay->c[0]; + double a_c1=attack->c[1],d_c1=decay->c[1]; + double a_g=attack->g, d_g=decay->g; + + double x0=is->x[0],x1=is->x[1]; + double y0=is->y[0],y1=is->y[1]; + int state=is->state; + int i=0; + + if(x[0]>y0)state=0; + + while(i=n)break; + if(x[i]>y0){ + state=0; + break; + } + } + } + } + + is->x[0]=x0;is->x[1]=x1; + is->y[0]=y0;is->y[1]=y1; + is->state=state; + +} + +/* allow decay to proceed in freefall */ +void compute_iir_freefall1(float *x, int n, iir_state *is, + iir_filter *decay){ + double d_c0=decay->c[0]; + + double x0=is->x[0]; + double y0=is->y[0]; + int i=0; + + while(iyd)yd=x[i]; + + x0=x[i]; + x[i]=y0=yd; + i++; + } + + is->x[0]=x0; + is->y[0]=y0; + +} + +void compute_iir_freefall2(float *x, int n, iir_state *is, + iir_filter *decay){ + double d_c0=decay->c[0]; + double d_c1=decay->c[1]; + + 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]; + double d_c1=decay->c[1]; + double d_c2=decay->c[2]; + + double x0=is->x[0],y0=is->y[0]; + double x1=is->x[1],y1=is->y[1]; + double x2=is->x[2],y2=is->y[2]; + int i=0; + + while(iyd)yd=x[i]; + + x2=x1;x1=x0;x0=x[i]; + y2=y1;y1=y0;x[i]=y0=yd; + i++; + } + + is->x[0]=x0;is->y[0]=y0; + is->x[1]=x1;is->y[1]=y1; + is->x[2]=x2;is->y[2]=y2; + +} + +void compute_iir_freefall4(float *x, int n, iir_state *is, + iir_filter *decay){ + double d_c0=decay->c[0]; + double d_c1=decay->c[1]; + double d_c2=decay->c[2]; + double d_c3=decay->c[3]; + + double x0=is->x[0],y0=is->y[0]; + double x1=is->x[1],y1=is->y[1]; + double x2=is->x[2],y2=is->y[2]; + double x3=is->x[3],y3=is->y[3]; + int i=0; + + while(iyd)yd=x[i]; + + x3=x2;x2=x1;x1=x0;x0=x[i]; + y3=y2;y2=y1;y1=y0;x[i]=y0=yd; + i++; + } + + is->x[0]=x0;is->y[0]=y0; + is->x[1]=x1;is->y[1]=y1; + is->x[2]=x2;is->y[2]=y2; + is->x[3]=x3;is->y[3]=y3; + +} + +/* symmetric filter computation */ + +void compute_iir_symmetric2(float *x, int n, iir_state *is, + iir_filter *filter){ + double c0=filter->c[0]; + double c1=filter->c[1]; + double g=filter->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(ix[0]=x0; + is->x[1]=x1; + is->y[0]=y0; + is->y[1]=y1; + +} + +void compute_iir_symmetric3(float *x, int n, iir_state *is, + iir_filter *filter){ + double c0=filter->c[0]; + double c1=filter->c[1]; + double c2=filter->c[2]; + double g=filter->g; + + double x0=is->x[0],y0=is->y[0]; + double x1=is->x[1],y1=is->y[1]; + double x2=is->x[2],y2=is->y[2]; + + int i=0; + + while(ix[0]=x0;is->y[0]=y0; + is->x[1]=x1;is->y[1]=y1; + is->x[2]=x2;is->y[2]=y2; + +} + +void compute_iir_symmetric4(float *x, int n, iir_state *is, + iir_filter *filter){ + double c0=filter->c[0]; + double c1=filter->c[1]; + double c2=filter->c[2]; + double c3=filter->c[3]; + double g=filter->g; + + double x0=is->x[0],y0=is->y[0]; + double x1=is->x[1],y1=is->y[1]; + double x2=is->x[2],y2=is->y[2]; + double x3=is->x[3],y3=is->y[3]; + + int i=0; + + while(ix[0]=x0;is->y[0]=y0; + is->x[1]=x1;is->y[1]=y1; + is->x[2]=x2;is->y[2]=y2; + is->x[3]=x3;is->y[3]=y3; + +} + + +/* filter decision wrapper */ +void compute_iir2(float *x, int n, iir_state *is, + iir_filter *attack, iir_filter *decay){ + + if (attack->alpha > decay->alpha){ + /* fast attack, slow decay */ + compute_iir_fast_attack2(x, n, is, attack, decay); + }else{ + compute_iir_symmetric2(x, n, is, attack); + } +} diff --git a/bessel.h b/bessel.h index da1d8e0..5a0e58a 100644 --- a/bessel.h +++ b/bessel.h @@ -21,4 +21,71 @@ * */ -extern double mkbessel_2(double raw_alpha,double *ycoeff0,double *ycoeff1); +#include "postfish.h" +extern int input_rate; + +#define MAXORDER 4 + +typedef struct { + double c[MAXORDER]; + double g; + int order; + float alpha; + float Hz; + float ms; +} iir_filter; + +static inline long impulse_ahead2(float alpha){ + return rint(.13f/alpha); +} +static inline long impulse_ahead3(float alpha){ + return rint(.22f/alpha); +} +static inline long impulse_ahead4(float alpha){ + return rint(.32f/alpha); +} + +static inline long step_ahead(float alpha){ + return rint(.6f/alpha); +} + +static inline float step_freq(long ahead){ + return input_rate*.6f/ahead; +} + +static inline float impulse_freq2(long ahead){ + return input_rate*.13f/ahead; +} +static inline float impulse_freq3(long ahead){ + return input_rate*.22f/ahead; +} +static inline float impulse_freq4(long ahead){ + return input_rate*.32f/ahead; +} + +typedef struct { + double x[MAXORDER]; + double y[MAXORDER]; + int state; +} iir_state; + +extern double mkbessel(double raw_alpha,int order,double *ycoeff); +extern void compute_iir_fast_attack2(float *x, int n, iir_state *is, + iir_filter *attack, iir_filter *decay); +extern void compute_iir_symmetric2(float *x, int n, iir_state *is, + iir_filter *filter); +extern void compute_iir_symmetric3(float *x, int n, iir_state *is, + iir_filter *filter); +extern void compute_iir_symmetric4(float *x, int n, iir_state *is, + iir_filter *filter); +extern void compute_iir2(float *x, int n, iir_state *is, + iir_filter *attack, iir_filter *decay); +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_freefall3(float *x, int n, iir_state *is, + iir_filter *decay); +extern void compute_iir_freefall4(float *x, int n, iir_state *is, + iir_filter *decay); + diff --git a/compandpanel.c b/compandpanel.c index 2c0bb85..b80dac6 100644 --- a/compandpanel.c +++ b/compandpanel.c @@ -59,12 +59,13 @@ static int bank_active=2; static cbar bars[multicomp_freqs_max+1]; static int inactive_updatep=1; -static void under_compand_change(GtkWidget *w,gpointer in){ +static void compand_change(GtkWidget *w,Readout *r,sig_atomic_t *var){ char buffer[80]; - Readout *r=(Readout *)in; float val=1./multibar_get_value(MULTIBAR(w),0); - if(val>=10){ + if(val==1.){ + sprintf(buffer," off"); + }else if(val>=10){ sprintf(buffer,"%4.1f:1",val); }else if(val>=1){ sprintf(buffer,"%4.2f:1",val); @@ -76,197 +77,73 @@ static void under_compand_change(GtkWidget *w,gpointer in){ readout_set(r,buffer); - c.under_ratio=rint(val*1000.); + *var=rint(val*1000.); +} +static void under_compand_change(GtkWidget *w,gpointer in){ + compand_change(w,(Readout *)in,&c.under_ratio); } static void over_compand_change(GtkWidget *w,gpointer in){ - char buffer[80]; - Readout *r=(Readout *)in; - float val=1./multibar_get_value(MULTIBAR(w),0); - - if(val>=10){ - sprintf(buffer,"%4.1f:1",val); - }else if(val>=1){ - sprintf(buffer,"%4.2f:1",val); - }else if(val>.10001){ - sprintf(buffer,"1:%4.2f",1./val); - }else{ - sprintf(buffer,"1:%4.1f",1./val); - } + compand_change(w,(Readout *)in,&c.over_ratio); +} - readout_set(r,buffer); - - c.over_ratio=rint(val*1000.); +static void base_compand_change(GtkWidget *w,gpointer in){ + compand_change(w,(Readout *)in,&c.base_ratio); } -static void suppress_compand_change(GtkWidget *w,gpointer in){ +static void timing_display(GtkWidget *w,Readout *r,float v){ char buffer[80]; - Readout *r=(Readout *)in; - float val=1./multibar_get_value(MULTIBAR(w),0); - if(val>.10001){ - sprintf(buffer,"1:%4.2f",1./val); + if(v<10){ + sprintf(buffer,"%4.2fms",v); + }else if(v<100){ + sprintf(buffer,"%4.1fms",v); + }else if (v<1000){ + sprintf(buffer,"%4.0fms",v); + }else if (v<10000){ + sprintf(buffer,"%4.2fs",v/1000.); }else{ - sprintf(buffer,"1:%4.1f",1./val); + sprintf(buffer,"%4.1fs",v/1000.); } readout_set(r,buffer); - - c.suppress_ratio=rint(val*1000.); -} - -static void under_limit_change(GtkWidget *w,gpointer in){ - char buffer[80]; - Readout *r=(Readout *)in; - float val=140.-multibar_get_value(MULTIBAR(w),0); - - sprintf(buffer,"%3ddB",(int)rint(val)); - readout_set(r,buffer); - - c.under_limit=rint(val*10.); -} - -static void over_limit_change(GtkWidget *w,gpointer in){ - char buffer[80]; - Readout *r=(Readout *)in; - float val=140.-multibar_get_value(MULTIBAR(w),0); - - sprintf(buffer,"%3ddB",(int)rint(val)); - readout_set(r,buffer); - - c.over_limit=rint(val*10.); } static void under_timing_change(GtkWidget *w,gpointer in){ - char buffer[80]; multireadout *r=(multireadout *)in; float attack=multibar_get_value(MULTIBAR(w),0); float decay=multibar_get_value(MULTIBAR(w),1); - if(attack<10){ - sprintf(buffer,"%4.2fms",attack); - }else if(attack<100){ - sprintf(buffer,"%4.1fms",attack); - }else if (attack<1000){ - sprintf(buffer,"%4.0fms",attack); - }else if (attack<10000){ - sprintf(buffer,"%4.2fs",attack/1000.); - }else{ - sprintf(buffer,"%4.1fs",attack/1000.); - } - - readout_set(r->r0,buffer); - - if(decay<10){ - sprintf(buffer,"%4.2fms",decay); - }else if (decay<100){ - sprintf(buffer,"%4.1fms",decay); - }else if (decay<1000){ - sprintf(buffer,"%4.0fms",decay); - }else if (decay<10000){ - sprintf(buffer,"%4.2fs",decay/1000.); - }else{ - sprintf(buffer,"%4.1fs",decay/1000.); - } - - readout_set(r->r1,buffer); - + timing_display(w,r->r0,attack); + timing_display(w,r->r1,decay); + multicompand_under_attack_set(attack); - multicompand_under_decay_set(decay); - + multicompand_under_decay_set(decay); } static void over_timing_change(GtkWidget *w,gpointer in){ - char buffer[80]; multireadout *r=(multireadout *)in; float attack=multibar_get_value(MULTIBAR(w),0); float decay=multibar_get_value(MULTIBAR(w),1); - if(attack<10){ - sprintf(buffer,"%4.2fms",attack); - }else if(attack<100){ - sprintf(buffer,"%4.1fms",attack); - }else if (attack<1000){ - sprintf(buffer,"%4.0fms",attack); - }else if (attack<10000){ - sprintf(buffer,"%4.2fs",attack/1000.); - }else{ - sprintf(buffer,"%4.1fs",attack/1000.); - } - - readout_set(r->r0,buffer); - - if(decay<10){ - sprintf(buffer,"%4.2fms",decay); - }else if (decay<100){ - sprintf(buffer,"%4.1fms",decay); - }else if (decay<1000){ - sprintf(buffer,"%4.0fms",decay); - }else if (decay<10000){ - sprintf(buffer,"%4.2fs",decay/1000.); - }else{ - sprintf(buffer,"%4.1fs",decay/1000.); - } - - readout_set(r->r1,buffer); + timing_display(w,r->r0,attack); + timing_display(w,r->r1,decay); multicompand_over_attack_set(attack); multicompand_over_decay_set(decay); } -static void suppress_timing_change(GtkWidget *w,gpointer in){ - char buffer[80]; +static void base_timing_change(GtkWidget *w,gpointer in){ multireadout *r=(multireadout *)in; float attack=multibar_get_value(MULTIBAR(w),0); float decay=multibar_get_value(MULTIBAR(w),1); - float release=multibar_get_value(MULTIBAR(w),2); - - if(attack<10){ - sprintf(buffer,"%4.2fms",attack); - }else if(attack<100){ - sprintf(buffer,"%4.1fms",attack); - }else if (attack<1000){ - sprintf(buffer,"%4.0fms",attack); - }else if (attack<10000){ - sprintf(buffer,"%4.2fs",attack/1000.); - }else{ - sprintf(buffer,"%4.1fs",attack/1000.); - } - - readout_set(r->r0,buffer); - - if(decay<10){ - sprintf(buffer,"%4.2fms",decay); - }else if (decay<100){ - sprintf(buffer,"%4.1fms",decay); - }else if (decay<1000){ - sprintf(buffer,"%4.0fms",decay); - }else if (decay<10000){ - sprintf(buffer,"%4.2fs",decay/1000.); - }else{ - sprintf(buffer,"%4.1fs",decay/1000.); - } - - readout_set(r->r1,buffer); - if(release<10){ - sprintf(buffer,"%4.2fms",release); - }else if (release<100){ - sprintf(buffer,"%4.1fms",release); - }else if (release<1000){ - sprintf(buffer,"%4.0fms",release); - }else if (release<10000){ - sprintf(buffer,"%4.2fs",release/1000.); - }else{ - sprintf(buffer,"%4.1fs",release/1000.); - } - - readout_set(r->r2,buffer); + timing_display(w,r->r0,attack); + timing_display(w,r->r1,decay); - multicompand_suppress_attack_set(attack); - multicompand_suppress_decay_set(decay); - multicompand_suppress_release_set(release); + multicompand_base_attack_set(attack); + multicompand_base_decay_set(decay); } @@ -275,7 +152,7 @@ static void under_lookahead_change(GtkWidget *w,gpointer in){ Readout *r=(Readout *)in; float val=multibar_get_value(MULTIBAR(w),0); - sprintf(buffer,"%5.1f%%",val); + sprintf(buffer,"%3.0f%%",val); readout_set(r,buffer); c.under_lookahead=rint(val*10.); @@ -286,16 +163,14 @@ static void over_lookahead_change(GtkWidget *w,gpointer in){ Readout *r=(Readout *)in; float val=multibar_get_value(MULTIBAR(w),0); - sprintf(buffer,"%5.1f%%",val); + sprintf(buffer,"%3.0f%%",val); readout_set(r,buffer); c.over_lookahead=rint(val*10.); } - static int updating_av_slider=0; static void average_change(GtkWidget *w,gpointer in){ - char buffer[80]; cbar *b=bars+multicomp_freqs_max; float o,u; float oav=0,uav=0; @@ -306,8 +181,8 @@ static void average_change(GtkWidget *w,gpointer in){ /* compute the current average */ for(i=0;islider),0); - sprintf(buffer,"%+4.0fdB",u); + sprintf(buffer,"%+4ddB",u); readout_set(READOUT(b->readoutu),buffer); - u=rint(u*10.); bc[bank_active].static_u[b->number]=u; o=multibar_get_value(MULTIBAR(b->slider),1); - sprintf(buffer,"%+4.0fdB",o); + sprintf(buffer,"%+4ddB",o); readout_set(READOUT(b->readouto),buffer); - o=rint(o*10.); bc[bank_active].static_o[b->number]=o; if(inactive_updatep){ - /* keep the inactive banks also tracking settings, but only where it - makes sense */ + /* keep the inactive banks also tracking settings */ switch(bank_active){ case 0: + if(b->number==0){ + bc[2].static_o[0]+=o-bc[2].static_o[1]; + bc[2].static_u[0]+=u-bc[2].static_u[1]; + } + if (b->number<9){ + int adj; + + /* convolutions for roundoff behavior */ + if(b->number>0){ + adj=(bc[1].static_o[b->number*2-1]*2 - + bc[1].static_o[b->number*2-2]-bc[1].static_o[b->number*2])/2; + bc[1].static_o[b->number*2-1]= + (bc[1].static_o[b->number*2-2]+o)/2+adj; + + adj=(bc[1].static_u[b->number*2-1]*2 - + bc[1].static_u[b->number*2-2]-bc[1].static_u[b->number*2])/2; + bc[1].static_u[b->number*2-1]= + (bc[1].static_u[b->number*2-2]+u)/2+adj; + + adj=(bc[2].static_o[b->number*3-1]*3 - + bc[2].static_o[b->number*3-2] - + bc[2].static_o[b->number*3-2] - + bc[2].static_o[b->number*3+1])/3; + bc[2].static_o[b->number*3-1]= + (bc[2].static_o[b->number*3-2]+ + bc[2].static_o[b->number*3-2]+ + o)/3+adj; + + adj=(bc[2].static_o[b->number*3]*3 - + bc[2].static_o[b->number*3-2] - + bc[2].static_o[b->number*3+1] - + bc[2].static_o[b->number*3+1])/3; + bc[2].static_o[b->number*3]= + (bc[2].static_o[b->number*3-2]+o+o)/3+adj; + + adj=(bc[2].static_u[b->number*3-1]*3 - + bc[2].static_u[b->number*3-2] - + bc[2].static_u[b->number*3-2] - + bc[2].static_u[b->number*3+1])/3; + bc[2].static_u[b->number*3-1]= + (bc[2].static_u[b->number*3-2]+ + bc[2].static_u[b->number*3-2]+ + u)/3+adj; + + adj=(bc[2].static_u[b->number*3]*3 - + bc[2].static_u[b->number*3-2] - + bc[2].static_u[b->number*3+1] - + bc[2].static_u[b->number*3+1])/3; + bc[2].static_u[b->number*3]= + (bc[2].static_u[b->number*3-2]+u+u)/3+adj; + + } + + if(b->number<9){ + adj=(bc[1].static_o[b->number*2+1]*2- + bc[1].static_o[b->number*2+2]-bc[1].static_o[b->number*2])/2; + bc[1].static_o[b->number*2+1]= + (bc[1].static_o[b->number*2+2]+o)/2+adj; + + adj=(bc[1].static_u[b->number*2+1]*2- + bc[1].static_u[b->number*2+2]-bc[1].static_u[b->number*2])/2; + bc[1].static_u[b->number*2+1]= + (bc[1].static_u[b->number*2+2]+u)/2+adj; + + adj=(bc[2].static_o[b->number*3+3]*3 - + bc[2].static_o[b->number*3+4] - + bc[2].static_o[b->number*3+4] - + bc[2].static_o[b->number*3+1])/3; + bc[2].static_o[b->number*3+3]= + (bc[2].static_o[b->number*3+4]+ + bc[2].static_o[b->number*3+4]+ + o)/3+adj; + + adj=(bc[2].static_o[b->number*3+2]*3 - + bc[2].static_o[b->number*3+4] - + bc[2].static_o[b->number*3+1] - + bc[2].static_o[b->number*3+1])/3; + bc[2].static_o[b->number*3+2]= + (bc[2].static_o[b->number*3+4]+o+o)/3+adj; + + adj=(bc[2].static_u[b->number*3+3]*3 - + bc[2].static_u[b->number*3+4] - + bc[2].static_u[b->number*3+4] - + bc[2].static_u[b->number*3+1])/3; + bc[2].static_u[b->number*3+3]= + (bc[2].static_u[b->number*3+4]+ + bc[2].static_u[b->number*3+4]+ + u)/3+adj; + + adj=(bc[2].static_u[b->number*3+2]*3 - + bc[2].static_u[b->number*3+4] - + bc[2].static_u[b->number*3+1] - + bc[2].static_u[b->number*3+1])/3; + bc[2].static_u[b->number*3+2]= + (bc[2].static_u[b->number*3+4]+u+u)/3+adj; + + } + } + + if(b->number==9){ + bc[1].static_o[19]+=o-bc[1].static_o[18]; + bc[1].static_u[19]+=u-bc[1].static_u[18]; + bc[2].static_o[29]+=o-bc[2].static_o[28]; + bc[2].static_u[29]+=u-bc[2].static_u[28]; + } + bc[1].static_o[b->number*2]=o; bc[1].static_u[b->number*2]=u; bc[2].static_o[b->number*3+1]=o; bc[2].static_u[b->number*3+1]=u; + break; case 1: if((b->number&1)==0){ @@ -383,13 +362,13 @@ static void slider_change(GtkWidget *w,gpointer in){ bc[2].static_u[b->number/2*3+1]=u; }else{ if(b->number<19){ - float val=(bc[2].static_o[b->number/2*3+2]+ - bc[2].static_o[b->number/2*3+3])*.5; + int val=(bc[2].static_o[b->number/2*3+2]+ + bc[2].static_o[b->number/2*3+3])/2; bc[2].static_o[b->number/2*3+2]+=(o-val); bc[2].static_o[b->number/2*3+3]+=(o-val); val=(bc[2].static_u[b->number/2*3+2]+ - bc[2].static_u[b->number/2*3+3])*.5; + bc[2].static_u[b->number/2*3+3])/2; bc[2].static_u[b->number/2*3+2]+=(u-val); bc[2].static_u[b->number/2*3+3]+=(u-val); @@ -398,6 +377,11 @@ static void slider_change(GtkWidget *w,gpointer in){ bc[2].static_u[b->number/2*3+2]=u; } } + if(b->number==0){ + bc[2].static_o[0]+=o-bc[2].static_o[1]; + bc[2].static_u[0]+=u-bc[2].static_u[1]; + } + break; case 2: if((b->number%3)==1){ @@ -409,10 +393,10 @@ static void slider_change(GtkWidget *w,gpointer in){ if(b->number<29){ bc[1].static_o[(b->number-1)/3*2+1]= (bc[2].static_o[(b->number-1)/3*3+2]+ - bc[2].static_o[(b->number-1)/3*3+3])*.5; + bc[2].static_o[(b->number-1)/3*3+3])/2; bc[1].static_u[(b->number-1)/3*2+1]= (bc[2].static_u[(b->number-1)/3*3+2]+ - bc[2].static_u[(b->number-1)/3*3+3])*.5; + bc[2].static_u[(b->number-1)/3*3+3])/2; }else{ bc[1].static_o[(b->number-1)/3*2+1]=o; bc[1].static_u[(b->number-1)/3*2+1]=u; @@ -429,8 +413,8 @@ static void slider_change(GtkWidget *w,gpointer in){ /* compute the current average */ for(i=0;i1) - gtk_box_pack_end(GTK_BOX(link_box),link_check,0,0,0); - - gtk_box_pack_end(GTK_BOX(staticbox),link_box,0,0,0); - gtk_container_set_border_width(GTK_CONTAINER(link_box),5); - g_signal_connect (G_OBJECT (link_check), "toggled", - G_CALLBACK (link_toggled), (gpointer)0); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(link_check),0); - gtk_box_pack_start(GTK_BOX(panel->subpanel_box),hbox,0,0,0); gtk_box_pack_start(GTK_BOX(hbox),sliderbox,0,0,0); gtk_box_pack_start(GTK_BOX(hbox),staticbox,0,0,0); - gtk_box_pack_start(GTK_BOX(staticbox),overtable,0,0,0); - gtk_box_pack_start(GTK_BOX(staticbox),undertable,0,0,10); - + { + GtkWidget *hs1=gtk_hseparator_new(); + GtkWidget *hs2=gtk_hseparator_new(); + GtkWidget *hs3=gtk_hseparator_new(); + + gtk_box_pack_start(GTK_BOX(staticbox),overtable,0,0,10); + gtk_box_pack_start(GTK_BOX(staticbox),hs1,0,0,0); + gtk_box_pack_start(GTK_BOX(staticbox),undertable,0,0,10); + gtk_box_pack_start(GTK_BOX(staticbox),hs2,0,0,0); + gtk_box_pack_start(GTK_BOX(staticbox),basetable,0,0,10); + gtk_box_pack_start(GTK_BOX(staticbox),hs3,0,0,0); - gtk_box_pack_end(GTK_BOX(staticbox),suppressframe,0,0,0); - gtk_container_add(GTK_CONTAINER(suppressframe),suppresstable); + gtk_container_set_border_width(GTK_CONTAINER(overtable),5); + gtk_container_set_border_width(GTK_CONTAINER(undertable),5); + gtk_container_set_border_width(GTK_CONTAINER(basetable),5); - gtk_container_set_border_width(GTK_CONTAINER(suppressframe),5); - gtk_container_set_border_width(GTK_CONTAINER(overtable),5); - gtk_container_set_border_width(GTK_CONTAINER(undertable),5); + } /* under compand: mode and knee */ { @@ -646,7 +617,7 @@ void compandpanel_create(postfish_mainpanel *mp, "peak"); GtkWidget *knee_button=gtk_check_button_new_with_label("soft knee"); - gtk_box_pack_start(GTK_BOX(envelopebox),underlabel,0,0,5); + gtk_box_pack_start(GTK_BOX(envelopebox),underlabel,0,0,0); gtk_box_pack_end(GTK_BOX(envelopebox),peak_button,0,0,5); gtk_box_pack_end(GTK_BOX(envelopebox),rms_button,0,0,5); gtk_box_pack_end(GTK_BOX(envelopebox),knee_button,0,0,5); @@ -671,7 +642,6 @@ void compandpanel_create(postfish_mainpanel *mp, multibar_callback(MULTIBAR(slider),under_compand_change,readout); multibar_thumb_set(MULTIBAR(slider),1.,0); - multibar_thumb_increment(MULTIBAR(slider),.01,.1); gtk_misc_set_alignment(GTK_MISC(label),1.,.5); @@ -682,25 +652,6 @@ void compandpanel_create(postfish_mainpanel *mp, } - /* under compand: limit */ - { - - GtkWidget *label=gtk_label_new("compand limit:"); - GtkWidget *readout=readout_new("140dB"); - GtkWidget *slider=multibar_slider_new(8,limit_labels,limit_levels,1); - - multibar_callback(MULTIBAR(slider),under_limit_change,readout); - multibar_thumb_set(MULTIBAR(slider),0.,0); - multibar_thumb_increment(MULTIBAR(slider),1.,10.); - - gtk_misc_set_alignment(GTK_MISC(label),1,.5); - - gtk_table_set_row_spacing(GTK_TABLE(undertable),1,4); - gtk_table_attach(GTK_TABLE(undertable),label,0,1,2,3,GTK_FILL,0,2,0); - gtk_table_attach(GTK_TABLE(undertable),slider,1,3,2,3,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); - gtk_table_attach(GTK_TABLE(undertable),readout,3,4,2,3,GTK_FILL,0,0,0); - } - /* under compand: timing */ { @@ -733,7 +684,6 @@ void 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 *labelbox=gtk_hbox_new(0,0); multibar_callback(MULTIBAR(slider),under_lookahead_change,readout); multibar_thumb_set(MULTIBAR(slider),100.,0); @@ -756,7 +706,7 @@ void compandpanel_create(postfish_mainpanel *mp, "peak"); GtkWidget *knee_button=gtk_check_button_new_with_label("soft knee"); - gtk_box_pack_start(GTK_BOX(envelopebox),overlabel,0,0,5); + gtk_box_pack_start(GTK_BOX(envelopebox),overlabel,0,0,0); gtk_box_pack_end(GTK_BOX(envelopebox),peak_button,0,0,5); gtk_box_pack_end(GTK_BOX(envelopebox),rms_button,0,0,5); gtk_box_pack_end(GTK_BOX(envelopebox),knee_button,0,0,5); @@ -781,7 +731,6 @@ void compandpanel_create(postfish_mainpanel *mp, multibar_callback(MULTIBAR(slider),over_compand_change,readout); multibar_thumb_set(MULTIBAR(slider),1.,0); - multibar_thumb_increment(MULTIBAR(slider),.01,.1); gtk_misc_set_alignment(GTK_MISC(label),1.,.5); @@ -792,25 +741,6 @@ void compandpanel_create(postfish_mainpanel *mp, } - /* over compand: limit */ - { - - GtkWidget *label=gtk_label_new("compand limit:"); - GtkWidget *readout=readout_new("140dB"); - GtkWidget *slider=multibar_slider_new(8,limit_labels,limit_levels,1); - - multibar_callback(MULTIBAR(slider),over_limit_change,readout); - multibar_thumb_set(MULTIBAR(slider),0.,0); - multibar_thumb_increment(MULTIBAR(slider),1.,10.); - - gtk_misc_set_alignment(GTK_MISC(label),1,.5); - - gtk_table_set_row_spacing(GTK_TABLE(overtable),1,4); - gtk_table_attach(GTK_TABLE(overtable),label,0,1,2,3,GTK_FILL,0,2,0); - gtk_table_attach(GTK_TABLE(overtable),slider,1,3,2,3,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); - gtk_table_attach(GTK_TABLE(overtable),readout,3,4,2,3,GTK_FILL,0,0,0); - } - /* over compand: timing */ { @@ -843,7 +773,6 @@ void 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 *labelbox=gtk_hbox_new(0,0); multibar_callback(MULTIBAR(slider),over_lookahead_change,readout); multibar_thumb_set(MULTIBAR(slider),100.,0); @@ -856,29 +785,9 @@ void compandpanel_create(postfish_mainpanel *mp, gtk_table_attach(GTK_TABLE(overtable),slider,1,3,3,4,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); gtk_table_attach(GTK_TABLE(overtable),readout,3,4,3,4,GTK_FILL,0,0,0); } - - /* base compand: ratio */ - { - GtkWidget *label=gtk_label_new("global ratio:"); - GtkWidget *readout=readout_new("1.55:1"); - GtkWidget *slider=multibar_slider_new(8,compand_labels,compand_levels,1); - - //multibar_callback(MULTIBAR(slider),over_compand_change,readout); - multibar_thumb_set(MULTIBAR(slider),1.,0); - multibar_thumb_increment(MULTIBAR(slider),.01,.1); - gtk_misc_set_alignment(GTK_MISC(label),1.,.5); - - gtk_table_set_row_spacing(GTK_TABLE(overtable),4,4); - - gtk_table_attach(GTK_TABLE(overtable),label,0,1,4,5,GTK_FILL,0,2,0); - gtk_table_attach(GTK_TABLE(overtable),slider,1,3,4,5,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); - gtk_table_attach(GTK_TABLE(overtable),readout,3,4,4,5,GTK_FILL,0,0,0); - - } - - /* suppress: mode */ + /* base compand: mode */ { GtkWidget *envelopebox=gtk_hbox_new(0,0); GtkWidget *rms_button=gtk_radio_button_new_with_label(NULL,"RMS"); @@ -886,68 +795,60 @@ void compandpanel_create(postfish_mainpanel *mp, gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(rms_button), "peak"); + gtk_box_pack_start(GTK_BOX(envelopebox),baselabel,0,0,0); gtk_box_pack_end(GTK_BOX(envelopebox),peak_button,0,0,5); gtk_box_pack_end(GTK_BOX(envelopebox),rms_button,0,0,5); g_signal_connect (G_OBJECT (rms_button), "clicked", - G_CALLBACK (suppress_mode), (gpointer)0); + G_CALLBACK (base_mode), (gpointer)0); g_signal_connect (G_OBJECT (peak_button), "clicked", - G_CALLBACK (suppress_mode), (gpointer)1); //To Hell I Go + G_CALLBACK (base_mode), (gpointer)1); //To Hell I Go gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rms_button),1); - gtk_table_attach(GTK_TABLE(suppresstable),envelopebox,1,5,0,1,GTK_FILL,0,0,0); + gtk_table_attach(GTK_TABLE(basetable),envelopebox,0,4,0,1,GTK_FILL,0,0,0); } - /* suppress: ratio */ + /* base compand: ratio */ { - GtkWidget *label=gtk_label_new("ratio:"); + GtkWidget *label=gtk_label_new("compand ratio:"); GtkWidget *readout=readout_new("1.55:1"); - GtkWidget *slider=multibar_slider_new(4,compand_labels_low,compand_levels_low,1); - - multibar_callback(MULTIBAR(slider),suppress_compand_change,readout); + GtkWidget *slider=multibar_slider_new(8,compand_labels,compand_levels,1); + + multibar_callback(MULTIBAR(slider),base_compand_change,readout); multibar_thumb_set(MULTIBAR(slider),1.,0); - multibar_thumb_increment(MULTIBAR(slider),.01,.1); gtk_misc_set_alignment(GTK_MISC(label),1.,.5); - gtk_table_set_row_spacing(GTK_TABLE(suppresstable),0,4); - gtk_table_attach(GTK_TABLE(suppresstable),label,0,1,1,2,GTK_FILL,0,2,0); - gtk_table_attach(GTK_TABLE(suppresstable),slider,1,4,1,2,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); - gtk_table_attach(GTK_TABLE(suppresstable),readout,4,5,1,2,GTK_FILL,0,0,0); + gtk_table_set_row_spacing(GTK_TABLE(basetable),0,4); + gtk_table_attach(GTK_TABLE(basetable),label,0,1,1,2,GTK_FILL,0,2,0); + gtk_table_attach(GTK_TABLE(basetable),slider,1,3,1,2,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(basetable),readout,3,4,1,2,GTK_FILL,0,0,0); } - /* suppress: timing */ + /* base compand: timing */ { - GtkWidget *label=gtk_label_new("timing:"); - GtkWidget *label2=gtk_label_new("attack / decay / release"); + GtkWidget *label=gtk_label_new("attack/decay:"); GtkWidget *readout1=readout_new(" 100ms"); GtkWidget *readout2=readout_new(" 100ms"); - GtkWidget *readout3=readout_new(" 100ms"); - GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,3); - + GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2); multireadout *r=calloc(1,sizeof(*r)); + r->r0=(Readout *)readout1; r->r1=(Readout *)readout2; - r->r2=(Readout *)readout3; - - gtk_widget_set_name(label2,"scalemarker"); - multibar_callback(MULTIBAR(slider),suppress_timing_change,r); + multibar_callback(MULTIBAR(slider),base_timing_change,r); multibar_thumb_set(MULTIBAR(slider),1,0); multibar_thumb_set(MULTIBAR(slider),100,1); - multibar_thumb_set(MULTIBAR(slider),1000,2); gtk_misc_set_alignment(GTK_MISC(label),1,.5); - gtk_table_set_row_spacing(GTK_TABLE(suppresstable),1,4); - gtk_table_attach(GTK_TABLE(suppresstable),label,0,1,2,3,GTK_FILL,0,2,0); - gtk_table_attach(GTK_TABLE(suppresstable),slider,1,2,2,3,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); - gtk_table_attach(GTK_TABLE(suppresstable),readout1,2,3,2,3,GTK_FILL,0,0,0); - gtk_table_attach(GTK_TABLE(suppresstable),readout2,3,4,2,3,GTK_FILL,0,0,0); - gtk_table_attach(GTK_TABLE(suppresstable),readout3,4,5,2,3,GTK_FILL,0,0,0); - gtk_table_attach(GTK_TABLE(suppresstable),label2,1,2,3,4,GTK_FILL,0,0,0); + gtk_table_set_row_spacing(GTK_TABLE(basetable),2,4); + gtk_table_attach(GTK_TABLE(basetable),label,0,1,4,5,GTK_FILL,0,2,0); + gtk_table_attach(GTK_TABLE(basetable),slider,1,2,4,5,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(basetable),readout1,2,3,4,5,GTK_FILL,0,0,0); + gtk_table_attach(GTK_TABLE(basetable),readout2,3,4,4,5,GTK_FILL,0,0,0); } @@ -959,8 +860,7 @@ void compandpanel_create(postfish_mainpanel *mp, bars[i].readoutu=readout_new(" +0"); bars[i].readouto=readout_new(" +0"); - bars[i].slider=multibar_new(14,labels,levels,2, - LO_DECAY|HI_DECAY|LO_ATTACK); + bars[i].slider=multibar_new(14,labels,levels,2,HI_DECAY|LO_DECAY|LO_ATTACK); bars[i].number=i; bars[i].label=label; @@ -1005,7 +905,7 @@ void compandpanel_create(postfish_mainpanel *mp, subpanel_show_all_but_toplevel(panel); /* Now unmap the sliders we don't want */ - static_octave(NULL,(gpointer)2); + static_octave(NULL,(gpointer)1); } @@ -1031,7 +931,7 @@ void compandpanel_feedback(int displayit){ } void compandpanel_reset(void){ - int i,j; + int i; for(i=0;iclipcount,clip,n*sizeof(*clip)); @@ -91,7 +91,6 @@ static void push_declip_feedback(int *clip,float *peak,int total){ int pull_declip_feedback(int *clip,float *peak,int *total){ declip_feedback *f=(declip_feedback *)feedback_pull(&feedpool); - int i,j; if(!f)return 0; @@ -147,12 +146,14 @@ int declip_setiterations(float it){ pthread_mutex_lock(&master_mutex); iterations=it; pthread_mutex_unlock(&master_mutex); + return 0; } int declip_setconvergence(float c){ pthread_mutex_lock(&master_mutex); convergence=c; pthread_mutex_unlock(&master_mutex); + return 0; } /* called only in playback thread */ @@ -164,7 +165,7 @@ int declip_reset(void){ } static void sliding_bark_average(float *f,int n,float width){ - int i=0,j; + int i=0; float acc=0.,del=0.; float sec[hipad+1]; @@ -172,7 +173,6 @@ static void sliding_bark_average(float *f,int n,float width){ for(i=0;i>16; int lo=widthlookup[i]&(0xffff); float del=hypot(f[(i<<1)+1],f[i<<1])/(lo-hi); @@ -317,7 +317,6 @@ time_linkage *declip_read(time_linkage *in){ switch(fillstate){ case 0: /* prime the lapping and cache */ for(i=0;idata[i]; total=0; memset(work+blocksize/2,0,sizeof(*work)*blocksize/2); diff --git a/eq.c b/eq.c index a2ea9a6..623727e 100644 --- a/eq.c +++ b/eq.c @@ -61,7 +61,7 @@ void eq_set(int freq, float value){ static float *curve_cache=0; static void workfunc(freq_state *f,float **data,float **peak, float **rms){ - int h,i,j,k; + int h,i,j; float sq_mags[f->qblocksize*2+1]; if(curve_dirty || !curve_cache){ diff --git a/eq.h b/eq.h index 6079422..340ab50 100644 --- a/eq.h +++ b/eq.h @@ -25,14 +25,14 @@ #define eq_freqs 30 -static float eq_freq_list[eq_freqs+1]={ +static const float eq_freq_list[eq_freqs+1]={ 25,31.5,40,50,63,80, 100,125,160,200,250,315, 400,500,630,800,1000,1250,1600, 2000,2500,3150,4000,5000,6300, 8000,10000,12500,16000,20000,9e10}; -static char *eq_freq_labels[eq_freqs]={ +static char * const eq_freq_labels[eq_freqs]={ "25","31.5","40","50","63","80", "100","125","160","200","250","315", "400","500","630","800","1k","1.2k","1.6k", @@ -40,7 +40,6 @@ static char *eq_freq_labels[eq_freqs]={ "8k","10k","12.5k","16k","20k" }; - extern int pull_eq_feedback(float **peak,float **rms); extern int eq_load(void); extern int eq_reset(); diff --git a/freq.c b/freq.c index 9a96825..993d182 100644 --- a/freq.c +++ b/freq.c @@ -41,7 +41,6 @@ typedef struct freq_feedback{ } freq_feedback; static feedback_generic *new_freq_feedback(void){ - int i; freq_feedback *ret=malloc(sizeof(*ret)); ret->peak=calloc(input_ch,sizeof(*ret->peak)); ret->rms=calloc(input_ch,sizeof(*ret->rms)); @@ -76,14 +75,13 @@ int pull_freq_feedback(freq_state *ff,float **peak,float **rms){ } /* called only by initial setup */ -int freq_load(freq_state *f,float *frequencies, int bands){ +int freq_load(freq_state *f,const float *frequencies, int bands){ int i,j; int blocksize=input_size*2; memset(f,0,sizeof(*f)); f->qblocksize=input_size; f->bands=bands; - f->frequencies=frequencies; f->fillstate=0; f->cache_samples=0; @@ -332,7 +330,7 @@ time_linkage *freq_read(time_linkage *in, freq_state *f, void (*func)(freq_state *f,float **data, float **peak, float **rms), int bypass){ - int i,j,k; + int i; float feedback_peak[input_ch][f->bands]; float feedback_rms[input_ch][f->bands]; diff --git a/freq.h b/freq.h index 674052d..de9e762 100644 --- a/freq.h +++ b/freq.h @@ -34,7 +34,6 @@ typedef struct { int qblocksize; int bands; - float *frequencies; float **ho_window; float *ho_area; @@ -51,7 +50,7 @@ typedef struct { extern void freq_transform_work(float *work,freq_state *f); extern int pull_freq_feedback(freq_state *ff,float **peak,float **rms); -extern int freq_load(freq_state *f,float *frequencies, int bands); +extern int freq_load(freq_state *f,const float *frequencies, int bands); extern int freq_reset(freq_state *f); extern time_linkage *freq_read(time_linkage *in, freq_state *f, void (*func)(freq_state *f, diff --git a/input.c b/input.c index 79c84f5..15b1da0 100644 --- a/input.c +++ b/input.c @@ -401,7 +401,7 @@ static feedback_generic *new_input_feedback(void){ } static void push_input_feedback(float *peak,float *rms, off_t cursor){ - int i,n=input_ch+2; + int n=input_ch+2; input_feedback *f=(input_feedback *) feedback_new(&feedpool,new_input_feedback); f->cursor=cursor; @@ -412,7 +412,7 @@ static void push_input_feedback(float *peak,float *rms, off_t cursor){ int pull_input_feedback(float *peak,float *rms,off_t *cursor){ input_feedback *f=(input_feedback *)feedback_pull(&feedpool); - int i,j,n=input_ch+2; + int n=input_ch+2; if(!f)return 0; if(rms)memcpy(rms,f->rms,sizeof(*rms)*n); if(peak)memcpy(peak,f->peak,sizeof(*peak)*n); @@ -496,7 +496,6 @@ time_linkage *input_read(void){ k=0; for(i=0;ipeak,sizeof(*peak)*input_ch); + if(att) + memcpy(att,f->att,sizeof(*att)*input_ch); + feedback_old(&limitstate.feedpool,(feedback_generic *)f); + return 1; +} + +/* called only by initial setup */ +int limit_load(void){ + 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;ig=mkbessel(alpha,2,filter->c); + filter->alpha=alpha; + filter->Hz=alpha*input_rate; + filter->ms=msec; +} + +/* called only in playback thread */ +int limit_reset(void ){ + /* reset cached pipe state */ + while(pull_limit_feedback(NULL,NULL)); + memset(limitstate.iir,0,input_ch*sizeof(&limitstate.iir)); + return 0; +} + +static inline float limit_knee(float x,float d){ + return (sqrtf(x*x+d)-x)*-.5f; +} + + +time_linkage *limit_read(time_linkage *in){ + float peakfeed[input_ch]; + float attfeed[input_ch]; + + int active=limit_active; + int visible=limit_visible; + int bypass=!(active || visible); + int i,k; + + float thresh=limitset.thresh/10.-.01; + float depth=limitset.depth; + float localpeak; + float localatt; + + float decayms=limitset.decay*.1; + if(decayms!=limitstate.decay.ms)filter_set(decayms,&limitstate.decay); + + if(in->samples==0){ + limitstate.out.samples=0; + return &limitstate.out; + } + + depth=depth*.2; + depth*=depth; + + for(i=0;idata[i]; + float *x=limitstate.out.data[i]; + + if(active){ + + /* 'knee' the actual samples, compute attenuation depth */ + for(k=0;ksamples;k++){ + float dB=todB(inx[k]); + float knee=limit_knee(dB-thresh,depth)+thresh; + float att=dB-knee; + + if(att>localatt)localatt=att; + + x[k]=att; + } + + + compute_iir_freefall2(x,input_size,limitstate.iir+i,&limitstate.decay); + + + for(k=0;ksamples;k++) + x[k]=inx[k]*fromdB(-x[k]); + + + } + } + + if(!active){ + float *temp=in->data[i]; + in->data[i]=limitstate.out.data[i]; + limitstate.out.data[i]=temp; + } + + if(!bypass){ + float *x=limitstate.out.data[i]; + /* get peak feedback */ + for(k=0;ksamples;k++) + if(fabs(x[k])>localpeak)localpeak=fabs(x[k]); + + } + + peakfeed[i]=todB(localpeak); + attfeed[i]=localatt; + + } + + limitstate.out.samples=in->samples; + + /* finish up the state feedabck */ + { + limit_feedback *ff= + (limit_feedback *)feedback_new(&limitstate.feedpool,new_limit_feedback); + + if(!ff->peak) + ff->peak=malloc(input_ch*sizeof(*ff->peak)); + + if(!ff->att) + ff->att=malloc(input_ch*sizeof(*ff->att)); + + memcpy(ff->peak,peakfeed,sizeof(peakfeed)); + memcpy(ff->att,attfeed,sizeof(attfeed)); + + feedback_push(&limitstate.feedpool,(feedback_generic *)ff); + } + + { + int tozero=limitstate.out.size-limitstate.out.samples; + if(tozero) + for(i=0;i +#include +#include "readout.h" +#include "multibar.h" +#include "mainpanel.h" +#include "subpanel.h" +#include "feedback.h" +#include "limit.h" +#include "limitpanel.h" + +extern sig_atomic_t limit_active; +extern sig_atomic_t limit_visible; +extern int input_ch; +extern int input_size; +extern int input_rate; + +extern limit_settings limitset; + +static GtkWidget *t_slider; +static GtkWidget *a_slider; + +static void limit_change(GtkWidget *w,gpointer in){ + char buffer[80]; + Readout *r=(Readout *)in; + float val=multibar_get_value(MULTIBAR(w),0); + + sprintf(buffer,"%+5.1fdB",val); + readout_set(r,buffer); + + limitset.thresh=rint(val*10.); +} + +static void depth_change(GtkWidget *w,gpointer in){ + char buffer[80]; + Readout *r=(Readout *)in; + float val=multibar_get_value(MULTIBAR(w),0); + + sprintf(buffer,"%+5.1fdB",val); + readout_set(r,buffer); + + limitset.depth=rint(val*10.); +} + +static void decay_change(GtkWidget *w,gpointer in){ + char buffer[80]; + Readout *r=(Readout *)in; + float v=multibar_get_value(MULTIBAR(w),0); + + + if(v<10){ + sprintf(buffer," %4.2fms",v); + }else if(v<100){ + sprintf(buffer," %4.1fms",v); + }else if (v<1000){ + sprintf(buffer," %4.0fms",v); + }else if (v<10000){ + sprintf(buffer," %4.2fs",v/1000.); + }else{ + sprintf(buffer," %4.1fs",v/1000.); + } + + readout_set(READOUT(r),buffer); + + limitset.decay=rint(v*10.); +} + +void limitpanel_create(postfish_mainpanel *mp, + GtkWidget *windowbutton, + GtkWidget *activebutton){ + + + char *labels[8]={"-80","-60","-40","-20","-10","-6","-3","+0"}; + float levels[9]={-80,-60,-50,-40,-30,-10,-6,-3,0}; + + char *labels2[4]={"-20","-10","-3","0"}; + float levels2[5]={-30,-20,-10,-3,0}; + + char *rlabels[3]={"6"," 20","40"}; + float rlevels[4]={0,3,10,20}; + + float timing_levels[6]={.1,1,10,100,1000,10000}; + char *timing_labels[5]={"1ms","10ms","100ms","1s","10s"}; + + subpanel_generic *panel=subpanel_create(mp,windowbutton,activebutton, + &limit_active, + &limit_visible, + "Hard _Limiter"," [l] "); + + GtkWidget *slidertable=gtk_table_new(4,4,0); + + GtkWidget *label1=gtk_label_new("hard limit"); + GtkWidget *label2=gtk_label_new("knee depth"); + GtkWidget *label3=gtk_label_new("decay speed"); + GtkWidget *label4=gtk_label_new("attenuation"); + + GtkWidget *readout1=readout_new("+XXXXdB"); + GtkWidget *readout2=readout_new("+XXXXdB"); + GtkWidget *readout3=readout_new("+XXXXms"); + + GtkWidget *slider2=multibar_slider_new(4,labels2,levels2,1); + GtkWidget *slider3=multibar_slider_new(5,timing_labels,timing_levels,1); + + t_slider=multibar_new(8,labels,levels,1,HI_DECAY); + a_slider=multibar_new(3,rlabels,rlevels,0,0); + + gtk_misc_set_alignment(GTK_MISC(label1),1,.5); + gtk_misc_set_alignment(GTK_MISC(label2),1,.5); + gtk_misc_set_alignment(GTK_MISC(label3),1,.5); + gtk_widget_set_name(label4,"scalemarker"); + + gtk_table_attach(GTK_TABLE(slidertable),label1,0,1,1,2,GTK_FILL,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(slidertable),label2,0,1,2,3,GTK_FILL,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(slidertable),label3,0,1,3,4,GTK_FILL,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(slidertable),label4,3,4,0,1,GTK_FILL,GTK_FILL|GTK_EXPAND,0,0); + + gtk_table_attach(GTK_TABLE(slidertable),t_slider,1,2,1,2,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,0,0); + gtk_table_attach(GTK_TABLE(slidertable),a_slider,3,4,1,2,GTK_FILL,GTK_FILL|GTK_EXPAND,0,0); + gtk_table_attach(GTK_TABLE(slidertable),slider2,1,2,2,3,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,0,4); + gtk_table_attach(GTK_TABLE(slidertable),slider3,1,2,3,4,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,0,0); + + gtk_table_attach(GTK_TABLE(slidertable),readout1,2,3,1,2,GTK_FILL,GTK_FILL|GTK_EXPAND,0,0); + gtk_table_attach(GTK_TABLE(slidertable),readout2,2,3,2,3,GTK_FILL,GTK_FILL|GTK_EXPAND,0,4); + gtk_table_attach(GTK_TABLE(slidertable),readout3,2,3,3,4,GTK_FILL,GTK_FILL|GTK_EXPAND,0,0); + + gtk_container_add(GTK_CONTAINER(panel->subpanel_box),slidertable); + + multibar_callback(MULTIBAR(t_slider),limit_change,readout1); + multibar_callback(MULTIBAR(slider2),depth_change,readout2); + multibar_callback(MULTIBAR(slider3),decay_change,readout3); + + multibar_thumb_set(MULTIBAR(t_slider),0.,0); + multibar_thumb_set(MULTIBAR(slider2),0.,0); + multibar_thumb_set(MULTIBAR(slider3),10.,0); + + subpanel_show_all_but_toplevel(panel); + +} + +static float *peakfeed=0; +static float *attfeed=0; +static float *zerofeed=0; + +void limitpanel_feedback(int displayit){ + if(!peakfeed){ + int i; + peakfeed=malloc(sizeof(*peakfeed)*input_ch); + attfeed=malloc(sizeof(*attfeed)*input_ch); + zerofeed=malloc(sizeof(*zerofeed)*input_ch); + for(i=0;i #include "input.h" #include "output.h" +#include "declip.h" +#include "eq.h" +#include "suppress.h" +#include "multicompand.h" +#include "singlecomp.h" +#include "limit.h" pthread_mutex_t master_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; @@ -45,7 +51,10 @@ int main(int argc, char **argv){ /* set up filter chains */ if(declip_load())exit(1); if(eq_load())exit(1); + if(suppress_load())exit(1); if(multicompand_load())exit(1); + if(singlecomp_load())exit(1); + if(limit_load())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 ef9299d..367c21b 100644 --- a/mainpanel.c +++ b/mainpanel.c @@ -34,6 +34,13 @@ #include "mainpanel.h" #include "windowbutton.h" +static void meterhold_reset(postfish_mainpanel *p){ + p->inpeak=-200; + p->outpeak=-200; + + readout_set(READOUT(p->inreadout),"------"); + readout_set(READOUT(p->outreadout),"------"); +} static void action_zero(GtkWidget *widget,postfish_mainpanel *p){ const char *time=gtk_entry_get_text(GTK_ENTRY(p->entry_a)); @@ -47,6 +54,9 @@ static void action_zero(GtkWidget *widget,postfish_mainpanel *p){ clippanel_reset(); eqpanel_reset(); compandpanel_reset(); + singlepanel_reset(); + limitpanel_reset(); + meterhold_reset(p); } static void action_end(GtkWidget *widget,postfish_mainpanel *p){ @@ -62,6 +72,9 @@ static void action_end(GtkWidget *widget,postfish_mainpanel *p){ clippanel_reset(); eqpanel_reset(); compandpanel_reset(); + singlepanel_reset(); + limitpanel_reset(); + meterhold_reset(p); } static void action_bb(GtkWidget *widget,postfish_mainpanel *p){ @@ -92,11 +105,67 @@ static void action_ff(GtkWidget *widget,postfish_mainpanel *p){ readout_set(READOUT(p->cue),(char *)time); } +/* gotta have the Fucking Fish */ +static int reanimate_fish(postfish_mainpanel *p){ + if(playback_active || (p->fishframe>0 && p->fishframe<12)){ + /* continue spinning */ + p->fishframe++; + if(p->fishframe>=12)p->fishframe=0; + + gtk_image_set_from_pixmap(GTK_IMAGE(p->twirlimage), + p->ff[p->fishframe], + p->fb[p->fishframe]); + + if(p->fishframe==0 && !playback_active){ + /* reschedule to blink */ + p->fishframe_timer= + gtk_timeout_add(rand()%1000*30,(GtkFunction)reanimate_fish,p); + return FALSE; + } + }else{ + p->fishframe++; + if(p->fishframe<=1)p->fishframe=12; + if(p->fishframe>=19)p->fishframe=0; + + gtk_image_set_from_pixmap(GTK_IMAGE(p->twirlimage), + p->ff[p->fishframe], + p->fb[p->fishframe]); + + + if(p->fishframe==12){ + /* reschedule to animate */ + p->fishframe_timer= + gtk_timeout_add(10,(GtkFunction)reanimate_fish,p); + return FALSE; + } + if(p->fishframe==0){ + /* reschedule to blink */ + p->fishframe_timer= + gtk_timeout_add(rand()%1000*30,(GtkFunction)reanimate_fish,p); + return FALSE; + } + } + return TRUE; +} + +static void animate_fish(postfish_mainpanel *p){ + if(p->fishframe_init){ + gtk_timeout_remove(p->fishframe_timer); + p->fishframe_timer= + gtk_timeout_add(80,(GtkFunction)reanimate_fish,p); + }else{ + p->fishframe_init=1; + p->fishframe_timer= + gtk_timeout_add(rand()%1000*30,(GtkFunction)reanimate_fish,p); + } +} + static void action_play(GtkWidget *widget,postfish_mainpanel *p){ if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))){ if(!playback_active){ pthread_t playback_thread_id; playback_active=1; + meterhold_reset(p); animate_fish(p); pthread_create(&playback_thread_id,NULL,&playback_thread,NULL); } @@ -109,13 +178,9 @@ static void action_entrya(GtkWidget *widget,postfish_mainpanel *p){ const char *time=gtk_entry_get_text(GTK_ENTRY(p->entry_a)); off_t cursor=input_time_to_cursor(time); - if(cursor==0){ - time=readout_get(READOUT(p->cue)); - gtk_entry_set_text(GTK_ENTRY(p->entry_a),time); - }else{ - input_seek(cursor); - readout_set(READOUT(p->cue),(char *)time); - } + input_seek(cursor); + readout_set(READOUT(p->cue),(char *)time); + } static void action_entryb(GtkWidget *widget,postfish_mainpanel *p){ @@ -125,12 +190,6 @@ static void action_entryb(GtkWidget *widget,postfish_mainpanel *p){ off_t cursora,cursorb=input_time_to_cursor(time); time=gtk_entry_get_text(GTK_ENTRY(p->entry_a)); cursora=input_time_to_cursor(time); - - if(cursorb==0){ - time=readout_get(READOUT(p->cue)); - cursorb=input_time_to_cursor(time); - gtk_entry_set_text(GTK_ENTRY(p->entry_b),time); - } if(cursoraentry_a)); + + time=readout_get(READOUT(p->cue)); + gtk_entry_set_text(GTK_ENTRY(p->entry_a),time); + +} + +static void action_setb(GtkWidget *widget,postfish_mainpanel *p){ + const char *time=gtk_entry_get_text(GTK_ENTRY(p->entry_b)); + off_t cursora,cursorb=input_time_to_cursor(time); + time=gtk_entry_get_text(GTK_ENTRY(p->entry_a)); + cursora=input_time_to_cursor(time); + + time=readout_get(READOUT(p->cue)); + cursorb=input_time_to_cursor(time); + gtk_entry_set_text(GTK_ENTRY(p->entry_b),time); + +} + static void action_reseta(GtkWidget *widget,postfish_mainpanel *p){ char time[14]; input_cursor_to_time(0,time); @@ -159,62 +238,7 @@ static void action_resetb(GtkWidget *widget,postfish_mainpanel *p){ char time[14]; input_cursor_to_time(0,time); gtk_entry_set_text(GTK_ENTRY(p->entry_b),time); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->cue_set[1]),0); -} - -/* gotta have the Fucking Fish */ -int reanimate_fish(postfish_mainpanel *p){ - if(playback_active || (p->fishframe>0 && p->fishframe<12)){ - /* continue spinning */ - p->fishframe++; - if(p->fishframe>=12)p->fishframe=0; - - gtk_image_set_from_pixmap(GTK_IMAGE(p->twirlimage), - p->ff[p->fishframe], - p->fb[p->fishframe]); - - if(p->fishframe==0 && !playback_active){ - /* reschedule to blink */ - p->fishframe_timer= - gtk_timeout_add(rand()%1000*30,(GtkFunction)reanimate_fish,p); - return FALSE; - } - }else{ - p->fishframe++; - if(p->fishframe<=1)p->fishframe=12; - if(p->fishframe>=19)p->fishframe=0; - - gtk_image_set_from_pixmap(GTK_IMAGE(p->twirlimage), - p->ff[p->fishframe], - p->fb[p->fishframe]); - - - if(p->fishframe==12){ - /* reschedule to animate */ - p->fishframe_timer= - gtk_timeout_add(10,(GtkFunction)reanimate_fish,p); - return FALSE; - } - if(p->fishframe==0){ - /* reschedule to blink */ - p->fishframe_timer= - gtk_timeout_add(rand()%1000*30,(GtkFunction)reanimate_fish,p); - return FALSE; - } - } - return TRUE; -} - -int animate_fish(postfish_mainpanel *p){ - if(p->fishframe_init){ - gtk_timeout_remove(p->fishframe_timer); - p->fishframe_timer= - gtk_timeout_add(80,(GtkFunction)reanimate_fish,p); - }else{ - p->fishframe_init=1; - p->fishframe_timer= - gtk_timeout_add(rand()%1000*30,(GtkFunction)reanimate_fish,p); - } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->cue_act[1]),0); } static void shutdown(void){ @@ -333,105 +357,125 @@ static gboolean mainpanel_keybinding(GtkWidget *widget, /* do not capture Alt accellerators */ if(event->state&GDK_MOD1_MASK) return FALSE; - if(event->state&GDK_CONTROL_MASK) return FALSE; + if(event->state&GDK_CONTROL_MASK){ - switch(event->keyval){ - case GDK_less: - case GDK_comma: - case GDK_period: - case GDK_greater: - - /* GTK has one unfortunate bit of hardwiring; if a key is held down - and autorepeats, the default pushbutton widget-unactivate timeout - is 250 ms, far slower than autorepeat. We must defeat this to - have autorepeat accellerators function at full speed. */ - - { - GdkEventKey copy=*event; - copy.type=GDK_KEY_RELEASE; - gtk_main_do_event((GdkEvent *)(©)); - } - while (gtk_events_pending ()) gtk_main_iteration (); + switch(event->keyval){ + case GDK_a: + case GDK_A: + gtk_widget_activate(p->cue_reset[0]); + break; + case GDK_b: + case GDK_B: + gtk_widget_activate(p->cue_reset[1]); + break; + + default: + return FALSE; } - switch(event->keyval){ - case GDK_t: - /* trigger master dB */ - gtk_widget_activate(p->masterdB_a); - break; - case GDK_minus: - multibar_thumb_set(MULTIBAR(p->masterdB_s), - multibar_get_value(MULTIBAR(p->masterdB_s),0)-.1,0); - break; - case GDK_underscore: - multibar_thumb_set(MULTIBAR(p->masterdB_s), - multibar_get_value(MULTIBAR(p->masterdB_s),0)-1.,0); - break; - case GDK_equal: - multibar_thumb_set(MULTIBAR(p->masterdB_s), - multibar_get_value(MULTIBAR(p->masterdB_s),0)+.1,0); - break; - case GDK_plus: - multibar_thumb_set(MULTIBAR(p->masterdB_s), - multibar_get_value(MULTIBAR(p->masterdB_s),0)+1.,0); - break; - case GDK_d: - gtk_widget_activate(p->buttonactive[0]); - break; - case GDK_c: - gtk_widget_activate(p->buttonactive[1]); - break; - case GDK_m: - gtk_widget_activate(p->buttonactive[2]); - break; - case GDK_s: - gtk_widget_activate(p->buttonactive[3]); - break; - case GDK_e: - gtk_widget_activate(p->buttonactive[4]); - break; - case GDK_l: - gtk_widget_activate(p->buttonactive[5]); - break; - case GDK_a: - gtk_widget_activate(p->cue_set[0]); - break; - case GDK_A: - gtk_widget_activate(p->cue_reset[0]); - break; - case GDK_b: - gtk_widget_activate(p->cue_set[1]); - break; - case GDK_B: - gtk_widget_activate(p->cue_reset[1]); - break; - case GDK_BackSpace: - gtk_widget_activate(p->deckactive[0]); - break; - case GDK_less: - gtk_widget_activate(p->deckactive[1]); - break; - case GDK_comma: - gtk_widget_activate(p->deckactive[2]); - break; - case GDK_space: - gtk_widget_activate(p->deckactive[3]); - break; - case GDK_period: - gtk_widget_activate(p->deckactive[4]); - break; - case GDK_greater: - gtk_widget_activate(p->deckactive[5]); - break; - case GDK_End: - gtk_widget_activate(p->deckactive[6]); + }else{ + /* non-control keypresses */ + switch(event->keyval){ + case GDK_less: + case GDK_comma: + case GDK_period: + case GDK_greater: + + /* GTK has one unfortunate bit of hardwiring; if a key is held down + and autorepeats, the default pushbutton widget-unactivate timeout + is 250 ms, far slower than autorepeat. We must defeat this to + have autorepeat accellerators function at full speed. */ + + { + GdkEventKey copy=*event; + copy.type=GDK_KEY_RELEASE; + gtk_main_do_event((GdkEvent *)(©)); + } + while (gtk_events_pending ()) gtk_main_iteration (); + } + + + switch(event->keyval){ + case GDK_t: + /* trigger master dB */ + gtk_widget_activate(p->masterdB_a); + break; + case GDK_minus: + multibar_thumb_set(MULTIBAR(p->masterdB_s), + multibar_get_value(MULTIBAR(p->masterdB_s),0)-.1,0); + break; + case GDK_underscore: + multibar_thumb_set(MULTIBAR(p->masterdB_s), + multibar_get_value(MULTIBAR(p->masterdB_s),0)-1.,0); + break; + case GDK_equal: + multibar_thumb_set(MULTIBAR(p->masterdB_s), + multibar_get_value(MULTIBAR(p->masterdB_s),0)+.1,0); break; - default: - return FALSE; + case GDK_plus: + multibar_thumb_set(MULTIBAR(p->masterdB_s), + multibar_get_value(MULTIBAR(p->masterdB_s),0)+1.,0); + break; + case GDK_d: + gtk_widget_activate(p->buttonactive[0]); + break; + case GDK_c: + gtk_widget_activate(p->buttonactive[1]); + break; + case GDK_m: + gtk_widget_activate(p->buttonactive[2]); + break; + case GDK_s: + gtk_widget_activate(p->buttonactive[3]); + break; + case GDK_v: + gtk_widget_activate(p->buttonactive[4]); + break; + case GDK_e: + gtk_widget_activate(p->buttonactive[5]); + break; + case GDK_l: + gtk_widget_activate(p->buttonactive[6]); + break; + case GDK_a: + gtk_widget_activate(p->cue_act[0]); + break; + case GDK_A: + gtk_widget_activate(p->cue_set[0]); + break; + case GDK_b: + gtk_widget_activate(p->cue_act[1]); + break; + case GDK_B: + gtk_widget_activate(p->cue_set[1]); + break; + case GDK_BackSpace: + gtk_widget_activate(p->deckactive[0]); + break; + case GDK_less: + gtk_widget_activate(p->deckactive[1]); + break; + case GDK_comma: + gtk_widget_activate(p->deckactive[2]); + break; + case GDK_space: + gtk_widget_activate(p->deckactive[3]); + break; + case GDK_period: + gtk_widget_activate(p->deckactive[4]); + break; + case GDK_greater: + gtk_widget_activate(p->deckactive[5]); + break; + case GDK_End: + gtk_widget_activate(p->deckactive[6]); + break; + default: + return FALSE; + } } - return TRUE; } @@ -578,11 +622,23 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){ GtkWidget *in=gtk_label_new("in:"); GtkWidget *out=gtk_label_new("out:"); GtkWidget *show=gtk_label_new("show:"); + GtkWidget *inbox=gtk_hbox_new(0,0); + GtkWidget *outbox=gtk_hbox_new(0,0); panel->inbar=multibar_new(12,labels,levels, 0, LO_ATTACK|LO_DECAY|HI_DECAY|PEAK_FOLLOW ); panel->outbar=multibar_new(12,labels,levels, 0, LO_ATTACK|LO_DECAY|HI_DECAY|PEAK_FOLLOW ); + panel->inreadout=readout_new("------"); + panel->outreadout=readout_new("------"); + + gtk_widget_set_name(panel->inreadout,"smallreadout"); + gtk_widget_set_name(panel->outreadout,"smallreadout"); + + gtk_box_pack_start(GTK_BOX(inbox),panel->inbar,1,1,0); + gtk_box_pack_end(GTK_BOX(inbox),panel->inreadout,0,1,0); + gtk_box_pack_start(GTK_BOX(outbox),panel->outbar,1,1,0); + gtk_box_pack_end(GTK_BOX(outbox),panel->outreadout,0,1,0); gtk_container_set_border_width(GTK_CONTAINER (ttable), 3); gtk_table_set_col_spacings(GTK_TABLE(ttable),5); @@ -609,8 +665,8 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){ gtk_table_attach(GTK_TABLE(ttable),show,0,1,0,1,GTK_FILL|GTK_SHRINK,GTK_FILL|GTK_SHRINK,0,0); gtk_table_attach(GTK_TABLE(ttable),in,0,1,1,2,GTK_FILL|GTK_SHRINK,GTK_FILL|GTK_SHRINK,0,0); gtk_table_attach(GTK_TABLE(ttable),out,0,1,2,3,GTK_FILL|GTK_SHRINK,GTK_FILL|GTK_SHRINK,0,0); - gtk_table_attach(GTK_TABLE(ttable),panel->inbar,1,3,1,2,GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,0); - gtk_table_attach(GTK_TABLE(ttable),panel->outbar,1,3,2,3,GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,0); + gtk_table_attach(GTK_TABLE(ttable),inbox,1,3,1,2,GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,0); + gtk_table_attach(GTK_TABLE(ttable),outbox,1,3,2,3,GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,0); gtk_table_set_row_spacing(GTK_TABLE(ttable),1,1); gtk_table_set_row_spacing(GTK_TABLE(ttable),2,2); @@ -651,7 +707,6 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){ /* master action bar */ { GtkWidget *bar_table=gtk_table_new(1,8,1); - char buffer[20]; for(i=0;i<7;i++){ GtkWidget *box=gtk_vbox_new(0,3); GtkWidget *label=gtk_label_new(text_bar[i]); @@ -717,10 +772,12 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){ panel->cue=readout_new(" : :00.00"); - panel->cue_set[0]=gtk_button_new_with_label("[a]"); - panel->cue_set[1]=gtk_toggle_button_new_with_label("[b]"); - panel->cue_reset[0]=gtk_button_new_with_label("[A]"); - panel->cue_reset[1]=gtk_button_new_with_label("[B]"); + panel->cue_act[0]=gtk_button_new_with_label("[a]"); + panel->cue_act[1]=gtk_toggle_button_new_with_label("[b]"); + panel->cue_set[0]=gtk_button_new_with_label("[A]"); + panel->cue_set[1]=gtk_button_new_with_label("[B]"); + panel->cue_reset[0]=gtk_button_new_with_label("^A"); + panel->cue_reset[1]=gtk_button_new_with_label("^B"); gtk_entry_set_width_chars(GTK_ENTRY(panel->entry_a),13); @@ -738,10 +795,16 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){ g_signal_connect_after(G_OBJECT (panel->entry_b), "grab_focus", G_CALLBACK (timeevent_unselect), NULL); - g_signal_connect (G_OBJECT (panel->cue_set[0]), "clicked", + g_signal_connect (G_OBJECT (panel->cue_act[0]), "clicked", G_CALLBACK (action_entrya), panel); - g_signal_connect (G_OBJECT (panel->cue_set[1]), "clicked", + g_signal_connect (G_OBJECT (panel->cue_act[1]), "clicked", G_CALLBACK (action_entryb), panel); + + g_signal_connect (G_OBJECT (panel->cue_set[0]), "clicked", + G_CALLBACK (action_seta), panel); + g_signal_connect (G_OBJECT (panel->cue_set[1]), "clicked", + G_CALLBACK (action_setb), panel); + g_signal_connect (G_OBJECT (panel->cue_reset[0]), "clicked", G_CALLBACK (action_reseta), panel); g_signal_connect (G_OBJECT (panel->cue_reset[1]), "clicked", @@ -761,14 +824,16 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){ gtk_box_pack_start(GTK_BOX(cuebox),framea,1,1,3); - gtk_box_pack_start(GTK_BOX(cuebox),panel->cue_set[0],0,0,0); + gtk_box_pack_start(GTK_BOX(cuebox),panel->cue_act[0],0,0,0); gtk_box_pack_start(GTK_BOX(cuebox),panel->entry_a,0,0,0); + gtk_box_pack_start(GTK_BOX(cuebox),panel->cue_set[0],0,0,0); gtk_box_pack_start(GTK_BOX(cuebox),panel->cue_reset[0],0,0,0); gtk_box_pack_start(GTK_BOX(cuebox),frameb,1,1,3); - gtk_box_pack_start(GTK_BOX(cuebox),panel->cue_set[1],0,0,0); + gtk_box_pack_start(GTK_BOX(cuebox),panel->cue_act[1],0,0,0); gtk_box_pack_start(GTK_BOX(cuebox),panel->entry_b,0,0,0); + gtk_box_pack_start(GTK_BOX(cuebox),panel->cue_set[1],0,0,0); gtk_box_pack_start(GTK_BOX(cuebox),panel->cue_reset[1],0,0,0); } @@ -815,12 +880,13 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){ gtk_table_attach_defaults(GTK_TABLE(panel->wintable),temp,1,2,0,1); } - mainpanel_panelentry(panel,"_Declip ","[d]",0,clippanel_create); + mainpanel_panelentry(panel,"_Declipper ","[d]",0,clippanel_create); mainpanel_panelentry(panel,"_Crosstalk ","[c]",1,0); mainpanel_panelentry(panel,"_Multicomp ","[m]",2,compandpanel_create); - mainpanel_panelentry(panel,"_Singlecomp ","[s]",3,0); - mainpanel_panelentry(panel,"_Equalizer ","[e]",4,eqpanel_create); - mainpanel_panelentry(panel,"_Limiter ","[l]",5,0); + mainpanel_panelentry(panel,"_Singlecomp ","[s]",3,singlepanel_create); + mainpanel_panelentry(panel,"De_verber ","[v]",4,suppresspanel_create); + mainpanel_panelentry(panel,"_Equalizer ","[e]",5,eqpanel_create); + mainpanel_panelentry(panel,"_Limiter ","[l]",6,limitpanel_create); g_signal_connect (G_OBJECT (panel->toplevel), "delete_event", G_CALLBACK (shutdown), NULL); @@ -834,7 +900,7 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){ } -static gboolean feedback_process(postfish_mainpanel *panel){ +static void feedback_process(postfish_mainpanel *panel){ /* first order of business: release the play button if playback is no longer in progress */ @@ -863,6 +929,13 @@ static gboolean feedback_process(postfish_mainpanel *panel){ if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(panel->channelshow[i]))){ peak[i]=todB(peak[i]); rms[i]=todB(rms[i]); + + if(peak[i]>panel->outpeak){ + panel->outpeak=ceil(peak[i]); + sprintf(buffer,"%+4.0fdB",panel->outpeak); + readout_set(READOUT(panel->outreadout),buffer); + } + }else{ peak[i]=-400; rms[i]=-400; @@ -877,6 +950,13 @@ static gboolean feedback_process(postfish_mainpanel *panel){ if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(panel->channelshow[i]))){ peak[i]=todB(peak[i]); rms[i]=todB(rms[i]); + + if(peak[i]>panel->inpeak){ + panel->inpeak=ceil(peak[i]); + sprintf(buffer,"%+4.0fdB",panel->inpeak); + readout_set(READOUT(panel->inreadout),buffer); + } + }else{ peak[i]=-400; rms[i]=-400; @@ -891,6 +971,8 @@ static gboolean feedback_process(postfish_mainpanel *panel){ clippanel_feedback(current_p); eqpanel_feedback(current_p); compandpanel_feedback(current_p); + singlepanel_feedback(current_p); + limitpanel_feedback(current_p); } } @@ -900,7 +982,6 @@ static gboolean async_event_handle(GIOChannel *channel, GIOCondition condition, gpointer data){ postfish_mainpanel *panel=data; - int i; char buf[1]; read(eventpipe[0],buf,1); @@ -967,7 +1048,6 @@ void mainpanel_go(int argc,char *argv[], int ch){ /* set up watching the event pipe */ { GIOChannel *channel = g_io_channel_unix_new (eventpipe[0]); - GSource *source; guint id; g_io_channel_set_encoding (channel, NULL, NULL); diff --git a/mainpanel.h b/mainpanel.h index 4f502de..6c55978 100644 --- a/mainpanel.h +++ b/mainpanel.h @@ -29,6 +29,8 @@ typedef struct postfish_mainpanel postfish_mainpanel; #include "clippanel.h" #include "eqpanel.h" #include "compandpanel.h" +#include "singlepanel.h" +#include "limitpanel.h" struct postfish_mainpanel{ GtkWidget *topframe; @@ -60,6 +62,7 @@ struct postfish_mainpanel{ GtkWidget *buttonactive[7]; + GtkWidget *cue_act[2]; GtkWidget *cue_set[2]; GtkWidget *cue_reset[2]; @@ -67,6 +70,11 @@ struct postfish_mainpanel{ GtkWidget *inbar; GtkWidget *outbar; + GtkWidget *inreadout; + GtkWidget *outreadout; + + float inpeak; + float outpeak; GtkWidget *channelshow[10]; /* support only up to 8 + mid/side */ diff --git a/multibar.c b/multibar.c index 271ff92..016f05f 100644 --- a/multibar.c +++ b/multibar.c @@ -21,9 +21,9 @@ * */ -#include #include #include +#include #include #include "multibar.h" @@ -516,9 +516,7 @@ static void draw(GtkWidget *widget,int n){ int x=m->thumbpixel[0]+xpad; int x0=x-(y1-y-2); - int x1=x+(y1-y-2); int x2=x0-y*3/2; - int x3=x1+y*3/2; GdkPoint tp[5]={ {x,y0},{x-yM,y0+yM},{x2,y0+yM},{x2,y1+1}, {x,y1+1}}; @@ -557,9 +555,7 @@ static void draw(GtkWidget *widget,int n){ GdkGC *dark_gc=widget->style->dark_gc[m->thumbstate[num]]; int x=m->thumbpixel[num]+xpad; - int x0=x-(y1-y-2); int x1=x+(y1-y-2); - int x2=x0-y*3/2; int x3=x1+y*3/2; GdkPoint tp[5]={ {x,y0},{x+yM,y0+yM},{x3,y0+yM},{x3,y1+1}, @@ -836,7 +832,7 @@ static gboolean configure(GtkWidget *widget, GdkEventConfigure *event){ int i; if (m->backing) - gdk_drawable_unref(m->backing); + g_object_unref(m->backing); m->backing = gdk_pixmap_new(widget->window, widget->allocation.width, @@ -968,7 +964,7 @@ static gint multibar_leave(GtkWidget *widget, return TRUE; } -static gint button_press (GtkWidget *widget, +static gboolean button_press (GtkWidget *widget, GdkEventButton *event){ Multibar *m=MULTIBAR(widget); if(m->thumbstate[0]){ @@ -985,13 +981,15 @@ static gint button_press (GtkWidget *widget, m->thumbx=m->thumbpixel[2]-event->x; } draw_and_expose(widget); + return TRUE; } -static gint button_release (GtkWidget *widget, +static gboolean button_release (GtkWidget *widget, GdkEventButton *event){ Multibar *m=MULTIBAR(widget); m->thumbgrab=-1; draw_and_expose(widget); + return TRUE; } static gboolean unfocus(GtkWidget *widget, @@ -1000,6 +998,7 @@ static gboolean unfocus(GtkWidget *widget, m->prev_thumbfocus=m->thumbfocus; m->thumbfocus=-1; draw_and_expose(widget); + return TRUE; } static gboolean refocus(GtkWidget *widget, @@ -1008,6 +1007,7 @@ static gboolean refocus(GtkWidget *widget, transition_thumbfocus=m->thumbfocus=m->prev_thumbfocus; m->thumbgrab=-1; draw_and_expose(widget); + return TRUE; } gboolean key_press(GtkWidget *w,GdkEventKey *event){ @@ -1175,7 +1175,6 @@ GtkWidget* multibar_new (int n, char **labels, float *levels, int thumbs, GtkWidget* multibar_slider_new (int n, char **labels, float *levels, int thumbs){ - int i; GtkWidget *ret= multibar_new(n,labels,levels,thumbs,0); Multibar *m=MULTIBAR(ret); m->readout=0; diff --git a/multicompand.c b/multicompand.c index 4c0eafd..5b64558 100644 --- a/multicompand.c +++ b/multicompand.c @@ -28,104 +28,14 @@ #include "subband.h" #include "bessel.h" -static int offset=0; -static void _analysis(char *base,int i,float *v,int n,int bark,int dB){ - int j; - FILE *of; - char buffer[80]; - - sprintf(buffer,"%s_%d.m",base,i); - of=fopen(buffer,"w"); - - if(!of)perror("failed to open data dump file"); - - for(j=0;j0?-x:0.); -} - typedef struct { - double c0; - double c1; - double g; - float alpha; - //int impulseahead; // 5764 == 1Hz @ 44.1 - //int stepahead; // 14850 == 1Hz @ 44.1 -} iir_filter; - -static inline long impulse_ahead(float alpha){ - return rint(.1307f/alpha); -} - -static inline long step_ahead(float alpha){ - return rint(.3367f/alpha); -} - -static inline float step_freq(long ahead){ - return input_rate*.3367/ahead; -} - -#if NASTY_IEEE_FLOAT32_HACK_IS_FASTER_THAN_LOG - -#define todB_p(x) (((*(int32_t*)(x)) & 0x7fffffff) * 7.1771144e-7f - 764.27118f) - -#else - -#define todB_p(x) todB(*(x)) - -#endif - -typedef struct { - double x[2]; - double y[2]; - int state; -} iir_state; + int loc; + float val; +} peak_state; typedef struct { subband_state ss; @@ -137,23 +47,20 @@ typedef struct { iir_filter under_attack[multicomp_banks][multicomp_freqs_max]; iir_filter under_decay[multicomp_banks][multicomp_freqs_max]; - iir_filter suppress_attack[multicomp_banks][multicomp_freqs_max]; - iir_filter suppress_decay[multicomp_banks][multicomp_freqs_max]; - iir_filter suppress_release[multicomp_banks][multicomp_freqs_max]; + iir_filter base_attack[multicomp_banks][multicomp_freqs_max]; + iir_filter base_decay[multicomp_banks][multicomp_freqs_max]; iir_state *over_iir[multicomp_freqs_max]; iir_state *under_iir[multicomp_freqs_max]; - iir_state *suppress_iirA[multicomp_freqs_max]; - iir_state *suppress_iirB[multicomp_freqs_max]; + iir_state *base_iir[multicomp_freqs_max]; + peak_state *over_peak[multicomp_freqs_max]; + peak_state *under_peak[multicomp_freqs_max]; + peak_state *base_peak[multicomp_freqs_max]; + sig_atomic_t pending_bank; sig_atomic_t active_bank; - int previous_over_mode; // RMS or peak? The iir follower domains - // are different, and upon transition, must be converted. - int previous_under_mode; // as above - int previous_suppress_mode; // as above - } multicompand_state; sig_atomic_t compand_visible; @@ -161,30 +68,31 @@ sig_atomic_t compand_active; banked_compand_settings bc[multicomp_banks]; other_compand_settings c; -multicompand_state ms; + +static multicompand_state ms; int pull_multicompand_feedback(float **peak,float **rms,int *bands){ return pull_subband_feedback(&ms.ss,peak,rms,bands); } -static sig_atomic_t pending_bank=0; -static sig_atomic_t reading=0; void multicompand_reset(){ - int h,i,j; + int i,j; subband_reset(&ms.ss); for(i=0;icorner_freq && attackp) + corner_freq=step_freq(input_size*2-ms.ss.qblocksize*3); + + alpha=corner_freq/input_rate; + filter->g=mkbessel(alpha,2,filter->c); + filter->alpha=alpha; + filter->Hz=alpha*input_rate; +} + + +static int multicompand_filterbank_set(float msec, + iir_filter + filterbank[multicomp_banks] + [multicomp_freqs_max], + int attackp){ int i,j; for(j=0;jfreqs[i]/2)corner_freq=freqs[i]/2; - - /* make sure the chosen frequency doesn't require a lookahead - greater than what's available */ - if(step_freq(input_size*2-ms.ss.qblocksize*3)*.95c0; - double d_c0=decay->c0; - double a_c1=attack->c1; - double d_c1=decay->c1; - double a_g=attack->g; - 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 state=is->state; - - int i=0; - - if(x[0]>y0)state=0; - - while(i=n)break; - if(x[i]>y0){ - state=0; - break; - } +static void prepare_peak(float *peak, float *x, int n, int ahead,int hold, + peak_state *ps){ + int ii,jj; + int loc=ps->loc; + float val=ps->val; + + /* Although we have two input_size blocks of zeroes after a + reset, we may still need to look ahead explicitly after a + reset if the lookahead is exceptionally long */ + if(loc==0 && val==0){ + for(ii=0;iival){ + val=fabs(x[ii]); + loc=ii+hold; } - } } - is->x[0]=x0; - is->x[1]=x1; - is->y[0]=y0; - is->y[1]=y1; - is->state=state; + if(val>peak[0])peak[0]=val; -} - -static void prepare_rms(float *rms, float **xx, int n, int ch,int ahead){ - if(ch){ - int i,j; - - memset(rms,0,sizeof(*rms)*n); - - for(j=0;j1) - for(i=0;ival){ - val=fabs(x[ii]); - loc=ii; - } - if(val>peak[0])peak[0]=val; - - for(ii=1;iival){ - val=fabs(x[ii+ahead]); - loc=ii+ahead; - } - if(ii>=loc){ - /* backfill */ - val=0; - for(jj=ii+ahead-1;jj>=ii;jj--){ - if(fabs(x[jj])>val)val=fabs(x[jj]); - if(jjpeak[jj])peak[jj]=val; - } - val=fabs(x[ii+ahead-1]); - loc=ii+ahead; - } - if(val>peak[ii])peak[ii]=val; + for(ii=1;iival){ + val=fabs(x[ii+ahead]); + loc=ii+ahead+hold; + } + if(ii>=loc){ + /* backfill */ + val=0; + for(jj=ii+ahead-1;jj>=ii;jj--){ + if(fabs(x[jj])>val)val=fabs(x[jj]); + if(jjpeak[jj])peak[jj]=val; } + val=fabs(x[ii+ahead-1]); + loc=ii+ahead+hold; } - - for(j=0;jpeak[ii])peak[ii]=val; } + + ps->loc=loc-input_size; + ps->val=val; + } -static void run_filter_only(float *dB,float *work,float **x,int n,int mode, +static void run_filter_only(float *dB,int n,int mode, iir_state *iir,iir_filter *attack,iir_filter *decay){ int i; - - compute_iir(dB, work, n, &iir[i], attack, decay); - + compute_iir2(dB, n, iir, attack, decay); + if(mode==0) for(i=0;ialpha)*lookahead); +static void run_filter(float *dB,float *x,int n, + float lookahead,int mode, + iir_state *iir,iir_filter *attack,iir_filter *decay, + peak_state *ps){ - else - prepare_rms(work, x, n, ch, impulse_ahead(attack->alpha)*lookahead); + memset(dB,0,sizeof(*dB)*n); + + if(mode) + prepare_peak(dB, x, n, + step_ahead(attack->alpha)*lookahead, + step_ahead(attack->alpha)*(1.-lookahead), + ps); + else + prepare_rms(dB, x, n, impulse_ahead2(attack->alpha)*lookahead); - } - }else{ - if(mode) - prepare_peak(work, x+i, n, 1, step_ahead(attack->alpha)*lookahead); - else - prepare_rms(work, x+i, n, 1, impulse_ahead(attack->alpha)*lookahead); - } + + run_filter_only(dB,n,mode,iir,attack,decay); +} - run_filter_only(dB,work,x,n,mode,iir,attack,decay); +static float soft_knee(float x){ + return (sqrtf(x*x+30.f)+x)*-.5f; } -static void over_compand(float ***x){ - int i,j,k; - float work[input_size]; - float dB[input_size]; +static float hard_knee(float x){ + return (x>0.f?-x:0.f); +} + +static void over_compand(float *lx,float zerocorner, + iir_filter *attack, iir_filter *decay, + iir_state *iir, peak_state *ps, + float *peakfeed, float *rmsfeed,float *adj,int active){ + int k; + float overdB[input_size]; float lookahead=c.over_lookahead/1000.; - int link=c.link_mode; int mode=c.over_mode; - - float (*knee)(float)=(c.over_softknee?soft_knee:hard_knee); - float corner_multiplier=(1.-1./(c.over_ratio/1000.)); - float base_multiplier=(1.-1./(c.base_ratio/1000.)); - if(ms.previous_over_mode!=mode){ - /* the followers for RMS are in linear^2 mode, the followers for - peak are dB. If the mode has changed, we need to convert from - one to the other to avoid pops */ - if(mode==0){ - /* from dB to linear^2 */ - for(i=0;imax){ + max=val; + maxpos=k; } + rms+=val; } - } - - ms.previous_under_mode=mode; - - for(i=0;ipeak)peak=fabs(x[k]); - } + over_compand(ms.ss.lap[i][j], + bc[ms.active_bank].static_o[i], + &ms.over_attack[ms.active_bank][i], + &ms.over_decay[ms.active_bank][i], + &ms.over_iir[i][j], + &ms.over_peak[i][j], + &peakfeed[i][j], + &rmsfeed[i][j], + adj,active); - peakfeed[i][j]=todB(peak); - rmsfeed[i][j]=todB(rms/input_size)*.5; + base_compand(ms.ss.lap[i][j], + &ms.base_attack[ms.active_bank][i], + &ms.base_decay[ms.active_bank][i], + &ms.base_iir[i][j], + &ms.base_peak[i][j], + adj,active); } - } - }else{ - for(i=0;ipeak)peak=fabs(x[k]); - } - } - - for(j=0;jrms,sizeof(*rms)*n); if(peak)memcpy(peak,f->peak,sizeof(*peak)*n); @@ -207,7 +213,6 @@ void *playback_thread(void *dummy){ time_linkage *link; int result; off_t count=0; - long last=-1; int ch=-1; long rate=-1; @@ -231,6 +236,10 @@ void *playback_thread(void *dummy){ result|=link->samples; link=multicompand_read(link); result|=link->samples; + link=singlecomp_read(link); + result|=link->samples; + link=suppress_read(link); + result|=link->samples; link=eq_read(link); result|=link->samples; @@ -238,8 +247,7 @@ void *playback_thread(void *dummy){ /************/ - - /* temporary; this would be frequency domain in the finished postfish */ + /* master att */ if(link->samples>0){ float scale=fromdB(master_att/10.); for(i=0;isamples;i++) @@ -248,6 +256,9 @@ void *playback_thread(void *dummy){ } + /* the limiter is single-block zero additional latency */ + link=limit_read(link); + /************/ if(link->samples>0){ @@ -280,7 +291,6 @@ void *playback_thread(void *dummy){ for(k=0,i=0;isamples;i++){ float mean=0.; - float div=0.; float divrms=0.; for(j=0;jchannels;j++){ diff --git a/postfish-gtkrc b/postfish-gtkrc index 70892bf..32468b3 100644 --- a/postfish-gtkrc +++ b/postfish-gtkrc @@ -78,7 +78,7 @@ style "multislide" { text[NORMAL]="#707070" text[ACTIVE]="#905050" - font_name = "sans 6" + font_name = "sans 7" } style "clipbar" { @@ -98,6 +98,15 @@ style "readout" { font_name = "Fixed, Nimbus Mono L, Courier, Monospace 10" } +style "small-readout" { + base[NORMAL]="#ffffff" + base[ACTIVE]="#ffffff" + bg[NORMAL]="#ffffff" + bg[ACTIVE]="#ffffff" + text[NORMAL]="#606060" + font_name = "Fixed, Nimbus Mono L, Courier, Monospace 8" +} + style "darkpanel" { bg[NORMAL]="#b0b0b0" } @@ -160,6 +169,7 @@ widget "*.GtkFrame.GtkHBox.GtkLabel" style "frame-label" widget "*.framelabel" style "frame-label" widget "*.Readout*" style "readout" +widget "*.smallreadout" style "small-readout" widget "*.GtkEntry" style "readout" widget "*.GtkHScale" style "slider" widget "*.GtkToggleButton*" style "button-poppy" diff --git a/postfish.h b/postfish.h index 99583ca..87f64e4 100644 --- a/postfish.h +++ b/postfish.h @@ -50,8 +50,37 @@ #include #include -#define todB(x) ((x)==0?-400.f:log((x)*(x))*4.34294480f) -#define fromdB(x) (exp((x)*.11512925f)) +static inline float todB(float x){ + return logf((x)*(x)+1e-30f)*4.34294480f; +} + +static inline float fromdB(float x){ + return expf((x)*.11512925f); +} + +#ifdef UGLY_IEEE754_FLOAT32_HACK + +static inline float todB_a(const float *x){ + return (float)((*(int32_t *)x)&0x7fffffff) * 7.1771144e-7f -764.27118f; +} + +static inline float fromdB_a(float x){ + int y=1.3933e+06f*(x+764.27118f); + return *(float *)&y; +} + +#else + +static inline float todB_a(const float *x){ + return todB(*x); +} + +static inline float fromdB_a(float x){ + return fromdB(x); +} + +#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)) diff --git a/readout.c b/readout.c index ccf3830..149727a 100644 --- a/readout.c +++ b/readout.c @@ -103,7 +103,7 @@ static gboolean configure(GtkWidget *widget, GdkEventConfigure *event){ Readout *r=READOUT(widget); if (r->backing) - gdk_drawable_unref(r->backing); + g_object_unref(r->backing); r->backing = gdk_pixmap_new(widget->window, widget->allocation.width, diff --git a/readout.h b/readout.h index dbc69c6..cd275e9 100644 --- a/readout.h +++ b/readout.h @@ -30,6 +30,7 @@ #include #include #include +#include G_BEGIN_DECLS diff --git a/reconstruct.c b/reconstruct.c index f7b3bac..2e25949 100644 --- a/reconstruct.c +++ b/reconstruct.c @@ -30,6 +30,7 @@ #include #include +#include #include "reconstruct.h" /* fftw3 requires this kind of static setup */ @@ -39,7 +40,7 @@ static fftwf_plan fftwf_sf; static fftwf_plan fftwf_sb; static float *q; static float *s; -static blocksize=0; +static int blocksize=0; void reconstruct_reinit(int n){ if(blocksize!=n){ diff --git a/rexperiment.c b/rexperiment.c new file mode 100644 index 0000000..db4fee5 --- /dev/null +++ b/rexperiment.c @@ -0,0 +1,295 @@ +/* + * + * postfish + * + * Copyright (C) 2002-2004 Monty and Xiph.Org + * + * 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. + * + * + */ + +/* arbitrary reconstruction filter. Postfish uses this for declipping. + + Many thanks to Johnathan Richard Shewchuk and his excellent paper + 'An Introduction to the Conjugate Gradient Method Without the + Agonizing Pain' for the additional understanding needed to make the + n^3 -> n^2 log n jump possible. Google for it, you'll find it. */ + +#include +#include "smallft.h" + +static void drft_forward_transpose(drft_lookup *fft, double *x){ + int i; + + for(i=1;in-1;i++)x[i]*=.5; + drft_backward(fft,x); +} + +static void drft_backward_transpose(drft_lookup *fft, double *x){ + int i; + + drft_forward(fft,x); + for(i=1;in-1;i++)x[i]*=2.; +} + +#include "postfish.h" +#include "test.h" + +static void sliding_bark_average(double *f,double *w, int n){ + int lo=0,hi=0,i; + double acc=0.; + + { + double bark=toBark(0); + int newhi=rint(fromBark(bark+.5)*n/44100.)+5; + acc+=fabs(f[0]); + for(hi=1;hin/2)newhi=n/2; + + for(;hie*e*phi_0;i++){ + compute_AtAx(fft,d,w,flag,1,n,q); + alpha=phi_new/inner_product(d,q,n); + for(j=0;je*e*phi_0;i++){ + compute_AtAx(fft,d,w,flag,1,n,q); + alpha=phi_new/inner_product(d,q,n); + for(j=0;j=.2 || work[i]<=-.2)flag[i]=1; + } + + for(i=0;i<512;i++)work[i]*=window[i]; + + for(i=0;i<512;i++)_analysis("pcm",i,work,512,0,0); + memcpy(freq,work,sizeof(work)); + drft_forward(&fft,freq); + for(i=0;i<512;i++)_analysis("freq",i,freq,512,1,1); + + sliding_bark_average(freq,w,blocksize); + _analysis("w",0,w,512,1,1); + + for(i=0;i<512;i++)w[i]= 1./(w[i]*w[i]); + + reconstruct2(&fft,work,w,flag,0,blocksize,blocksize); + +} + + diff --git a/singlecomp.c b/singlecomp.c new file mode 100644 index 0000000..a7397c1 --- /dev/null +++ b/singlecomp.c @@ -0,0 +1,521 @@ +/* + * + * postfish + * + * Copyright (C) 2002-2004 Monty and Xiph.Org + * + * 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 "feedback.h" +#include "bessel.h" +#include "singlecomp.h" + +extern int input_size; +extern int input_rate; +extern int input_ch; + +sig_atomic_t singlecomp_active; +sig_atomic_t singlecomp_visible; + +typedef struct { + int loc; + float val; +} peak_state; + +typedef struct{ + time_linkage out; + feedback_generic_pool feedpool; + + iir_state *o_iir; + iir_state *u_iir; + iir_state *b_iir; + + peak_state *o_peak; + peak_state *u_peak; + peak_state *b_peak; + + iir_filter o_attack; + iir_filter o_decay; + iir_filter u_attack; + iir_filter u_decay; + iir_filter b_attack; + iir_filter b_decay; + + int fillstate; + float **cache; + int cache_samples; + +} singlecomp_state; + +singlecomp_settings scset; +singlecomp_state scs; + +static void _analysis(char *base,int i,float *v,int n,int dB,int offset){ + int j; + FILE *of; + char buffer[80]; + + sprintf(buffer,"%s_%d.m",base,i); + of=fopen(buffer,"a"); + + if(!of)perror("failed to open data dump file"); + + for(j=0;jpeak,sizeof(*peak)*input_ch); + if(rms) + memcpy(rms,f->rms,sizeof(*rms)*input_ch); + feedback_old(&scs.feedpool,(feedback_generic *)f); + return 1; +} + +/* called only by initial setup */ +int singlecomp_load(void){ + int i; + memset(&scs,0,sizeof(scs)); + + 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_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.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;icorner_freq && attackp) + corner_freq=step_freq(input_size); + + alpha=corner_freq/input_rate; + filter->g=mkbessel(alpha,2,filter->c); + filter->alpha=alpha; + filter->Hz=alpha*input_rate; + filter->ms=msec; +} + +/* called only in playback thread */ +int singlecomp_reset(void ){ + /* reset cached pipe state */ + scs.fillstate=0; + while(pull_singlecomp_feedback(NULL,NULL)); + + memset(scs.o_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)); + return 0; +} + +static void prepare_peak(float *peak, float *x, int n, int ahead,int hold, + peak_state *ps){ + int ii,jj; + int loc=ps->loc; + float val=ps->val; + + /* Although we have two input_size blocks of zeroes after a + reset, we may still need to look ahead explicitly after a + reset if the lookahead is exceptionally long */ + + if(loc==0 && val==0){ + for(ii=0;iival){ + val=fabs(x[ii]); + loc=ii+hold; + } + } + + if(val>peak[0])peak[0]=val; + + for(ii=1;iival){ + val=fabs(x[ii+ahead]); + loc=ii+ahead+hold; + } + if(ii>=loc){ + /* backfill */ + val=0; + for(jj=ii+ahead-1;jj>=ii;jj--){ + if(fabs(x[jj])>val)val=fabs(x[jj]); + if(jjpeak[jj])peak[jj]=val; + } + val=fabs(x[ii+ahead-1]); + loc=ii+ahead+hold; + } + if(val>peak[ii])peak[ii]=val; + } + + ps->loc=loc-input_size; + ps->val=val; +} + +static void run_filter(float *cache, float *in, float *work, + int ahead,int hold,int mode, + iir_state *iir,iir_filter *attack,iir_filter *decay, + peak_state *ps){ + int k; + float *work2=work+input_size; + + if(mode){ + /* peak mode */ + memcpy(work,cache,sizeof(*work)*input_size); + memcpy(work2,in,sizeof(*work)*input_size); + + prepare_peak(work, work, input_size, ahead, hold, ps); + + }else{ + /* rms mode */ + float *cachea=cache+ahead; + float *worka=work+input_size-ahead; + + for(k=0;k0.f?-x:0.f); +} + +static void over_compand(float *A,float *B,float *adj, + float zerocorner,float multiplier, + float lookahead,int mode,int softknee, + iir_filter *attack, iir_filter *decay, + iir_state *iir, peak_state *ps, + int active){ + + int k; + float work[input_size*2]; + int ahead=(mode?step_ahead(attack->alpha):impulse_ahead2(attack->alpha)); + int hold=(1.-lookahead)*ahead; + ahead-=hold; + + run_filter(A,B,work,ahead,hold,mode,iir,attack,decay,ps); + + if(active){ + if(softknee){ + for(k=0;kalpha):impulse_ahead2(attack->alpha)); + int hold=(1.-lookahead)*ahead; + ahead-=hold; + + run_filter(A,B,work,ahead,hold,mode,iir,attack,decay,ps); + + if(active){ + if(softknee){ + for(k=0;kalpha):impulse_ahead2(attack->alpha)); + + run_filter(A,B,work,ahead,0,mode,iir,attack,decay,ps); + + if(active) + for(k=0;ksamples==0){ + scs.out.samples=0; + return &scs.out; + } + for(i=0;idata[i]; + float adj[input_size]; // under will set it + + 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)); + memset(scs.cache[i],0,sizeof(**scs.cache)*input_size); + + under_compand(scs.cache[i],in->data[i],adj, + (float)(scset.u_thresh), + 1.-1./(scset.u_ratio/1000.), + scset.u_lookahead/1000., + scset.u_mode, + scset.u_softknee, + &scs.u_attack,&scs.u_decay, + scs.u_iir+i,scs.u_peak+i, + active); + + over_compand(scs.cache[i],in->data[i],adj, + (float)(scset.o_thresh), + 1.-1./(scset.o_ratio/1000.), + scset.o_lookahead/1000., + scset.o_mode, + scset.o_softknee, + &scs.o_attack,&scs.o_decay, + scs.o_iir+i,scs.o_peak+i, + active); + + base_compand(scs.cache[i],in->data[i],adj, + 1.-1./(scset.b_ratio/1000.), + scset.b_mode, + &scs.b_attack,&scs.b_decay, + scs.b_iir+i,scs.b_peak+i, + active); + + + in->data[i]=scs.cache[i]; + scs.cache[i]=temp; + } + scs.cache_samples=in->samples; + scs.fillstate=1; + scs.out.samples=0; + if(in->samples==in->size)goto tidy_up; + + for(i=0;idata[i],0,sizeof(**in->data)*in->size); + in->samples=0; + /* fall through */ + case 1: /* nominal processing */ + + for(i=0;idata[i],adj, + (float)(scset.u_thresh), + 1.-1./(scset.u_ratio/1000.), + scset.u_lookahead/1000., + scset.u_mode, + scset.u_softknee, + &scs.u_attack,&scs.u_decay, + scs.u_iir+i,scs.u_peak+i, + active); + + over_compand(scs.cache[i],in->data[i],adj, + (float)(scset.o_thresh), + 1.-1./(scset.o_ratio/1000.), + scset.o_lookahead/1000., + scset.o_mode, + scset.o_softknee, + &scs.o_attack,&scs.o_decay, + scs.o_iir+i,scs.o_peak+i, + active); + + /* feedback before base */ + { + int k; + float rms=0.; + float peak=0.; + float *x=scs.cache[i]; + + for(k=0;kdata[i],adj, + 1.-1./(scset.b_ratio/1000.), + scset.b_mode, + &scs.b_attack,&scs.b_decay, + scs.b_iir+i,scs.b_peak+i, + active); + + if(active){ + int k; + float *x=scs.cache[i]; + float *out=scs.out.data[i]; + + for(k=0;kdata[i]; + in->data[i]=temp; + } + } + scs.out.samples=scs.cache_samples; + scs.cache_samples=in->samples; + if(scs.out.samplespeak) + ff->peak=malloc(input_ch*sizeof(*ff->peak)); + + if(!ff->rms) + ff->rms=malloc(input_ch*sizeof(*ff->rms)); + + memcpy(ff->peak,peakfeed,sizeof(peakfeed)); + memcpy(ff->rms,rmsfeed,sizeof(rmsfeed)); + + feedback_push(&scs.feedpool,(feedback_generic *)ff); + } + + tidy_up: + { + int tozero=scs.out.size-scs.out.samples; + if(tozero) + for(i=0;i +#include +#include "readout.h" +#include "multibar.h" +#include "mainpanel.h" +#include "subpanel.h" +#include "feedback.h" +#include "singlecomp.h" +#include "singlepanel.h" + +extern sig_atomic_t singlecomp_active; +extern sig_atomic_t singlecomp_visible; +extern int input_ch; +extern int input_size; +extern int input_rate; + +extern singlecomp_settings scset; + +typedef struct { + GtkWidget *r0; + GtkWidget *r1; +} multireadout; + +GtkWidget *t_label; +GtkWidget *t_slider; +multireadout t_readout; + + +static void compand_change(GtkWidget *w,Readout *r,sig_atomic_t *var){ + char buffer[80]; + float val=1./multibar_get_value(MULTIBAR(w),0); + + if(val==1.){ + sprintf(buffer," off"); + }else if(val>=10){ + sprintf(buffer,"%4.1f:1",val); + }else if(val>=1){ + sprintf(buffer,"%4.2f:1",val); + }else if(val>.10001){ + sprintf(buffer,"1:%4.2f",1./val); + }else{ + sprintf(buffer,"1:%4.1f",1./val); + } + + readout_set(r,buffer); + + *var=rint(val*1000.); +} +static void under_compand_change(GtkWidget *w,gpointer in){ + compand_change(w,(Readout *)in,&scset.u_ratio); +} + +static void over_compand_change(GtkWidget *w,gpointer in){ + compand_change(w,(Readout *)in,&scset.o_ratio); +} + +static void base_compand_change(GtkWidget *w,gpointer in){ + compand_change(w,(Readout *)in,&scset.b_ratio); +} + +static void timing_display(GtkWidget *w,GtkWidget *r,float v){ + char buffer[80]; + + if(v<10){ + sprintf(buffer,"%4.2fms",v); + }else if(v<100){ + sprintf(buffer,"%4.1fms",v); + }else if (v<1000){ + sprintf(buffer,"%4.0fms",v); + }else if (v<10000){ + sprintf(buffer,"%4.2fs",v/1000.); + }else{ + sprintf(buffer,"%4.1fs",v/1000.); + } + + readout_set(READOUT(r),buffer); +} + +static void under_timing_change(GtkWidget *w,gpointer in){ + multireadout *r=(multireadout *)in; + float attack=multibar_get_value(MULTIBAR(w),0); + float decay=multibar_get_value(MULTIBAR(w),1); + + timing_display(w,r->r0,attack); + timing_display(w,r->r1,decay); + + scset.u_attack=rint(attack*10.); + scset.u_decay=rint(decay*10.); +} + +static void over_timing_change(GtkWidget *w,gpointer in){ + multireadout *r=(multireadout *)in; + float attack=multibar_get_value(MULTIBAR(w),0); + float decay=multibar_get_value(MULTIBAR(w),1); + + timing_display(w,r->r0,attack); + timing_display(w,r->r1,decay); + + scset.o_attack=rint(attack*10.); + scset.o_decay=rint(decay*10.); +} + +static void base_timing_change(GtkWidget *w,gpointer in){ + multireadout *r=(multireadout *)in; + float attack=multibar_get_value(MULTIBAR(w),0); + float decay=multibar_get_value(MULTIBAR(w),1); + + timing_display(w,r->r0,attack); + timing_display(w,r->r1,decay); + + scset.b_attack=rint(attack*10.); + scset.b_decay=rint(decay*10.); +} + +static void under_lookahead_change(GtkWidget *w,gpointer in){ + char buffer[80]; + Readout *r=(Readout *)in; + float val=multibar_get_value(MULTIBAR(w),0); + + sprintf(buffer,"%3.0f%%",val); + readout_set(r,buffer); + + scset.u_lookahead=rint(val*10.); +} + +static void over_lookahead_change(GtkWidget *w,gpointer in){ + char buffer[80]; + Readout *r=(Readout *)in; + float val=multibar_get_value(MULTIBAR(w),0); + + sprintf(buffer,"%3.0f%%",val); + readout_set(r,buffer); + + scset.o_lookahead=rint(val*10.); +} + +static void slider_change(GtkWidget *w,gpointer in){ + char buffer[80]; + multireadout *r=(multireadout *)in; + int o,u; + + u=multibar_get_value(MULTIBAR(w),0); + sprintf(buffer,"%+4ddB",u); + readout_set(READOUT(r->r0),buffer); + scset.u_thresh=u; + + o=multibar_get_value(MULTIBAR(w),1); + sprintf(buffer,"%+4ddB",o); + readout_set(READOUT(r->r1),buffer); + scset.o_thresh=o; +} + +static void over_mode(GtkButton *b,gpointer in){ + int mode=(int)in; + scset.o_mode=mode; +} + +static void under_mode(GtkButton *b,gpointer in){ + int mode=(int)in; + scset.u_mode=mode; +} + +static void base_mode(GtkButton *b,gpointer in){ + int mode=(int)in; + scset.b_mode=mode; +} + +static void under_knee(GtkToggleButton *b,gpointer in){ + int mode=gtk_toggle_button_get_active(b); + scset.u_softknee=mode; +} + +static void over_knee(GtkToggleButton *b,gpointer in){ + int mode=gtk_toggle_button_get_active(b); + scset.o_softknee=mode; +} + +void singlepanel_create(postfish_mainpanel *mp, + GtkWidget *windowbutton, + GtkWidget *activebutton){ + + char *labels[14]={"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"}; + + float timing_levels[6]={.5,1,10,100,1000,10000}; + char *timing_labels[5]={"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%"}; + + + subpanel_generic *panel=subpanel_create(mp,windowbutton,activebutton, + &singlecomp_active, + &singlecomp_visible, + "_Singleband Compand"," [s] "); + + GtkWidget *sliderframe=gtk_frame_new(NULL); + GtkWidget *allbox=gtk_vbox_new(0,0); + GtkWidget *slidertable=gtk_table_new(2,3,0); + + GtkWidget *overlabel=gtk_label_new("Over threshold compand "); + GtkWidget *overtable=gtk_table_new(6,4,0); + + GtkWidget *underlabel=gtk_label_new("Under threshold compand "); + GtkWidget *undertable=gtk_table_new(5,4,0); + + GtkWidget *baselabel=gtk_label_new("Global compand "); + GtkWidget *basetable=gtk_table_new(3,4,0); + + gtk_widget_set_name(overlabel,"framelabel"); + gtk_widget_set_name(underlabel,"framelabel"); + gtk_widget_set_name(baselabel,"framelabel"); + + gtk_misc_set_alignment(GTK_MISC(overlabel),0,.5); + gtk_misc_set_alignment(GTK_MISC(underlabel),0,.5); + gtk_misc_set_alignment(GTK_MISC(baselabel),0,.5); + + + { + GtkWidget *label1=gtk_label_new("compand threshold"); + GtkWidget *label2=gtk_label_new("under"); + GtkWidget *label3=gtk_label_new("over"); + + gtk_misc_set_alignment(GTK_MISC(label1),.5,1.); + gtk_misc_set_alignment(GTK_MISC(label2),.5,1.); + gtk_misc_set_alignment(GTK_MISC(label3),.5,1.); + gtk_widget_set_name(label2,"scalemarker"); + gtk_widget_set_name(label3,"scalemarker"); + + gtk_table_attach(GTK_TABLE(slidertable),label2,0,1,0,1,GTK_FILL,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(slidertable),label1,1,2,0,1,GTK_FILL,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(slidertable),label3,2,3,0,1,GTK_FILL,GTK_FILL|GTK_EXPAND,2,0); + + gtk_container_add(GTK_CONTAINER(sliderframe),slidertable); + + //gtk_frame_set_shadow_type(GTK_FRAME(sliderframe),GTK_SHADOW_NONE); + + gtk_container_set_border_width(GTK_CONTAINER(sliderframe),4); + gtk_container_set_border_width(GTK_CONTAINER(slidertable),10); + + } + + gtk_box_pack_start(GTK_BOX(panel->subpanel_box),allbox,0,0,0); + gtk_box_pack_start(GTK_BOX(allbox),sliderframe,0,0,0); + + + { + GtkWidget *hs1=gtk_hseparator_new(); + GtkWidget *hs2=gtk_hseparator_new(); + + //gtk_box_pack_start(GTK_BOX(allbox),hs3,0,0,0); + gtk_box_pack_start(GTK_BOX(allbox),overtable,0,0,10); + gtk_box_pack_start(GTK_BOX(allbox),hs1,0,0,0); + gtk_box_pack_start(GTK_BOX(allbox),undertable,0,0,10); + gtk_box_pack_start(GTK_BOX(allbox),hs2,0,0,0); + gtk_box_pack_start(GTK_BOX(allbox),basetable,0,0,10); + + gtk_container_set_border_width(GTK_CONTAINER(overtable),5); + gtk_container_set_border_width(GTK_CONTAINER(undertable),5); + gtk_container_set_border_width(GTK_CONTAINER(basetable),5); + + } + + /* under compand: mode and knee */ + { + GtkWidget *envelopebox=gtk_hbox_new(0,0); + GtkWidget *rms_button=gtk_radio_button_new_with_label(NULL,"RMS"); + GtkWidget *peak_button= + gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(rms_button), + "peak"); + GtkWidget *knee_button=gtk_check_button_new_with_label("soft knee"); + + gtk_box_pack_start(GTK_BOX(envelopebox),underlabel,0,0,0); + gtk_box_pack_end(GTK_BOX(envelopebox),peak_button,0,0,5); + gtk_box_pack_end(GTK_BOX(envelopebox),rms_button,0,0,5); + gtk_box_pack_end(GTK_BOX(envelopebox),knee_button,0,0,5); + + g_signal_connect (G_OBJECT (knee_button), "clicked", + G_CALLBACK (under_knee), (gpointer)0); + g_signal_connect (G_OBJECT (rms_button), "clicked", + G_CALLBACK (under_mode), (gpointer)0); + g_signal_connect (G_OBJECT (peak_button), "clicked", + G_CALLBACK (under_mode), (gpointer)1); //To Hell I Go + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rms_button),1); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(knee_button),1); + gtk_table_attach(GTK_TABLE(undertable),envelopebox,0,4,0,1,GTK_FILL,0,0,0); + } + + /* under compand: ratio */ + { + + 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); + + multibar_callback(MULTIBAR(slider),under_compand_change,readout); + multibar_thumb_set(MULTIBAR(slider),1.,0); + + gtk_misc_set_alignment(GTK_MISC(label),1.,.5); + + gtk_table_set_row_spacing(GTK_TABLE(undertable),0,4); + gtk_table_attach(GTK_TABLE(undertable),label,0,1,1,2,GTK_FILL,0,2,0); + gtk_table_attach(GTK_TABLE(undertable),slider,1,3,1,2,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(undertable),readout,3,4,1,2,GTK_FILL,0,0,0); + + } + + /* under compand: timing */ + { + + GtkWidget *label=gtk_label_new("attack/decay:"); + GtkWidget *readout1=readout_new(" 100ms"); + GtkWidget *readout2=readout_new(" 100ms"); + GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2); + multireadout *r=calloc(1,sizeof(*r)); + + r->r0=readout1; + r->r1=readout2; + + multibar_callback(MULTIBAR(slider),under_timing_change,r); + multibar_thumb_set(MULTIBAR(slider),1,0); + multibar_thumb_set(MULTIBAR(slider),100,1); + + gtk_misc_set_alignment(GTK_MISC(label),1,.5); + + gtk_table_set_row_spacing(GTK_TABLE(undertable),2,4); + gtk_table_attach(GTK_TABLE(undertable),label,0,1,4,5,GTK_FILL,0,2,0); + gtk_table_attach(GTK_TABLE(undertable),slider,1,2,4,5,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(undertable),readout1,2,3,4,5,GTK_FILL,0,0,0); + gtk_table_attach(GTK_TABLE(undertable),readout2,3,4,4,5,GTK_FILL,0,0,0); + + } + + /* under compand: lookahead */ + { + + GtkWidget *label=gtk_label_new("lookahead:"); + GtkWidget *readout=readout_new("100%"); + GtkWidget *slider=multibar_slider_new(8,per_labels,per_levels,1); + + multibar_callback(MULTIBAR(slider),under_lookahead_change,readout); + multibar_thumb_set(MULTIBAR(slider),100.,0); + multibar_thumb_increment(MULTIBAR(slider),1.,10.); + + gtk_misc_set_alignment(GTK_MISC(label),1,.5); + + gtk_table_set_row_spacing(GTK_TABLE(undertable),3,4); + gtk_table_attach(GTK_TABLE(undertable),label,0,1,3,4,GTK_FILL,0,2,0); + gtk_table_attach(GTK_TABLE(undertable),slider,1,3,3,4,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(undertable),readout,3,4,3,4,GTK_FILL,0,0,0); + } + + /* over compand: mode and knee */ + { + GtkWidget *envelopebox=gtk_hbox_new(0,0); + GtkWidget *rms_button=gtk_radio_button_new_with_label(NULL,"RMS"); + GtkWidget *peak_button= + gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(rms_button), + "peak"); + GtkWidget *knee_button=gtk_check_button_new_with_label("soft knee"); + + gtk_box_pack_start(GTK_BOX(envelopebox),overlabel,0,0,0); + gtk_box_pack_end(GTK_BOX(envelopebox),peak_button,0,0,5); + gtk_box_pack_end(GTK_BOX(envelopebox),rms_button,0,0,5); + gtk_box_pack_end(GTK_BOX(envelopebox),knee_button,0,0,5); + + g_signal_connect (G_OBJECT (knee_button), "clicked", + G_CALLBACK (over_knee), (gpointer)0); + g_signal_connect (G_OBJECT (rms_button), "clicked", + G_CALLBACK (over_mode), (gpointer)0); + g_signal_connect (G_OBJECT (peak_button), "clicked", + G_CALLBACK (over_mode), (gpointer)1); //To Hell I Go + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rms_button),1); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(knee_button),1); + gtk_table_attach(GTK_TABLE(overtable),envelopebox,0,4,0,1,GTK_FILL,0,0,0); + } + + /* over compand: ratio */ + { + + 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); + + multibar_callback(MULTIBAR(slider),over_compand_change,readout); + multibar_thumb_set(MULTIBAR(slider),1.,0); + + gtk_misc_set_alignment(GTK_MISC(label),1.,.5); + + gtk_table_set_row_spacing(GTK_TABLE(overtable),0,4); + gtk_table_attach(GTK_TABLE(overtable),label,0,1,1,2,GTK_FILL,0,2,0); + gtk_table_attach(GTK_TABLE(overtable),slider,1,3,1,2,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(overtable),readout,3,4,1,2,GTK_FILL,0,0,0); + + } + + /* over compand: timing */ + { + + GtkWidget *label=gtk_label_new("attack/decay:"); + GtkWidget *readout1=readout_new(" 100ms"); + GtkWidget *readout2=readout_new(" 100ms"); + GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2); + + multireadout *r=calloc(1,sizeof(*r)); + r->r0=readout1; + r->r1=readout2; + + multibar_callback(MULTIBAR(slider),over_timing_change,r); + multibar_thumb_set(MULTIBAR(slider),1,0); + multibar_thumb_set(MULTIBAR(slider),100,1); + + gtk_misc_set_alignment(GTK_MISC(label),1,.5); + + gtk_table_set_row_spacing(GTK_TABLE(overtable),2,4); + gtk_table_attach(GTK_TABLE(overtable),label,0,1,5,6,GTK_FILL,0,2,0); + gtk_table_attach(GTK_TABLE(overtable),slider,1,2,5,6,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(overtable),readout1,2,3,5,6,GTK_FILL,0,0,0); + gtk_table_attach(GTK_TABLE(overtable),readout2,3,4,5,6,GTK_FILL,0,0,0); + + } + + /* over compand: lookahead */ + { + + GtkWidget *label=gtk_label_new("lookahead:"); + GtkWidget *readout=readout_new("100%"); + GtkWidget *slider=multibar_slider_new(8,per_labels,per_levels,1); + + multibar_callback(MULTIBAR(slider),over_lookahead_change,readout); + multibar_thumb_set(MULTIBAR(slider),100.,0); + multibar_thumb_increment(MULTIBAR(slider),1.,10.); + + gtk_misc_set_alignment(GTK_MISC(label),1,.5); + + gtk_table_set_row_spacing(GTK_TABLE(overtable),3,4); + gtk_table_attach(GTK_TABLE(overtable),label,0,1,3,4,GTK_FILL,0,2,0); + gtk_table_attach(GTK_TABLE(overtable),slider,1,3,3,4,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(overtable),readout,3,4,3,4,GTK_FILL,0,0,0); + } + + + /* base compand: mode */ + { + GtkWidget *envelopebox=gtk_hbox_new(0,0); + GtkWidget *rms_button=gtk_radio_button_new_with_label(NULL,"RMS"); + GtkWidget *peak_button= + gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(rms_button), + "peak"); + + gtk_box_pack_start(GTK_BOX(envelopebox),baselabel,0,0,0); + gtk_box_pack_end(GTK_BOX(envelopebox),peak_button,0,0,5); + gtk_box_pack_end(GTK_BOX(envelopebox),rms_button,0,0,5); + + g_signal_connect (G_OBJECT (rms_button), "clicked", + G_CALLBACK (base_mode), (gpointer)0); + g_signal_connect (G_OBJECT (peak_button), "clicked", + G_CALLBACK (base_mode), (gpointer)1); //To Hell I Go + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rms_button),1); + gtk_table_attach(GTK_TABLE(basetable),envelopebox,0,4,0,1,GTK_FILL,0,0,0); + } + + /* base compand: ratio */ + { + + 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); + + multibar_callback(MULTIBAR(slider),base_compand_change,readout); + multibar_thumb_set(MULTIBAR(slider),1.,0); + + gtk_misc_set_alignment(GTK_MISC(label),1.,.5); + + gtk_table_set_row_spacing(GTK_TABLE(basetable),0,4); + gtk_table_attach(GTK_TABLE(basetable),label,0,1,1,2,GTK_FILL,0,2,0); + gtk_table_attach(GTK_TABLE(basetable),slider,1,3,1,2,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(basetable),readout,3,4,1,2,GTK_FILL,0,0,0); + + } + + /* base compand: timing */ + { + + GtkWidget *label=gtk_label_new("attack/decay:"); + GtkWidget *readout1=readout_new(" 100ms"); + GtkWidget *readout2=readout_new(" 100ms"); + GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,2); + multireadout *r=calloc(1,sizeof(*r)); + + r->r0=readout1; + r->r1=readout2; + + multibar_callback(MULTIBAR(slider),base_timing_change,r); + multibar_thumb_set(MULTIBAR(slider),1,0); + multibar_thumb_set(MULTIBAR(slider),100,1); + + gtk_misc_set_alignment(GTK_MISC(label),1,.5); + + gtk_table_set_row_spacing(GTK_TABLE(basetable),2,4); + gtk_table_attach(GTK_TABLE(basetable),label,0,1,4,5,GTK_FILL,0,2,0); + gtk_table_attach(GTK_TABLE(basetable),slider,1,2,4,5,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,0); + gtk_table_attach(GTK_TABLE(basetable),readout1,2,3,4,5,GTK_FILL,0,0,0); + gtk_table_attach(GTK_TABLE(basetable),readout2,3,4,4,5,GTK_FILL,0,0,0); + + } + + /* threshold controls */ + + { + t_readout.r0=readout_new(" +0"); + t_readout.r1=readout_new(" +0"); + t_slider=multibar_new(14,labels,levels,2,HI_DECAY|LO_DECAY|LO_ATTACK); + + multibar_callback(MULTIBAR(t_slider),slider_change,&t_readout); + multibar_thumb_set(MULTIBAR(t_slider),-140.,0); + multibar_thumb_set(MULTIBAR(t_slider),0.,1); + multibar_thumb_bounds(MULTIBAR(t_slider),-140,0); + multibar_thumb_increment(MULTIBAR(t_slider),1.,10.); + + + gtk_table_attach(GTK_TABLE(slidertable),t_readout.r0,0,1,1,2, + 0,0,0,0); + gtk_table_attach(GTK_TABLE(slidertable),t_slider,1,2,1,2, + GTK_FILL|GTK_EXPAND,GTK_EXPAND,0,0); + gtk_table_attach(GTK_TABLE(slidertable),t_readout.r1,2,3,1,2, + 0,0,0,0); + } + + subpanel_show_all_but_toplevel(panel); + +} + +static float *peakfeed=0; +static float *rmsfeed=0; + +void singlepanel_feedback(int displayit){ + if(!peakfeed){ + peakfeed=malloc(sizeof(*peakfeed)*input_ch); + rmsfeed=malloc(sizeof(*rmsfeed)*input_ch); + } + + if(pull_singlecomp_feedback(peakfeed,rmsfeed)==1) + multibar_set(MULTIBAR(t_slider),rmsfeed,peakfeed, + input_ch,(displayit && singlecomp_visible)); +} + +void singlepanel_reset(void){ + multibar_reset(MULTIBAR(t_slider)); +} + + + diff --git a/singlepanel.h b/singlepanel.h new file mode 100644 index 0000000..c6bf4f6 --- /dev/null +++ b/singlepanel.h @@ -0,0 +1,30 @@ +/* + * + * 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. + * + * + */ + +extern void singlepanel_create(postfish_mainpanel *mp, + GtkWidget *windowbutton, + GtkWidget *activebutton); +extern void singlepanel_feedback(int displayit); +extern void singlepanel_reset(void); + + diff --git a/subband.c b/subband.c index d4e390b..6acf5b9 100644 --- a/subband.c +++ b/subband.c @@ -41,9 +41,7 @@ typedef struct subband_feedback{ } subband_feedback; static feedback_generic *new_subband_feedback(void){ - int i; subband_feedback *ret=calloc(1,sizeof(*ret)); - return (feedback_generic *)ret; } @@ -51,7 +49,7 @@ static feedback_generic *new_subband_feedback(void){ int pull_subband_feedback(subband_state *ff,float **peak,float **rms,int *b){ subband_feedback *f=(subband_feedback *)feedback_pull(&ff->feedpool); - int i,j; + int i; if(!f)return 0; @@ -130,12 +128,11 @@ int subband_load(subband_state *f,int bands,int qblocksize){ /* called only by initial setup */ int subband_load_freqs(subband_state *f,subband_window *w, - float *freq_list,int bands){ + const float *freq_list,int bands){ int i,j; memset(w,0,sizeof(*w)); - w->freq_list=freq_list; w->freq_bands=bands; /* supersample the spectrum */ @@ -233,7 +230,7 @@ int subband_reset(subband_state *f){ and padded FFTs with 75% overlap. */ static void subband_work(subband_state *f,time_linkage *in,subband_window *w){ - int i,j,k,l,m,off; + int i,j,k,l,off; float *workoff=f->fftwf_forward_in+f->qblocksize; for(i=0;ifftwf_forward_in+f->qblocksize; float scale=f->qblocksize*4.; for(i=0;i=0;j--){ /* add bands back together for output */ - if(out) + if(out){ if(j==bands-1){ memcpy(out[i],f->lap[j][i],input_size*(sizeof **out)); }else{ for(k=0;klap[j][i][k]; } + } /* shift bands for next lap */ /* optimization target: ringbuffer me! */ @@ -420,8 +417,8 @@ time_linkage *subband_read(time_linkage *in, subband_state *f, }else{ /* extrapolation mechanism; avoid harsh transients at edges */ for(i=0;idata[i],input_size, - f->cache[i],input_size); + preextrapolate_helper(in->data[i],input_size, + f->cache[i],input_size); if(in->samplessize) postextrapolate_helper(f->cache[i],input_size, @@ -526,7 +523,6 @@ time_linkage *subband_read(time_linkage *in, subband_state *f, /* finish up the state feedabck */ if(!bypass){ - int j; subband_feedback *ff= (subband_feedback *)feedback_new(&f->feedpool,new_subband_feedback); diff --git a/subband.h b/subband.h index 1dd78c9..56e8338 100644 --- a/subband.h +++ b/subband.h @@ -49,7 +49,6 @@ typedef struct { typedef struct { - float *freq_list; int freq_bands; float **ho_window; float *ho_area; @@ -60,7 +59,7 @@ typedef struct { extern int subband_load(subband_state *f,int bands, int qb); extern int subband_load_freqs(subband_state *f,subband_window *w, - float *freq_list,int bands); + const float *freq_list,int bands); extern time_linkage *subband_read(time_linkage *in, subband_state *f, subband_window *w, diff --git a/subpanel.c b/subpanel.c index f112427..536691d 100644 --- a/subpanel.c +++ b/subpanel.c @@ -116,7 +116,6 @@ subpanel_generic *subpanel_create(postfish_mainpanel *mp, char *prompt,char *shortcut){ subpanel_generic *panel=calloc(1,sizeof(*panel)); - GdkWindow *root=gdk_get_default_root_window(); GtkWidget *toplabelbox=gtk_event_box_new(); GtkWidget *toplabelframe=gtk_frame_new(NULL); diff --git a/suppress.c b/suppress.c new file mode 100644 index 0000000..2327c0d --- /dev/null +++ b/suppress.c @@ -0,0 +1,204 @@ +/* + * + * postfish + * + * Copyright (C) 2002-2004 Monty and Xiph.Org + * + * 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 "feedback.h" +#include +#include "subband.h" +#include "bessel.h" +#include "suppress.h" + +/* (since this one is kinda unique) The Reverberation Suppressor.... + + Reverberation in a measurably live environment displays + log amplitude decay with time (linear decay when plotted on a dB + scale). + + In its simplest form, the suppressor follows actual RMS amplitude + attacks but chooses a slower-than-actual decay, then expands + according to the dB distance between the slow and actual decay. + + Thus, the suppressor can be used to 'dry out' a very 'wet' + reverberative track. */ + +extern int input_size; +extern int input_rate; +extern int input_ch; + +typedef struct { + subband_state ss; + subband_window sw; + + iir_filter smooth; + iir_filter trigger; + iir_filter release; + + iir_state *iirS[suppress_freqs]; + iir_state *iirT[suppress_freqs]; + iir_state *iirR[suppress_freqs]; + +} suppress_state; + +sig_atomic_t suppress_visible; +sig_atomic_t suppress_active; + +suppress_settings sset; +static suppress_state sss; + +void suppress_reset(){ + int i,j; + + subband_reset(&sss.ss); + + for(i=0;icorner_freq && + attackp) + corner_freq=impulse_freq4(input_size*2-sss.ss.qblocksize*3); + + alpha=corner_freq/input_rate; + filter->g=mkbessel(alpha,order,filter->c); + filter->alpha=alpha; + filter->Hz=alpha*input_rate; + filter->ms=msec; +} + +int suppress_load(void){ + int i; + int qblocksize=input_size/16; + memset(&sss,0,sizeof(sss)); + + subband_load(&sss.ss,suppress_freqs,qblocksize); + subband_load_freqs(&sss.ss,&sss.sw,suppress_freq_list,suppress_freqs); + + for(i=0;ims)filter_set(smoothms,smooth,1,4); + if(triggerms!=trigger->ms)filter_set(triggerms,trigger,0,1); + if(releasems!=release->ms)filter_set(releasems,release,0,1); + + ahead=impulse_ahead4(smooth->alpha); + + for(i=0;i +#include +#include "readout.h" +#include "multibar.h" +#include "mainpanel.h" +#include "subpanel.h" +#include "feedback.h" +#include "suppress.h" +#include "suppresspanel.h" + +extern sig_atomic_t suppress_active; +extern sig_atomic_t suppress_visible; +extern int input_ch; +extern int input_size; +extern int input_rate; + +extern suppress_settings sset; + +typedef struct { + GtkWidget *cslider; + Readout *readoutc; + int number; +} tbar; + +Readout *readoutsmooth; +Readout *readouttrigger; +Readout *readoutrelease; + +static tbar bars[suppress_freqs+1]; + +static void compand_change(GtkWidget *w,gpointer in){ + char buffer[80]; + tbar *bar=(tbar *)in; + float val=multibar_get_value(MULTIBAR(w),0); + + if(val==1.){ + sprintf(buffer," off"); + }else + sprintf(buffer,"%4.2f",val); + + readout_set(bar->readoutc,buffer); + + sset.ratio[bar->number]=1000./val; + +} + +static void timing_change(GtkWidget *w,gpointer in){ + char buffer[80]; + float smooth=multibar_get_value(MULTIBAR(w),0); + float trigger=multibar_get_value(MULTIBAR(w),1); + float release=multibar_get_value(MULTIBAR(w),2); + + if(smooth<100){ + sprintf(buffer,"%4.1fms",smooth); + }else if (smooth<1000){ + sprintf(buffer,"%4.0fms",smooth); + }else if (smooth<10000){ + sprintf(buffer," %4.2fs",smooth/1000.); + }else{ + sprintf(buffer," %4.1fs",smooth/1000.); + } + readout_set(readoutsmooth,buffer); + + if(trigger<100){ + sprintf(buffer,"%4.1fms",trigger); + }else if (trigger<1000){ + sprintf(buffer,"%4.0fms",trigger); + }else if (trigger<10000){ + sprintf(buffer," %4.2fs",trigger/1000.); + }else{ + sprintf(buffer," %4.1fs",trigger/1000.); + } + readout_set(readouttrigger,buffer); + + if(release<100){ + sprintf(buffer,"%4.1fms",release); + }else if (release<1000){ + sprintf(buffer,"%4.0fms",release); + }else if (release<10000){ + sprintf(buffer," %4.2fs",release/1000.); + }else{ + sprintf(buffer," %4.1fs",release/1000.); + } + readout_set(readoutrelease,buffer); + + sset.smooth=rint(smooth*10.); + sset.trigger=rint(trigger*10.); + sset.release=rint(release*10.); +} + +static void suppress_link(GtkToggleButton *b,gpointer in){ + int mode=gtk_toggle_button_get_active(b); + sset.linkp=mode; +} + +void suppresspanel_create(postfish_mainpanel *mp, + GtkWidget *windowbutton, + GtkWidget *activebutton){ + int i; + float compand_levels[5]={1,1.5,2,3,5}; + char *compand_labels[4]={"1.5","2","3","5"}; + + float timing_levels[5]={1, 10, 100, 1000, 10000}; + char *timing_labels[4]={"10ms"," 100ms","1s","10s"}; + + subpanel_generic *panel=subpanel_create(mp,windowbutton,activebutton, + &suppress_active, + &suppress_visible, + "De_verberation filter"," [v] "); + + + GtkWidget *table=gtk_table_new(suppress_freqs+4,5,0); + GtkWidget *timinglabel=gtk_label_new("suppressor filter timing"); + GtkWidget *releaselabel=gtk_label_new("release"); + GtkWidget *smoothlabel=gtk_label_new("smooth"); + GtkWidget *triggerlabel=gtk_label_new("trigger"); + GtkWidget *compandlabel=gtk_label_new("suppression depth"); + + GtkWidget *linkbutton= + gtk_check_button_new_with_mnemonic("_link channels into single image"); + GtkWidget *linkbox=gtk_hbox_new(0,0); + + gtk_container_add(GTK_CONTAINER(panel->subpanel_box),table); + + gtk_box_pack_end(GTK_BOX(linkbox),linkbutton,0,0,0); + + gtk_table_attach(GTK_TABLE(table),timinglabel,0,2,0,1, + GTK_EXPAND|GTK_FILL, + GTK_EXPAND|GTK_FILL, + 0,5); + gtk_table_attach(GTK_TABLE(table),smoothlabel,2,3,0,1, + GTK_EXPAND|GTK_FILL, + GTK_EXPAND|GTK_FILL, + 0,0); + gtk_table_attach(GTK_TABLE(table),triggerlabel,3,4,0,1, + GTK_EXPAND|GTK_FILL, + GTK_EXPAND|GTK_FILL, + 0,0); + gtk_table_attach(GTK_TABLE(table),releaselabel,4,5,0,1, + GTK_EXPAND|GTK_FILL, + GTK_EXPAND|GTK_FILL, + 0,0); + gtk_table_attach(GTK_TABLE(table),compandlabel,0,4,2,3, + GTK_EXPAND|GTK_FILL, + GTK_EXPAND|GTK_FILL, + 0,5); + if(input_ch>1) + gtk_table_attach(GTK_TABLE(table),linkbox,0,5,suppress_freqs+3, + suppress_freqs+4,GTK_FILL|GTK_EXPAND,0,0,10); + + gtk_table_set_row_spacing(GTK_TABLE(table),1,5); + + gtk_misc_set_alignment(GTK_MISC(timinglabel),0,1.); + gtk_widget_set_name(timinglabel,"framelabel"); + gtk_misc_set_alignment(GTK_MISC(smoothlabel),.5,1.); + gtk_widget_set_name(smoothlabel,"scalemarker"); + gtk_misc_set_alignment(GTK_MISC(triggerlabel),.5,1.); + gtk_widget_set_name(triggerlabel,"scalemarker"); + gtk_misc_set_alignment(GTK_MISC(releaselabel),.5,1.); + gtk_widget_set_name(releaselabel,"scalemarker"); + gtk_misc_set_alignment(GTK_MISC(compandlabel),0,1.); + gtk_widget_set_name(compandlabel,"framelabel"); + + g_signal_connect (G_OBJECT (linkbutton), "clicked", + G_CALLBACK (suppress_link), 0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linkbutton),1); + + /* timing controls */ + { + GtkWidget *slider=multibar_slider_new(4,timing_labels,timing_levels,3); + + readoutsmooth=READOUT(readout_new("10.0ms")); + readouttrigger=READOUT(readout_new("10.0ms")); + readoutrelease=READOUT(readout_new("10.0ms")); + + multibar_callback(MULTIBAR(slider),timing_change,0); + + multibar_thumb_set(MULTIBAR(slider),20,0); + multibar_thumb_set(MULTIBAR(slider),100,1); + multibar_thumb_set(MULTIBAR(slider),1000,2); + + gtk_table_attach(GTK_TABLE(table),slider,1,2,1,2, + GTK_FILL|GTK_EXPAND,GTK_EXPAND,5,0); + gtk_table_attach(GTK_TABLE(table),GTK_WIDGET(readoutsmooth),2,3,1,2, + 0,0,0,0); + gtk_table_attach(GTK_TABLE(table),GTK_WIDGET(readouttrigger),3,4,1,2, + 0,0,0,0); + gtk_table_attach(GTK_TABLE(table),GTK_WIDGET(readoutrelease),4,5,1,2, + 0,0,0,0); + } + + /* threshold controls */ + + for(i=0;i