[xiph-cvs] r6506 - trunk/postfish
xiphmont at xiph.org
xiphmont at xiph.org
Tue Apr 13 21:50:39 PDT 2004
Author: xiphmont
Date: 2004-04-14 00:50:38 -0400 (Wed, 14 Apr 2004)
New Revision: 6506
Added:
trunk/postfish/limit.c
trunk/postfish/limit.h
trunk/postfish/limitpanel.c
trunk/postfish/limitpanel.h
trunk/postfish/rexperiment.c
trunk/postfish/singlecomp.c
trunk/postfish/singlecomp.h
trunk/postfish/singlepanel.c
trunk/postfish/singlepanel.h
trunk/postfish/suppress.c
trunk/postfish/suppress.h
trunk/postfish/suppresspanel.c
trunk/postfish/suppresspanel.h
Modified:
trunk/postfish/Makefile
trunk/postfish/bessel.c
trunk/postfish/bessel.h
trunk/postfish/compandpanel.c
trunk/postfish/compandpanel.h
trunk/postfish/declip.c
trunk/postfish/eq.c
trunk/postfish/eq.h
trunk/postfish/freq.c
trunk/postfish/freq.h
trunk/postfish/input.c
trunk/postfish/main.c
trunk/postfish/mainpanel.c
trunk/postfish/mainpanel.h
trunk/postfish/multibar.c
trunk/postfish/multicompand.c
trunk/postfish/multicompand.h
trunk/postfish/output.c
trunk/postfish/postfish-gtkrc
trunk/postfish/postfish.h
trunk/postfish/readout.c
trunk/postfish/readout.h
trunk/postfish/reconstruct.c
trunk/postfish/subband.c
trunk/postfish/subband.h
trunk/postfish/subpanel.c
trunk/postfish/version.h
trunk/postfish/windowbutton.c
Log:
Must... get... changes... under... source... control...
Subversion is not scary, and there are no monsters under my bed.
Monty
<p><p>Modified: trunk/postfish/Makefile
===================================================================
--- trunk/postfish/Makefile 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/Makefile 2004-04-14 04:50:38 UTC (rev 6506)
@@ -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 @@
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
Modified: trunk/postfish/bessel.c
===================================================================
--- trunk/postfish/bessel.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/bessel.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -23,20 +23,52 @@
/* code derived directly from mkfilter by the late A.J. Fisher,
University of York <fisher at minster.york.ac.uk> 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"
+#include "bessel.h"
-#define TWOPI (2.0 * M_PIl)
-#define EPS 1e-10
-#define MAXORDER 2
-#define MAXPZ 4
-
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 @@
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 @@
}
}
-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 @@
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 @@
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;i<order;i++)
+ ycoeff[order-i-1] = -(botcoeffs[i].re / botcoeffs[zplane.numpoles].re);
return hypot(dc_gain.re,dc_gain.im);
}
+/* assymetrical attack/decay filter computation */
+/* this one is designed for fast attack, slow decay */
+void compute_iir_fast_attack2(float *x, int n, iir_state *is,
+ iir_filter *attack, iir_filter *decay){
+ double a_c0=attack->c[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){
+
+ if(state==0){
+ /* attack case */
+ while(i<n){
+ double ya= (x[i]+x0*2.+x1)/a_g + y0*a_c0+y1*a_c1;
+
+ if(ya<y0){
+ state=1;
+ break;
+ }
+ x1=x0;x0=x[i];
+ y1=y0;x[i]=y0=ya;
+ i++;
+ }
+ }
+ if(state==1){
+ /* decay case */
+ if(y1<y0){
+ /* decay fixup needed because we're in discontinuous time */
+ y1=y0;
+ }
+
+ while(1){
+ double yd = (x[i]+x0*2.+x1)/d_g + y0*d_c0+y1*d_c1;
+
+ x1=x0;x0=x[i];
+ y1=y0;x[i]=y0=yd;
+ i++;
+
+ if(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(i<n){
+ double yd;
+
+ yd = y0*d_c0;
+
+ if(x[i]>yd)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(i<n){
+ double yd;
+ if(y1<y0)y1=y0; // slope fixup
+
+ yd = y0*d_c0+y1*d_c1;
+
+
+ if(x[i]>yd)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(i<n){
+ double yd;
+ if(y1<y0)y1=y0; // slope fixup
+ if(y2<y1)y2=y1; // slope fixup
+
+
+ yd = y0*d_c0+y1*d_c1+y2*d_c2;
+
+
+ if(x[i]>yd)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(i<n){
+ double yd;
+ if(y1<y0)y1=y0; // slope fixup
+ if(y2<y1)y2=y1; // slope fixup
+ if(y3<y2)y3=y2; // slope fixup
+
+
+ yd = y0*d_c0+y1*d_c1+y2*d_c2+y3*d_c3;
+
+ if(x[i]>yd)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(i<n){
+ double yd= (x[i]+x0*2.+x1)/g + y0*c0+y1*c1;
+ 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_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(i<n){
+ double yd= (x[i]+(x0+x1)*3.+x2)/g + y0*c0+y1*c1+y2*c2;
+ 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_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(i<n){
+ double yd= (x[i]+(x0+x2)*4.+x1*6.+x3)/g +
+ y0*c0+y1*c1+y2*c2+y3*c3;
+ 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;
+
+}
+
+
+/* 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);
+ }
+}
+
+
Modified: trunk/postfish/bessel.h
===================================================================
--- trunk/postfish/bessel.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/bessel.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -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);
+
Modified: trunk/postfish/compandpanel.c
===================================================================
--- trunk/postfish/compandpanel.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/compandpanel.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -59,12 +59,13 @@
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,198 +77,74 @@
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);
+ compand_change(w,(Readout *)in,&c.over_ratio);
+}
- 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);
-
- 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);
+ timing_display(w,r->r0,attack);
+ timing_display(w,r->r1,decay);
- 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);
-
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);
+ timing_display(w,r->r0,attack);
+ timing_display(w,r->r1,decay);
- 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);
+ multicompand_base_attack_set(attack);
+ multicompand_base_decay_set(decay);
- multicompand_suppress_attack_set(attack);
- multicompand_suppress_decay_set(decay);
- multicompand_suppress_release_set(release);
-
}
static void under_lookahead_change(GtkWidget *w,gpointer in){
@@ -275,7 +152,7 @@
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 @@
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 @@
/* compute the current average */
for(i=0;i<multicomp_freqs[bank_active];i++){
- oav+=rint(bc[bank_active].static_o[i]/10.);
- uav+=rint(bc[bank_active].static_u[i]/10.);
+ oav+=rint(bc[bank_active].static_o[i]);
+ uav+=rint(bc[bank_active].static_u[i]);
}
oav=rint(oav/multicomp_freqs[bank_active]);
uav=rint(uav/multicomp_freqs[bank_active]);
@@ -326,7 +201,7 @@
/* update u average (might have pushed it) */
uav=0;
for(i=0;i<multicomp_freqs[bank_active];i++)
- uav+=rint(bc[bank_active].static_u[i]/10.);
+ uav+=rint(bc[bank_active].static_u[i]);
uav=rint(uav/multicomp_freqs[bank_active]);
multibar_thumb_set(MULTIBAR(bars[multicomp_freqs_max].slider),uav,0);
}else{
@@ -338,7 +213,7 @@
/* update o average (might have pushed it) */
oav=0;
for(i=0;i<multicomp_freqs[bank_active];i++)
- oav+=rint(bc[bank_active].static_o[i]/10.);
+ oav+=rint(bc[bank_active].static_o[i]);
oav=rint(oav/multicomp_freqs[bank_active]);
multibar_thumb_set(MULTIBAR(bars[multicomp_freqs_max].slider),oav,1);
}
@@ -349,31 +224,135 @@
static void slider_change(GtkWidget *w,gpointer in){
char buffer[80];
cbar *b=(cbar *)in;
- float o,u;
+ int o,u;
int i;
u=multibar_get_value(MULTIBAR(b->slider),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 @@
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 @@
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 @@
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 @@
/* compute the current average */
for(i=0;i<multicomp_freqs[bank_active];i++){
- oav+=rint(bc[bank_active].static_o[i]/10.);
- uav+=rint(bc[bank_active].static_u[i]/10.);
+ oav+=rint(bc[bank_active].static_o[i]);
+ uav+=rint(bc[bank_active].static_u[i]);
}
oav=rint(oav/multicomp_freqs[bank_active]);
uav=rint(uav/multicomp_freqs[bank_active]);
@@ -461,8 +445,8 @@
inactive_updatep=0;
{
- float o=bc[bank_active].static_o[i]/10.;
- float u=bc[bank_active].static_u[i]/10.;
+ float o=bc[bank_active].static_o[i];
+ float u=bc[bank_active].static_u[i];
multibar_thumb_set(MULTIBAR(bars[i].slider),u,0);
multibar_thumb_set(MULTIBAR(bars[i].slider),o,1);
@@ -483,11 +467,6 @@
}
}
-static void link_toggled(GtkToggleButton *b,gpointer in){
- int active=gtk_toggle_button_get_active(b);
- c.link_mode=active;
-}
-
static void over_mode(GtkButton *b,gpointer in){
int mode=(int)in;
c.over_mode=mode;
@@ -498,42 +477,36 @@
c.under_mode=mode;
}
-static void under_knee(GtkButton *b,gpointer in){
+static void base_mode(GtkButton *b,gpointer in){
int mode=(int)in;
+ c.base_mode=mode;
+}
+
+static void under_knee(GtkToggleButton *b,gpointer in){
+ int mode=gtk_toggle_button_get_active(b);
c.under_softknee=mode;
}
-static void over_knee(GtkButton *b,gpointer in){
- int mode=(int)in;
+static void over_knee(GtkToggleButton *b,gpointer in){
+ int mode=gtk_toggle_button_get_active(b);
c.over_softknee=mode;
}
-static void suppress_mode(GtkButton *b,gpointer in){
- int mode=(int)in;
- c.suppress_mode=mode;
-}
-
void compandpanel_create(postfish_mainpanel *mp,
GtkWidget *windowbutton,
GtkWidget *activebutton){
- int i,j;
+ int i;
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,.667,1,1.5,2,4,10};
+ 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 compand_levels_low[5]={1,1.2,1.5,2,3};
- char *compand_labels_low[4]={"1:1.2","1:1.5","1:2","1:3"};
-
float timing_levels[6]={.5,1,10,100,1000,10000};
char *timing_labels[5]={"1ms","10ms","100ms","1s","10s"};
- float limit_levels[9]={0,40,60,80,100,110,120,130,135};
- char *limit_labels[8]={"100dB","80dB","60dB","40dB","30dB","20dB","10dB","5dB"};
-
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%"};
@@ -549,23 +522,23 @@
GtkWidget *staticbox=gtk_vbox_new(0,0);
GtkWidget *slidertable=gtk_table_new(multicomp_freqs_max+2,4,0);
- GtkWidget *overlabel=gtk_label_new("Over threshold compand");
+ 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 *underlabel=gtk_label_new("Under threshold compand ");
GtkWidget *undertable=gtk_table_new(5,4,0);
- GtkWidget *suppressframe=gtk_frame_new(" Reverb suppression ");
- GtkWidget *suppresstable=gtk_table_new(4,5,0);
+ GtkWidget *baselabel=gtk_label_new("Global compand ");
+ GtkWidget *basetable=gtk_table_new(3,4,0);
- GtkWidget *link_box=gtk_hbox_new(0,0);
- GtkWidget *link_check=gtk_check_button_new_with_mnemonic("_link channel envelopes");
-
gtk_widget_set_name(overlabel,"framelabel");
gtk_widget_set_name(underlabel,"framelabel");
- gtk_container_set_border_width(GTK_CONTAINER(suppresstable),4);
+ 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);
+
{
@@ -586,7 +559,7 @@
gtk_widget_set_name(label3,"scalemarker");
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(octave_c),1);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(octave_b),1);
g_signal_connect (G_OBJECT (octave_a), "clicked",
G_CALLBACK (static_octave), (gpointer)0);
@@ -613,30 +586,28 @@
}
- if(input_ch>1)
- 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_end(GTK_BOX(staticbox),suppressframe,0,0,0);
- gtk_container_add(GTK_CONTAINER(suppressframe),suppresstable);
+ 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_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);
+ 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);
@@ -646,7 +617,7 @@
"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 @@
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 @@
}
- /* 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 @@
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 @@
"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 @@
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 @@
}
- /* 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 @@
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 @@
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 @@
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 @@
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 @@
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_reset(void){
- int i,j;
+ int i;
for(i=0;i<multicomp_freqs_max;i++)
multibar_reset(MULTIBAR(bars[i].slider));
}
Modified: trunk/postfish/compandpanel.h
===================================================================
--- trunk/postfish/compandpanel.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/compandpanel.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -21,12 +21,16 @@
*
*/
+extern void suppresspanel_create(postfish_mainpanel *mp,
+ GtkWidget *windowbutton,
+ GtkWidget *activebutton);
+
extern void compandpanel_create(postfish_mainpanel *mp,
GtkWidget *windowbutton,
GtkWidget *activebutton);
extern void compandpanel_feedback(int displayit);
extern void compandpanel_reset(void);
-extern void compandpanel_set_play(int playp);
+
Modified: trunk/postfish/declip.c
===================================================================
--- trunk/postfish/declip.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/declip.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -80,7 +80,7 @@
}
static void push_declip_feedback(int *clip,float *peak,int total){
- int i,n=input_ch;
+ int n=input_ch;
declip_feedback *f=(declip_feedback *)
feedback_new(&feedpool,new_declip_feedback);
memcpy(f->clipcount,clip,n*sizeof(*clip));
@@ -91,7 +91,6 @@
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 @@
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 @@
}
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 @@
for(i=0;i<n/2;i++){
- float bark=toBark(44100.*i/n);
int hi=widthlookup[i]>>16;
int lo=widthlookup[i]&(0xffff);
float del=hypot(f[(i<<1)+1],f[i<<1])/(lo-hi);
@@ -317,7 +317,6 @@
switch(fillstate){
case 0: /* prime the lapping and cache */
for(i=0;i<input_ch;i++){
- int j;
float *temp=in->data[i];
total=0;
memset(work+blocksize/2,0,sizeof(*work)*blocksize/2);
Modified: trunk/postfish/eq.c
===================================================================
--- trunk/postfish/eq.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/eq.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -61,7 +61,7 @@
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){
Modified: trunk/postfish/eq.h
===================================================================
--- trunk/postfish/eq.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/eq.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -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 @@
"8k","10k","12.5k","16k","20k"
};
-
extern int pull_eq_feedback(float **peak,float **rms);
extern int eq_load(void);
extern int eq_reset();
Modified: trunk/postfish/freq.c
===================================================================
--- trunk/postfish/freq.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/freq.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -41,7 +41,6 @@
} 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 @@
}
/* 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 @@
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];
Modified: trunk/postfish/freq.h
===================================================================
--- trunk/postfish/freq.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/freq.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -34,7 +34,6 @@
int qblocksize;
int bands;
- float *frequencies;
float **ho_window;
float *ho_area;
@@ -51,7 +50,7 @@
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,
Modified: trunk/postfish/input.c
===================================================================
--- trunk/postfish/input.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/input.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -401,7 +401,7 @@
}
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 @@
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 @@
k=0;
for(i=0;i<out.samples;i++){
float mean=0.;
- float div=0.;
float divrms=0.;
for(j=0;j<out.channels;j++){
Added: trunk/postfish/limit.c
===================================================================
--- trunk/postfish/limit.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/limit.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -0,0 +1,244 @@
+/*
+ *
+ * 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 "limit.h"
+
+extern int input_size;
+extern int input_rate;
+extern int input_ch;
+
+sig_atomic_t limit_active;
+sig_atomic_t limit_visible;
+
+typedef struct{
+ time_linkage out;
+ feedback_generic_pool feedpool;
+
+ iir_state *iir;
+ iir_filter decay;
+
+} limit_state;
+
+limit_settings limitset;
+limit_state limitstate;
+
+static void _analysis(char *base,int i,float *v,int n,int dB,int offset){
+ int j;
+ FILE *of;
+ char buffer[80];
+
+ sprintf(buffer,"%s_%d.m",base,i);
+ of=fopen(buffer,"a");
+
+ if(!of)perror("failed to open data dump file");
+
+ for(j=0;j<n;j++){
+ fprintf(of,"%f ",(float)j+offset);
+ if(dB)
+ fprintf(of,"%f\n",todB(v[j]));
+ else
+ fprintf(of,"%f\n",(v[j]));
+ }
+ fprintf(of,"\n");
+ fclose(of);
+}
+
+static int offset=0;
+
+/* feedback! */
+typedef struct limit_feedback{
+ feedback_generic parent_class;
+ float *peak;
+ float *att;
+} limit_feedback;
+
+static feedback_generic *new_limit_feedback(void){
+ limit_feedback *ret=calloc(1,sizeof(*ret));
+ return (feedback_generic *)ret;
+}
+
+
+int pull_limit_feedback(float *peak,float *att){
+ limit_feedback *f=(limit_feedback *)feedback_pull(&limitstate.feedpool);
+
+ if(!f)return 0;
+
+ if(peak)
+ memcpy(peak,f->peak,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;i<input_ch;i++)
+ limitstate.out.data[i]=malloc(input_size*sizeof(**limitstate.out.data));
+
+ return(0);
+}
+
+static void filter_set(float msec,
+ iir_filter *filter){
+ float alpha;
+ float corner_freq= 500./msec;
+
+ 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 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;i<input_ch;i++){
+ localpeak=0.;
+ localatt=0.;
+
+ if(!bypass){
+ float *inx=in->data[i];
+ float *x=limitstate.out.data[i];
+
+ if(active){
+
+ /* 'knee' the actual samples, compute attenuation depth */
+ for(k=0;k<in->samples;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;k<in->samples;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;k<in->samples;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<limitstate.out.channels;i++)
+ memset(limitstate.out.data[i]+limitstate.out.samples,0,sizeof(**limitstate.out.data)*tozero);
+ }
+
+ offset+=input_size;
+
+ return &limitstate.out;
+}
+
Added: trunk/postfish/limit.h
===================================================================
--- trunk/postfish/limit.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/limit.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -0,0 +1,33 @@
+/*
+ *
+ * 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.
+ *
+ *
+ */
+
+typedef struct{
+ sig_atomic_t thresh;
+ sig_atomic_t depth;
+ sig_atomic_t decay;
+} limit_settings;
+
+extern int pull_limit_feedback(float *peak,float *att);
+extern int limit_load(void);
+extern int limit_reset(void);
+extern time_linkage *limit_read(time_linkage *in);
Added: trunk/postfish/limitpanel.c
===================================================================
--- trunk/postfish/limitpanel.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/limitpanel.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -0,0 +1,190 @@
+/*
+ *
+ * postfish
+ *
+ * Copyright (C) 2002-2004 Monty
+ *
+ * Postfish is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Postfish is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Postfish; see the file COPYING. If not, write to the
+ * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ */
+
+#include "postfish.h"
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#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<input_ch;i++)zerofeed[i]=-150.;
+ }
+
+ if(pull_limit_feedback(peakfeed,attfeed)==1){
+ multibar_set(MULTIBAR(t_slider),zerofeed,peakfeed,
+ input_ch,(displayit && limit_visible));
+ multibar_set(MULTIBAR(a_slider),zerofeed,attfeed,
+ input_ch,(displayit && limit_visible));
+ }
+}
+
+void limitpanel_reset(void){
+ multibar_reset(MULTIBAR(t_slider));
+ multibar_reset(MULTIBAR(a_slider));
+}
+
+
+
Added: trunk/postfish/limitpanel.h
===================================================================
--- trunk/postfish/limitpanel.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/limitpanel.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -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 limitpanel_create(postfish_mainpanel *mp,
+ GtkWidget *windowbutton,
+ GtkWidget *activebutton);
+extern void limitpanel_feedback(int displayit);
+extern void limitpanel_reset(void);
+
+
Modified: trunk/postfish/main.c
===================================================================
--- trunk/postfish/main.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/main.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -31,6 +31,12 @@
#include <fftw3.h>
#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 @@
/* 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)){
Modified: trunk/postfish/mainpanel.c
===================================================================
--- trunk/postfish/mainpanel.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/mainpanel.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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(cursora<cursorb){
input_Acursor_set(cursora);
@@ -148,6 +207,26 @@
}
+static void action_seta(GtkWidget *widget,postfish_mainpanel *p){
+ const char *time=gtk_entry_get_text(GTK_ENTRY(p->entry_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,64 +238,9 @@
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);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->cue_act[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);
- }
-}
-
static void shutdown(void){
gtk_main_quit ();
}
@@ -333,105 +357,125 @@
/* 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);
+ }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;
- 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]);
- 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,12 +622,24 @@
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);
gtk_misc_set_alignment(GTK_MISC(show),1,.5);
@@ -609,8 +665,8 @@
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 @@
/* 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 @@
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 @@
g_signal_connect_after(G_OBJECT (panel->entry_b), "grab_focus",
G_CALLBACK (timeevent_unselect), NULL);
+ g_signal_connect (G_OBJECT (panel->cue_act[0]), "clicked",
+ G_CALLBACK (action_entrya), panel);
+ 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_entrya), panel);
+ G_CALLBACK (action_seta), panel);
g_signal_connect (G_OBJECT (panel->cue_set[1]), "clicked",
- G_CALLBACK (action_entryb), panel);
+ 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 @@
gtk_box_pack_start(GTK_BOX(cuebox),framea,1,1,3);
+ 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->entry_a,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_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->entry_b,0,0,0);
gtk_box_pack_start(GTK_BOX(cuebox),panel->cue_reset[1],0,0,0);
}
@@ -815,12 +880,13 @@
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 @@
}
-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 @@
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 @@
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 @@
clippanel_feedback(current_p);
eqpanel_feedback(current_p);
compandpanel_feedback(current_p);
+ singlepanel_feedback(current_p);
+ limitpanel_feedback(current_p);
}
}
@@ -900,7 +982,6 @@
GIOCondition condition,
gpointer data){
postfish_mainpanel *panel=data;
- int i;
char buf[1];
read(eventpipe[0],buf,1);
@@ -967,7 +1048,6 @@
/* 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);
Modified: trunk/postfish/mainpanel.h
===================================================================
--- trunk/postfish/mainpanel.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/mainpanel.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -29,6 +29,8 @@
#include "clippanel.h"
#include "eqpanel.h"
#include "compandpanel.h"
+#include "singlepanel.h"
+#include "limitpanel.h"
struct postfish_mainpanel{
GtkWidget *topframe;
@@ -60,6 +62,7 @@
GtkWidget *buttonactive[7];
+ GtkWidget *cue_act[2];
GtkWidget *cue_set[2];
GtkWidget *cue_reset[2];
@@ -67,7 +70,12 @@
GtkWidget *inbar;
GtkWidget *outbar;
+ GtkWidget *inreadout;
+ GtkWidget *outreadout;
+ float inpeak;
+ float outpeak;
+
GtkWidget *channelshow[10]; /* support only up to 8 + mid/side */
GtkWidget *cue;
Modified: trunk/postfish/multibar.c
===================================================================
--- trunk/postfish/multibar.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/multibar.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -21,9 +21,9 @@
*
*/
-#include <stdio.h>
#include <stdlib.h>
#include <math.h>
+#include <string.h>
#include <gdk/gdkkeysyms.h>
#include "multibar.h"
@@ -516,9 +516,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
m->prev_thumbfocus=m->thumbfocus;
m->thumbfocus=-1;
draw_and_expose(widget);
+ return TRUE;
}
static gboolean refocus(GtkWidget *widget,
@@ -1008,6 +1007,7 @@
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_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;
Modified: trunk/postfish/multicompand.c
===================================================================
--- trunk/postfish/multicompand.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/multicompand.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -28,106 +28,16 @@
#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;j<n;j++){
- if(bark){
- float b=toBark((4000.f*j/n)+.25);
- fprintf(of,"%f ",b);
- }else
- fprintf(of,"%f ",(float)j);
-
- if(dB){
- float val=todB(hypot(v[j],v[j+1]));
- if(val<-140)val=-140;
- fprintf(of,"%f\n",val);
- j++;
-
- }else{
- fprintf(of,"%f\n",v[j]);
- }
- }
- fclose(of);
-}
-
-static void _analysis_append(char *base,int basemod,float *v,int n,int off){
- int j;
- FILE *of;
- char buffer[80];
-
- sprintf(buffer,"%s_%d.m",base,basemod);
- of=fopen(buffer,"a");
-
- if(!of)perror("failed to open data dump file");
-
- for(j=0;j<n;j++){
- fprintf(of,"%f ",(float)j+off);
- fprintf(of,"%f\n",v[j]);
- }
- fprintf(of,"\n");
- fclose(of);
-}
-
extern int input_size;
extern int input_rate;
extern int input_ch;
-/* lookup table this soon */
-static float soft_knee(float x){
- return atanf(-x*.2)*x/3.14159-x*.5-(5./M_PI);
-}
-
-static float hard_knee(float x){
- return (x>0?-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;
+ int loc;
+ float val;
+} peak_state;
-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;
-
-typedef struct {
subband_state ss;
subband_window sw[multicomp_banks];
@@ -137,23 +47,20 @@
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 @@
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;i<multicomp_freqs_max;i++)
for(j=0;j<input_ch;j++){
+ memset(&ms.over_peak[i][j],0,sizeof(peak_state));
+ memset(&ms.under_peak[i][j],0,sizeof(peak_state));
+ memset(&ms.base_peak[i][j],0,sizeof(peak_state));
memset(&ms.over_iir[i][j],0,sizeof(iir_state));
memset(&ms.under_iir[i][j],0,sizeof(iir_state));
- memset(&ms.suppress_iirA[i][j],0,sizeof(iir_state));
- memset(&ms.suppress_iirB[i][j],0,sizeof(iir_state));
+ memset(&ms.base_iir[i][j],0,sizeof(iir_state));
}
}
int multicompand_load(void){
- int h,i,j;
+ int h,i;
int qblocksize=input_size/8;
memset(&ms,0,sizeof(ms));
@@ -195,10 +103,12 @@
multicomp_freqs[h]);
for(i=0;i<multicomp_freqs_max;i++){
+ ms.over_peak[i]=calloc(input_ch,sizeof(peak_state));
+ ms.under_peak[i]=calloc(input_ch,sizeof(peak_state));
+ ms.base_peak[i]=calloc(input_ch,sizeof(peak_state));
ms.over_iir[i]=calloc(input_ch,sizeof(iir_state));
ms.under_iir[i]=calloc(input_ch,sizeof(iir_state));
- ms.suppress_iirA[i]=calloc(input_ch,sizeof(iir_state));
- ms.suppress_iirB[i]=calloc(input_ch,sizeof(iir_state));
+ ms.base_iir[i]=calloc(input_ch,sizeof(iir_state));
}
ms.active_bank=0;
@@ -206,499 +116,295 @@
return 0;
}
-int multicompand_filterbank_set(float msec,iir_filter filterbank[multicomp_banks][multicomp_freqs_max]){
+static void multicompand_filter_set(float msec,
+ iir_filter *filter,
+ int attackp){
+ float alpha;
+ float corner_freq= 500./msec;
+
+ /* 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)*1.01>corner_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;j<multicomp_banks;j++){
- float *freqs=multicomp_freq_list[j];
int bands=multicomp_freqs[j];
iir_filter *filters=filterbank[j];
- for(i=0;i<bands;i++){
- float alpha;
- float corner_freq=500./msec;
-
- /* limit the filter corner frequency to prevent fast attacks
- from destroying low frequencies */
- if(corner_freq>freqs[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)*.95<freqs[i])
- corner_freq=step_freq(input_size*2-ms.ss.qblocksize*3);
-
- alpha=corner_freq/input_rate*2.;
- filters[i].g=mkbessel_2(alpha,&filters[i].c0,&filters[i].c1);
- filters[i].alpha=alpha;
- }
+ for(i=0;i<bands;i++)
+ multicompand_filter_set(msec,filters+i,attackp);
}
+ return 0;
}
-
int multicompand_over_attack_set(float msec){
- multicompand_filterbank_set(msec,ms.over_attack);
+ return multicompand_filterbank_set(msec,ms.over_attack,1);
}
int multicompand_over_decay_set(float msec){
- multicompand_filterbank_set(msec,ms.over_decay);
+ return multicompand_filterbank_set(msec,ms.over_decay,0);
}
int multicompand_under_attack_set(float msec){
- multicompand_filterbank_set(msec,ms.under_attack);
+ return multicompand_filterbank_set(msec,ms.under_attack,1);
}
int multicompand_under_decay_set(float msec){
- multicompand_filterbank_set(msec,ms.under_decay);
+ return multicompand_filterbank_set(msec,ms.under_decay,0);
}
-int multicompand_suppress_attack_set(float msec){
- multicompand_filterbank_set(msec,ms.suppress_attack);
+int multicompand_base_attack_set(float msec){
+ return multicompand_filterbank_set(msec,ms.base_attack,1);
}
-int multicompand_suppress_decay_set(float msec){
- multicompand_filterbank_set(msec,ms.suppress_decay);
+int multicompand_base_decay_set(float msec){
+ return multicompand_filterbank_set(msec,ms.base_decay,0);
}
-int multicompand_suppress_release_set(float msec){
- multicompand_filterbank_set(msec,ms.suppress_release);
+static void prepare_rms(float *rms, float *xx, int n, int ahead){
+ int i;
+ float *x=xx+ahead;
+ for(i=0;i<n;i++)
+ rms[i]+=x[i]*x[i];
}
-/* assymetrical attack/decay filter; the z-space fixup is designed for
- the case where decay is the same or slower than attack */
-/* The Bessel filter followers are inlined here as later to avoid some
- really shockingly bad code generation by gcc on x86 */
-static void compute_iir(float *y, float *x, int n,
- iir_state *is, iir_filter *attack, iir_filter *decay){
- double a_c0=attack->c0;
- 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;
+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;
- if(x[0]>y0)state=0;
-
- while(i<n){
-
- if(state==0){
- /* attack case */
- while(i<n){
- y[i] = (x[i]+x0*2.+x1)/a_g + y0*a_c0+y1*a_c1;
-
- if(y[i]<y0){
- /* decay fixup; needed because we're in discontinuous time. In a
- physical time-assymmetric Bessel follower, the decay case would
- take over at the instant the attack filter peaks. In z-space,
- the attack filter has already begun to decay, and the decay
- filter otherwise takes over with an already substantial
- negative slope in the filter state, or if it takes over in the
- preceeding time quanta, a substantial positive slope. Fix this
- up to take over at zero y slope. */
- y1=y0;
- state=1;
- break;
- }
- x1=x0;x0=x[i];
- y1=y0;y0=y[i];
- i++;
+ /* 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;ii<ahead;ii++)
+ if(fabs(x[ii])>val){
+ val=fabs(x[ii]);
+ loc=ii+hold;
}
- }
-
- if(state==1){
- /* decay case */
- while(1){
- y[i] = (x[i]+x0*2+x1)/d_g + y0*d_c0+y1*d_c1;
-
- x1=x0;x0=x[i];
- y1=y0;y0=y[i];
- i++;
-
- if(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;
+ 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;j<ch;j++){
- float *x=xx[j]+ahead;
- for(i=0;i<n;i++)
- rms[i]+=x[i]*x[i];
- }
- if(ch>1)
- for(i=0;i<n;i++)
- rms[i]/=ch;
- }
-}
-
-static void prepare_peak(float *peak, float **xx, int n, int ch,int ahead){
- if(ch){
- int j,k,l;
-
- memset(peak,0,sizeof(*peak)*n);
-
- for(l=0;l<ch;l++){
-
- float *x=xx[l];
- int ii,jj;
- int loc=0;
- float val=fabs(x[0]);
-
- /* find highest point in next [ahead] */
- for(ii=1;ii<ahead;ii++)
- if(fabs(x[ii])>val){
- val=fabs(x[ii]);
- loc=ii;
- }
- if(val>peak[0])peak[0]=val;
-
- for(ii=1;ii<n;ii++){
- if(fabs(x[ii+ahead])>val){
- 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(jj<n && val>peak[jj])peak[jj]=val;
- }
- val=fabs(x[ii+ahead-1]);
- loc=ii+ahead;
- }
- if(val>peak[ii])peak[ii]=val;
+ for(ii=1;ii<n;ii++){
+ if(fabs(x[ii+ahead])>val){
+ 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(jj<n && val>peak[jj])peak[jj]=val;
}
+ val=fabs(x[ii+ahead-1]);
+ loc=ii+ahead+hold;
}
-
- for(j=0;j<n;j++)
- peak[j]=todB_p(peak+j);
+ if(val>peak[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;i<n;i++)
- dB[i]=todB_p(dB+i)*.5f;
+ dB[i]=todB_a(dB+i)*.5f;
+ else
+ for(i=0;i<n;i++)
+ dB[i]=todB_a(dB+i);
+
}
-static void run_filter(float *dB,float *work,float **x,int n, int ch, int i,
- float lookahead,int link,int mode,
- iir_state *iir,iir_filter *attack,iir_filter *decay){
- if(link){
- if(i==0){
- if(mode)
- prepare_peak(work, x, n, ch, step_ahead(attack->alpha)*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;i<multicomp_freqs_max;i++){
- for(j=0;j<input_ch;j++){
- ms.over_iir[i][j].x[0]=fromdB(ms.over_iir[i][j].x[0]*2.);
- ms.over_iir[i][j].x[1]=fromdB(ms.over_iir[i][j].x[1]*2.);
- ms.over_iir[i][j].y[0]=fromdB(ms.over_iir[i][j].y[0]*2.);
- ms.over_iir[i][j].y[1]=fromdB(ms.over_iir[i][j].y[1]*2.);
- }
- }
+ run_filter(overdB,lx,input_size,lookahead,mode,iir,attack, decay,ps);
+
+ if(active){
+ if(c.over_softknee){
+ for(k=0;k<input_size;k++)
+ adj[k]+=soft_knee(overdB[k]-zerocorner)*corner_multiplier;
}else{
- /* from linear^2 to dB */
- for(i=0;i<multicomp_freqs_max;i++){
- for(j=0;j<input_ch;j++){
- ms.over_iir[i][j].x[0]=todB(ms.over_iir[i][j].x[0])*.5;
- ms.over_iir[i][j].x[1]=todB(ms.over_iir[i][j].x[1])*.5;
- ms.over_iir[i][j].y[0]=todB(ms.over_iir[i][j].y[0])*.5;
- ms.over_iir[i][j].y[1]=todB(ms.over_iir[i][j].y[1])*.5;
- }
+ for(k=0;k<input_size;k++)
+ adj[k]+=hard_knee(overdB[k]-zerocorner)*corner_multiplier;
+ }
+ }
+
+ {
+ /* determine rms and peak for feedback */
+ float max=-1.;
+ int maxpos=-1;
+ float rms=0.;
+
+ for(k=0;k<input_size;k++){
+ float val=lx[k]*lx[k];
+ if(val>max){
+ max=val;
+ maxpos=k;
}
+ rms+=val;
}
+ *peakfeed=todB(max)*.5+adj[maxpos];
+ *rmsfeed=todB(rms/input_size)*.5+adj[maxpos];
}
+}
- ms.previous_over_mode=mode;
+static void base_compand(float *x,
+ iir_filter *attack, iir_filter *decay,
+ iir_state *iir, peak_state *ps,
+ float *adj,int active){
+ int k;
+ float basedB[input_size];
+ int mode=c.base_mode;
+ float base_multiplier=(1.-1./(c.base_ratio/1000.));
- for(i=0;i<multicomp_freqs[ms.active_bank];i++){
- float zerocorner=bc[ms.active_bank].static_o[i]/10.;
- float limitcorner=zerocorner + fabs((c.over_limit*10.)/corner_multiplier);
-
- for(j=0;j<input_ch;j++){
- float *lx=x[i][j];
- run_filter(dB,work,x[i],input_size,input_ch,j,lookahead,link,mode,
- ms.over_iir[i],&ms.over_attack[ms.active_bank][i],&ms.over_decay[ms.active_bank][i]);
-
- if(compand_active)
- for(k=0;k<input_size;k++){
- float adj=(knee(dB[i]-zerocorner)-knee(dB[i]-limitcorner))*corner_multiplier;
- adj-= (dB[i]+adj)*base_multiplier;
- lx[k]*=fromdB(adj);
- }
- }
- }
+ run_filter(basedB,x,input_size,1.,mode,
+ iir,attack,decay,ps);
+
+ if(active)
+ for(k=0;k<input_size;k++)
+ adj[k]-=(basedB[k]+adj[k])*base_multiplier;
+
}
-static void under_compand(float ***x){
- int i,j,k;
- float work[input_size];
- float dB[input_size];
+static void under_compand(float *x,float zerocorner,
+ iir_filter *attack, iir_filter *decay,
+ iir_state *iir, peak_state *ps,
+ float *adj,int active){
+ int k;
+ float underdB[input_size];
float lookahead=c.under_lookahead/1000.;
- int link=c.link_mode;
int mode=c.under_mode;
-
- float (*knee)(float)=(c.under_softknee?soft_knee:hard_knee);
-
float corner_multiplier=(1.-1./(c.under_ratio/1000.));
- if(ms.previous_under_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;i<multicomp_freqs_max;i++){
- for(j=0;j<input_ch;j++){
- ms.under_iir[i][j].x[0]=fromdB(ms.under_iir[i][j].x[0]*2.);
- ms.under_iir[i][j].x[1]=fromdB(ms.under_iir[i][j].x[1]*2.);
- ms.under_iir[i][j].y[0]=fromdB(ms.under_iir[i][j].y[0]*2.);
- ms.under_iir[i][j].y[1]=fromdB(ms.under_iir[i][j].y[1]*2.);
- }
- }
+ run_filter(underdB,x,input_size,lookahead,mode,
+ iir,attack,decay,ps);
+
+ if(active){
+ if(c.under_softknee){
+ for(k=0;k<input_size;k++)
+ adj[k]-=soft_knee(zerocorner-underdB[k])*corner_multiplier;
}else{
- /* from linear^2 to dB */
- for(i=0;i<multicomp_freqs_max;i++){
- for(j=0;j<input_ch;j++){
- ms.under_iir[i][j].x[0]=todB(ms.under_iir[i][j].x[0])*.5;
- ms.under_iir[i][j].x[1]=todB(ms.under_iir[i][j].x[1])*.5;
- ms.under_iir[i][j].y[0]=todB(ms.under_iir[i][j].y[0])*.5;
- ms.under_iir[i][j].y[1]=todB(ms.under_iir[i][j].y[1])*.5;
- }
- }
+ for(k=0;k<input_size;k++)
+ adj[k]-=hard_knee(zerocorner-underdB[k])*corner_multiplier;
}
}
-
- ms.previous_under_mode=mode;
-
- for(i=0;i<multicomp_freqs[ms.active_bank];i++){
- float zerocorner=bc[ms.active_bank].static_o[i]/10.;
- float limitcorner=zerocorner- fabs((c.under_limit*10.)/corner_multiplier);
-
- for(j=0;j<input_ch;j++){
- float *lx=x[i][j];
- run_filter(dB,work,x[i],input_size,input_ch,j,lookahead,link,mode,
- ms.under_iir[i],&ms.under_attack[ms.active_bank][i],&ms.under_decay[ms.active_bank][i]);
- if(compand_active)
- for(k=0;k<input_size;k++)
- lx[k]*=fromdB((knee(zerocorner-dB[i])-knee(limitcorner-dB[i]))*corner_multiplier);
- }
- }
}
- /* (since this one is kinda unique) The 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|peak}
- amplitude attacks but chooses a slower-than-actual decay, then
- expands according to the dB distance between the slow and actual
- decay.
-
- The 'depth' setting is used to limit the expanded distance
- between actual and slow decay; it's also used to drag the slow
- decay down with the actual decay once the expansion has hit the
- depth limit.
-
- Thus, the suppressor can be used to 'dry out' a very 'wet'
- reverberative track. */
-
-static void suppress(float ***x){
+static void multicompand_work(float **peakfeed,float **rmsfeed){
int i,j,k;
- float work[input_size];
- float dB_fast[input_size];
- float dB_slow[input_size];
- int link=c.link_mode;
- int mode=c.suppress_mode;
+ float adj[input_size];
+ float *x;
+ int active=compand_active;
- float multiplier=(1.-1./(c.suppress_ratio/1000.));
-
- if(ms.previous_suppress_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;i<multicomp_freqs_max;i++){
- for(j=0;j<input_ch;j++){
- ms.suppress_iirA[i][j].x[0]=fromdB(ms.suppress_iirA[i][j].x[0]*2.);
- ms.suppress_iirA[i][j].x[1]=fromdB(ms.suppress_iirA[i][j].x[1]*2.);
- ms.suppress_iirA[i][j].y[0]=fromdB(ms.suppress_iirA[i][j].y[0]*2.);
- ms.suppress_iirA[i][j].y[1]=fromdB(ms.suppress_iirA[i][j].y[1]*2.);
- ms.suppress_iirB[i][j].x[0]=fromdB(ms.suppress_iirB[i][j].x[0]*2.);
- ms.suppress_iirB[i][j].x[1]=fromdB(ms.suppress_iirB[i][j].x[1]*2.);
- ms.suppress_iirB[i][j].y[0]=fromdB(ms.suppress_iirB[i][j].y[0]*2.);
- ms.suppress_iirB[i][j].y[1]=fromdB(ms.suppress_iirB[i][j].y[1]*2.);
- }
- }
- }else{
- /* from linear^2 to dB */
- for(i=0;i<multicomp_freqs_max;i++){
- for(j=0;j<input_ch;j++){
- ms.suppress_iirA[i][j].x[0]=todB(ms.suppress_iirA[i][j].x[0])*.5;
- ms.suppress_iirA[i][j].x[1]=todB(ms.suppress_iirA[i][j].x[1])*.5;
- ms.suppress_iirA[i][j].y[0]=todB(ms.suppress_iirA[i][j].y[0])*.5;
- ms.suppress_iirA[i][j].y[1]=todB(ms.suppress_iirA[i][j].y[1])*.5;
- ms.suppress_iirB[i][j].x[0]=todB(ms.suppress_iirB[i][j].x[0])*.5;
- ms.suppress_iirB[i][j].x[1]=todB(ms.suppress_iirB[i][j].x[1])*.5;
- ms.suppress_iirB[i][j].y[0]=todB(ms.suppress_iirB[i][j].y[0])*.5;
- ms.suppress_iirB[i][j].y[1]=todB(ms.suppress_iirB[i][j].y[1])*.5;
- }
- }
- }
- }
-
- ms.previous_suppress_mode=mode;
-
for(i=0;i<multicomp_freqs[ms.active_bank];i++){
+
for(j=0;j<input_ch;j++){
- float *lx=x[i][j];
+ memset(adj,0,sizeof(adj));
- run_filter(dB_fast,work,x[i],input_size,input_ch,j,1.,link,mode,
- ms.suppress_iirA[i],&ms.suppress_attack[ms.active_bank][i],&ms.suppress_decay[ms.active_bank][i]);
- run_filter_only(dB_slow,work,x[i],input_size,mode,
- ms.suppress_iirB[i],&ms.suppress_attack[ms.active_bank][i],&ms.suppress_release[ms.active_bank][i]);
-
- if(compand_active && multiplier!=0.)
- for(k=0;k<input_size;k++){
- float adj=(dB_fast[i]-dB_slow[i])*multiplier;
- lx[k]*=fromdB(adj);
- }
- }
- }
-}
-
-static void multicompand_work(float **peakfeed,float **rmsfeed){
- int i,j,k;
-
- under_compand(ms.ss.lap);
- over_compand(ms.ss.lap);
-
- /* feedback displays the results of the static compander */
- if(c.link_mode==0){
- for(i=0;i<multicomp_freqs[ms.active_bank];i++){
- for(j=0;j<input_ch;j++){
- float *x=ms.ss.lap[i][j];
- float rms=0,peak=0;
+ if(active || compand_visible){
+ under_compand(ms.ss.lap[i][j],
+ bc[ms.active_bank].static_u[i],
+ &ms.under_attack[ms.active_bank][i],
+ &ms.under_decay[ms.active_bank][i],
+ &ms.under_iir[i][j],
+ &ms.under_peak[i][j],
+ adj,active);
- for(k=0;k<input_size;k++){
- rms+=x[k]*x[k];
- if(fabs(x[k])>peak)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;i<multicomp_freqs[ms.active_bank];i++){
- float rms=0,peak=0;
- for(j=0;j<input_ch;j++){
- float *x=ms.ss.lap[i][j];
-
- for(k=0;k<input_size;k++){
- rms+=x[k]*x[k];
- if(fabs(x[k])>peak)peak=fabs(x[k]);
- }
- }
-
- for(j=0;j<input_ch;j++){
- peakfeed[i][j]=todB(peak);
- rmsfeed[i][j]=todB(rms/input_size/input_ch)*.5;
+
+
+ if(active){
+ x=ms.ss.lap[i][j];
+ for(k=0;k<input_size;k++)
+ x[k]*=fromdB_a(adj[k]);
}
}
}
-
- suppress(ms.ss.lap);
-
- offset+=input_size;
}
void multicompand_set_bank(int bank){
ms.pending_bank=bank;
}
-static int bypass_state;
-static int active_state;
time_linkage *multicompand_read(time_linkage *in){
- int i,j;
- int pending=ms.pending_bank;
int bypass=!(compand_visible||compand_active);
- if(pending!=ms.active_bank || (bypass && !bypass_state)){
-
- }
-
ms.active_bank=ms.pending_bank;
- bypass_state=bypass;
return subband_read(in,&ms.ss,&ms.sw[ms.active_bank],
multicompand_work,bypass);
}
-
Modified: trunk/postfish/multicompand.h
===================================================================
--- trunk/postfish/multicompand.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/multicompand.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -26,8 +26,8 @@
#define multicomp_freqs_max 30
#define multicomp_banks 3
-static int multicomp_freqs[multicomp_banks]={10,20,30};
-static float multicomp_freq_list[multicomp_banks][multicomp_freqs_max+1]={
+static const int multicomp_freqs[multicomp_banks]={10,20,30};
+static const float multicomp_freq_list[multicomp_banks][multicomp_freqs_max+1]={
{31.5,63,125,250,500,1000,2000,4000,8000,16000,9e10},
{31.5,44,63,88,125,175,250,350,500,700,1000,1400,
2000,2800,4000,5600,8000,11000,16000,22000},
@@ -36,7 +36,7 @@
8000,10000,12500,16000,20000,9e10}
};
-static char *multicomp_freq_labels[multicomp_banks][multicomp_freqs_max]={
+static char * const multicomp_freq_labels[multicomp_banks][multicomp_freqs_max]={
{"31.5","63","125","250","500","1k","2k","4k","8k","16k"},
{"31.5","44","63","88","125","175","250","350","500","700","1k","1.4k",
"2k","2.8k","4k","5.6k","8k","11k","16k","22k"},
@@ -55,31 +55,24 @@
sig_atomic_t over_mode;
sig_atomic_t over_softknee;
sig_atomic_t over_ratio;
- sig_atomic_t over_limit;
- sig_atomic_t base_ratio;
sig_atomic_t over_attack;
sig_atomic_t over_decay;
sig_atomic_t over_lookahead;
sig_atomic_t over_trim;
+ sig_atomic_t base_mode;
+ sig_atomic_t base_attack;
+ sig_atomic_t base_decay;
+ sig_atomic_t base_ratio;
+
sig_atomic_t under_mode;
sig_atomic_t under_softknee;
sig_atomic_t under_ratio;
- sig_atomic_t under_limit;
sig_atomic_t under_attack;
sig_atomic_t under_decay;
sig_atomic_t under_lookahead;
sig_atomic_t under_trim;
- sig_atomic_t suppress_mode;
- sig_atomic_t suppress_ratio;
-
- sig_atomic_t suppress_attack;
- sig_atomic_t suppress_decay;
- sig_atomic_t suppress_release;
-
- sig_atomic_t link_mode;
-
} other_compand_settings;
extern void multicompand_reset();
@@ -92,6 +85,5 @@
extern int multicompand_over_decay_set(float msec);
extern int multicompand_under_attack_set(float msec);
extern int multicompand_under_decay_set(float msec);
-extern int multicompand_suppress_attack_set(float msec);
-extern int multicompand_suppress_decay_set(float msec);
-extern int multicompand_suppress_release_set(float msec);
+extern int multicompand_base_attack_set(float msec);
+extern int multicompand_base_decay_set(float msec);
Modified: trunk/postfish/output.c
===================================================================
--- trunk/postfish/output.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/output.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -31,6 +31,9 @@
#include "declip.h"
#include "eq.h"
#include "multicompand.h"
+#include "singlecomp.h"
+#include "suppress.h"
+#include "limit.h"
extern int input_size;
sig_atomic_t playback_active=0;
@@ -56,6 +59,9 @@
declip_reset(); /* clear any persistent lapping state */
eq_reset(); /* clear any persistent lapping state */
multicompand_reset(); /* clear any persistent lapping state */
+ singlecomp_reset(); /* clear any persistent lapping state */
+ suppress_reset(); /* clear any persistent lapping state */
+ limit_reset(); /* clear any persistent lapping state */
output_reset(); /* clear any persistent lapping state */
}
@@ -75,7 +81,7 @@
}
static void push_output_feedback(float *peak,float *rms){
- int i,n=input_ch+2;
+ int n=input_ch+2;
output_feedback *f=(output_feedback *)
feedback_new(&feedpool,new_output_feedback);
@@ -86,7 +92,7 @@
int pull_output_feedback(float *peak,float *rms){
output_feedback *f=(output_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);
@@ -207,7 +213,6 @@
time_linkage *link;
int result;
off_t count=0;
- long last=-1;
int ch=-1;
long rate=-1;
@@ -231,6 +236,10 @@
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 @@
/************/
-
- /* 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;i<link->samples;i++)
@@ -248,6 +256,9 @@
}
+ /* the limiter is single-block zero additional latency */
+ link=limit_read(link);
+
/************/
if(link->samples>0){
@@ -280,7 +291,6 @@
for(k=0,i=0;i<link->samples;i++){
float mean=0.;
- float div=0.;
float divrms=0.;
for(j=0;j<link->channels;j++){
Modified: trunk/postfish/postfish-gtkrc
===================================================================
--- trunk/postfish/postfish-gtkrc 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/postfish-gtkrc 2004-04-14 04:50:38 UTC (rev 6506)
@@ -78,7 +78,7 @@
text[NORMAL]="#707070"
text[ACTIVE]="#905050"
- font_name = "sans 6"
+ font_name = "sans 7"
}
style "clipbar" {
@@ -98,6 +98,15 @@
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 "*.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"
Modified: trunk/postfish/postfish.h
===================================================================
--- trunk/postfish/postfish.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/postfish.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -50,8 +50,37 @@
#include <signal.h>
#include <fcntl.h>
-#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))
Modified: trunk/postfish/readout.c
===================================================================
--- trunk/postfish/readout.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/readout.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -103,7 +103,7 @@
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,
Modified: trunk/postfish/readout.h
===================================================================
--- trunk/postfish/readout.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/readout.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -30,6 +30,7 @@
#include <glib-object.h>
#include <gtk/gtkcontainer.h>
#include <gtk/gtkdrawingarea.h>
+#include <gdk/gdkdrawable.h>
G_BEGIN_DECLS
Modified: trunk/postfish/reconstruct.c
===================================================================
--- trunk/postfish/reconstruct.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/reconstruct.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -30,6 +30,7 @@
#include <string.h>
#include <fftw3.h>
+#include <math.h>
#include "reconstruct.h"
/* fftw3 requires this kind of static setup */
@@ -39,7 +40,7 @@
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){
Added: trunk/postfish/rexperiment.c
===================================================================
--- trunk/postfish/rexperiment.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/rexperiment.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -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 <string.h>
+#include "smallft.h"
+
+static void drft_forward_transpose(drft_lookup *fft, double *x){
+ int i;
+
+ for(i=1;i<fft->n-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;i<fft->n-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;hi<newhi;hi++)acc+=hypot(f[(hi<<1)-1],f[hi<<1]);
+ w[0]=acc/hi;
+ }
+
+ for(i=1;i<n/2;i++){
+ double bark=toBark(44100.*i/n);
+ int newlo=rint(fromBark(bark-.5)*n/44100.)-5;
+ int newhi=rint(fromBark(bark+.5)*n/44100.)+5;
+ if(newhi>n/2)newhi=n/2;
+
+ for(;hi<newhi;hi++)
+ acc+=hypot(f[(hi<<1)-1],f[hi<<1]);
+ for(;lo<newlo;lo++)
+ if(lo==0)
+ acc-=fabs(f[0]);
+ else
+ acc-=hypot(f[(lo<<1)-1],f[lo<<1]);
+
+ w[(i<<1)-1]=w[i<<1]=acc/(hi-lo);
+ }
+ w[n-1]=w[n-2];
+}
+
+void _analysis(char *base,int i,double *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;j<n;j++){
+ if(bark){
+ float b=toBark((4000.f*j/n)+.25);
+ fprintf(of,"%f ",b);
+ }else
+ fprintf(of,"%f ",(double)j);
+
+ if(dB){
+ if(j==0||j==n-1)
+ fprintf(of,"%f\n",todB(v[j]));
+ else{
+ fprintf(of,"%f\n",todB(hypot(v[j],v[j+1])));
+ j++;
+ }
+ }else{
+ fprintf(of,"%f\n",v[j]);
+ }
+ }
+ fclose(of);
+}
+
+static double inner_product(double *a, double *b, int n){
+ int i;
+ double acc=0.;
+ for(i=0;i<n;i++)acc+=a[i]*b[i];
+ return acc;
+}
+
+static void compute_AtAx(drft_lookup *fft,
+ double *x,double *w,int *flag,int mask,int n,
+ double *out){
+ int i;
+
+ if(mask){
+ for(i=0;i<n;i++)
+ if(!flag[i])
+ out[i]=0;
+ else
+ out[i]=x[i];
+ }else
+ for(i=0;i<n;i++)
+ if(flag[i])
+ out[i]=0;
+ else
+ out[i]=x[i];
+
+ drft_forward(fft,out);
+ for(i=0;i<n;i++)out[i]*=w[i];
+ drft_backward(fft,out);
+
+ for(i=0;i<n;i++)
+ if(!flag[i])out[i]=0;
+
+}
+
+static void compute_Atb_minus_AtAx(drft_lookup *fft,
+ double *x,double *w,double *Atb,int *flag,
+ int n,double *out){
+ int i;
+ compute_AtAx(fft,x,w,flag,1,n,out);
+ for(i=0;i<n;i++)out[i]=Atb[i]-out[i];
+}
+
+void reconstruct(drft_lookup *fft,
+ double *x, double *w, int *flag, double e,int max,int n){
+ int i,j;
+ double Atb[n];
+ double r[n];
+ double d[n];
+ double q[n];
+ double phi_new,phi_old,phi_0;
+ double alpha,beta;
+
+ /* compute initial Atb */
+ compute_AtAx(fft,x,w,flag,0,n,Atb);
+ for(j=0;j<n;j++)Atb[j]= -Atb[j];
+
+ compute_Atb_minus_AtAx(fft,x,w,Atb,flag,n,r);
+ memcpy(d,r,sizeof(d));
+ phi_0=phi_new=inner_product(r,r,n);
+
+ for(i=0;i<max && phi_new>e*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<n;j++)x[j]+=alpha*d[j];
+
+ _analysis("x",i,x,512,0,0);
+ {
+ double freq[n];
+ memcpy(freq,x,sizeof(freq));
+ drft_forward(fft,freq);
+ _analysis("f",i,freq,512,1,1);
+ }
+
+ if((i & 0x3f)==0x3f)
+ compute_Atb_minus_AtAx(fft,x,w,Atb,flag,n,r);
+ else
+ for(j=0;j<n;j++)r[j]-=alpha*q[j];
+
+ phi_old=phi_new;
+ phi_new=inner_product(r,r,n);
+ beta=phi_new/phi_old;
+ for(j=0;j<n;j++) d[j]=r[j]+beta*d[j];
+ }
+}
+
+void precondition(drft_lookup *fft,double *x,
+ double *w, int *flag, int n,double *out){
+ int i;
+ memcpy(out,x,sizeof(*x)*n);
+ for(i=0;i<n;i++)
+ if(!flag[i])out[i]=0;
+ drft_backward_transpose(fft,out);
+ for(i=0;i<n;i++)out[i]/=w[i]*n;
+ drft_backward(fft,out);
+ for(i=0;i<n;i++)out[i]/=n;
+ for(i=0;i<n;i++)
+ if(!flag[i])out[i]=0;
+}
+
+void reconstruct2(drft_lookup *fft,
+ double *x, double *w, int *flag, double e,int max,int n){
+ int i,j;
+ double Atb[n];
+ double r[n];
+ double s[n];
+ double d[n];
+ double q[n];
+ double phi_new,phi_old,phi_0;
+ double alpha,beta;
+
+ /* compute initial Atb */
+ compute_AtAx(fft,x,w,flag,0,n,Atb);
+ for(j=0;j<n;j++)Atb[j]= -Atb[j];
+
+ compute_Atb_minus_AtAx(fft,x,w,Atb,flag,n,r);
+ precondition(fft,r,w,flag,n,d);
+ phi_0=phi_new=inner_product(r,d,n);
+
+ for(i=0;i<max && phi_new>e*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<n;j++)x[j]+=alpha*d[j];
+
+ _analysis("x1",i,x,512,0,0);
+ {
+ double freq[n];
+ memcpy(freq,x,sizeof(freq));
+ drft_forward(fft,freq);
+ _analysis("f1",i,freq,512,1,1);
+ }
+
+ if((i & 0x3f)==0x3f)
+ compute_Atb_minus_AtAx(fft,x,w,Atb,flag,n,r);
+ else
+ for(j=0;j<n;j++)r[j]-=alpha*q[j];
+
+ precondition(fft,r,w,flag,n,s);
+ phi_old=phi_new;
+ phi_new=inner_product(r,s,n);
+ beta=phi_new/phi_old;
+ for(j=0;j<n;j++) d[j]=s[j]+beta*d[j];
+ }
+}
+
+int main(){
+ int i,j,k;
+ drft_lookup fft;
+ int blocksize=512;
+ double window[512];
+ double work[512];
+ double freq[blocksize];
+ double w[blocksize];
+ int flag[512];
+
+ drft_init(&fft,512);
+ for(i=0;i<blocksize;i++) window[i]=sin( (double)i/blocksize*M_PIl);
+ for(i=0;i<blocksize;i++) window[i]*=window[i];
+ for(i=0;i<blocksize;i++) window[i]=sin(window[i]*M_PIl*.5);
+
+ memcpy(work,testdata[0],sizeof(work));
+
+ for(i=0;i<blocksize;i++){
+ flag[i]=0;
+ if(work[i]>=.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);
+
+}
+
+
Added: trunk/postfish/singlecomp.c
===================================================================
--- trunk/postfish/singlecomp.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/singlecomp.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -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;j<n;j++){
+ fprintf(of,"%f ",(float)j+offset);
+ if(dB)
+ fprintf(of,"%f\n",todB(v[j]));
+ else
+ fprintf(of,"%f\n",(v[j]));
+ }
+ fprintf(of,"\n");
+ fclose(of);
+}
+
+static int offset=0;
+
+
+/* feedback! */
+typedef struct singlecomp_feedback{
+ feedback_generic parent_class;
+ float *peak;
+ float *rms;
+} singlecomp_feedback;
+
+static feedback_generic *new_singlecomp_feedback(void){
+ singlecomp_feedback *ret=calloc(1,sizeof(*ret));
+ return (feedback_generic *)ret;
+}
+
+int pull_singlecomp_feedback(float *peak,float *rms){
+ singlecomp_feedback *f=(singlecomp_feedback *)feedback_pull(&scs.feedpool);
+
+ if(!f)return 0;
+
+ if(peak)
+ memcpy(peak,f->peak,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;i<input_ch;i++)
+ scs.out.data[i]=malloc(input_size*sizeof(**scs.out.data));
+
+ scs.fillstate=0;
+ scs.cache=malloc(input_ch*sizeof(*scs.cache));
+ for(i=0;i<input_ch;i++)
+ scs.cache[i]=malloc(input_size*sizeof(**scs.cache));
+
+ return(0);
+}
+
+static void filter_set(float msec,
+ iir_filter *filter,
+ int attackp){
+ float alpha;
+ float corner_freq= 500./msec;
+
+ /* make sure the chosen frequency doesn't require a lookahead
+ greater than what's available */
+ if(step_freq(input_size)*1.01>corner_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;ii<ahead;ii++)
+ if(fabs(x[ii])>val){
+ val=fabs(x[ii]);
+ loc=ii+hold;
+ }
+ }
+
+ if(val>peak[0])peak[0]=val;
+
+ for(ii=1;ii<n;ii++){
+ if(fabs(x[ii+ahead])>val){
+ 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(jj<n && val>peak[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;k<input_size-ahead;k++)
+ work[k]=cachea[k]*cachea[k];
+
+ for(k=0;k<ahead;k++)
+ worka[k]=in[k]*in[k];
+ }
+
+ compute_iir2(work, input_size, iir, attack, decay);
+
+ if(mode==0)
+ for(k=0;k<input_size;k++)
+ work[k]=todB_a(work+k)*.5f;
+ else
+ for(k=0;k<input_size;k++)
+ work[k]=todB_a(work+k);
+}
+
+static float soft_knee(float x){
+ return (sqrtf(x*x+30.f)+x)*-.5f;
+}
+
+static float hard_knee(float x){
+ return (x>0.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;k<input_size;k++)
+ adj[k]+=soft_knee(work[k]-zerocorner)*multiplier;
+ }else{
+ for(k=0;k<input_size;k++)
+ adj[k]+=hard_knee(work[k]-zerocorner)*multiplier;
+ }
+ }
+}
+
+static void under_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;k<input_size;k++)
+ adj[k]= -soft_knee(zerocorner-work[k])*multiplier;
+ }else{
+ for(k=0;k<input_size;k++)
+ adj[k]= -hard_knee(zerocorner-work[k])*multiplier;
+ }
+ }else
+ memset(adj,0,sizeof(*adj)*input_size);
+
+}
+
+static void base_compand(float *A,float *B,float *adj,
+ float multiplier,int mode,
+ 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));
+
+ run_filter(A,B,work,ahead,0,mode,iir,attack,decay,ps);
+
+ if(active)
+ for(k=0;k<input_size;k++)
+ adj[k]-=(work[k]+adj[k])*multiplier;
+
+}
+
+time_linkage *singlecomp_read(time_linkage *in){
+ float peakfeed[input_ch];
+ float rmsfeed[input_ch];
+
+ int active=singlecomp_active;
+ int i;
+
+ float o_attackms=scset.o_attack*.1;
+ float o_decayms=scset.o_decay*.1;
+ float u_attackms=scset.u_attack*.1;
+ float u_decayms=scset.u_decay*.1;
+ float b_attackms=scset.b_attack*.1;
+ float b_decayms=scset.b_decay*.1;
+
+ if(o_attackms!=scs.o_attack.ms)filter_set(o_attackms,&scs.o_attack,1);
+ if(o_decayms!=scs.o_decay.ms)filter_set(o_decayms,&scs.o_decay,0);
+ if(u_attackms!=scs.u_attack.ms)filter_set(u_attackms,&scs.u_attack,1);
+ if(u_decayms!=scs.u_decay.ms)filter_set(u_decayms,&scs.u_decay,0);
+ if(b_attackms!=scs.b_attack.ms)filter_set(b_attackms,&scs.b_attack,1);
+ if(b_decayms!=scs.b_decay.ms)filter_set(b_decayms,&scs.b_decay,0);
+
+ switch(scs.fillstate){
+ case 0: /* prime the cache */
+ if(in->samples==0){
+ scs.out.samples=0;
+ return &scs.out;
+ }
+ for(i=0;i<input_ch;i++){
+ float *temp=in->data[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;i<input_ch;i++)
+ memset(in->data[i],0,sizeof(**in->data)*in->size);
+ in->samples=0;
+ /* fall through */
+ case 1: /* nominal processing */
+
+ for(i=0;i<input_ch;i++){
+
+ float adj[input_size]; // under will set it
+
+ 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);
+
+ /* feedback before base */
+ {
+ int k;
+ float rms=0.;
+ float peak=0.;
+ float *x=scs.cache[i];
+
+ for(k=0;k<input_size;k++){
+ float mul=fromdB_a(adj[k]);
+ float val=x[k]*mul;
+
+ val*=val;
+ rms+= val;
+ if(peak<val)peak=val;
+
+ }
+
+ peakfeed[i]=todB_a(&peak)*.5;
+ rms/=input_size;
+ rmsfeed[i]=todB_a(&rms)*.5;
+ }
+
+ 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);
+
+ if(active){
+ int k;
+ float *x=scs.cache[i];
+ float *out=scs.out.data[i];
+
+ for(k=0;k<input_size;k++)
+ out[k]=x[k]*fromdB_a(adj[k]);
+ }else
+ memcpy(scs.out.data[i],scs.cache[i],input_size*sizeof(*scs.cache[i]));
+
+ {
+ float *temp=scs.cache[i];
+ scs.cache[i]=in->data[i];
+ in->data[i]=temp;
+ }
+ }
+ scs.out.samples=scs.cache_samples;
+ scs.cache_samples=in->samples;
+ if(scs.out.samples<scs.out.size)scs.fillstate=2;
+ break;
+ case 2: /* we've pushed out EOF already */
+ scs.out.samples=0;
+ }
+
+ /* finish up the state feedabck */
+ {
+ singlecomp_feedback *ff=
+ (singlecomp_feedback *)feedback_new(&scs.feedpool,new_singlecomp_feedback);
+
+ if(!ff->peak)
+ 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<scs.out.channels;i++)
+ memset(scs.out.data[i]+scs.out.samples,0,sizeof(**scs.out.data)*tozero);
+ }
+
+ offset+=input_size;
+
+ return &scs.out;
+}
+
Added: trunk/postfish/singlecomp.h
===================================================================
--- trunk/postfish/singlecomp.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/singlecomp.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -0,0 +1,54 @@
+/*
+ *
+ * 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"
+
+typedef struct {
+ sig_atomic_t o_attack;
+ sig_atomic_t o_decay;
+ sig_atomic_t u_attack;
+ sig_atomic_t u_decay;
+ sig_atomic_t b_attack;
+ sig_atomic_t b_decay;
+
+ sig_atomic_t o_thresh;
+ sig_atomic_t o_ratio;
+ sig_atomic_t o_lookahead;
+ sig_atomic_t o_mode;
+ sig_atomic_t o_softknee;
+
+ sig_atomic_t u_thresh;
+ sig_atomic_t u_ratio;
+ sig_atomic_t u_lookahead;
+ sig_atomic_t u_mode;
+ sig_atomic_t u_softknee;
+
+ sig_atomic_t b_ratio;
+ sig_atomic_t b_mode;
+
+} singlecomp_settings;
+
+extern int pull_singlecomp_feedback(float *peak,float *rms);
+extern int singlecomp_load(void);
+extern int singlecomp_reset(void);
+extern time_linkage *singlecomp_read(time_linkage *in);
Added: trunk/postfish/singlepanel.c
===================================================================
--- trunk/postfish/singlepanel.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/singlepanel.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -0,0 +1,582 @@
+/*
+ *
+ * postfish
+ *
+ * Copyright (C) 2002-2004 Monty
+ *
+ * Postfish is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Postfish is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Postfish; see the file COPYING. If not, write to the
+ * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ */
+
+#include "postfish.h"
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#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));
+}
+
+
+
Added: trunk/postfish/singlepanel.h
===================================================================
--- trunk/postfish/singlepanel.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/singlepanel.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -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);
+
+
Modified: trunk/postfish/subband.c
===================================================================
--- trunk/postfish/subband.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/subband.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -41,9 +41,7 @@
} 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 @@
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 @@
/* 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 @@
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;i<input_ch;i++){
@@ -303,7 +300,6 @@
static void bypass_work(subband_state *f,time_linkage *in){
int i,j;
- float *workoff=f->fftwf_forward_in+f->qblocksize;
float scale=f->qblocksize*4.;
for(i=0;i<input_ch;i++){
@@ -358,13 +354,14 @@
for(j=bands-1;j>=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;k<input_size;k++)
out[i][k]+=f->lap[j][i][k];
}
+ }
/* shift bands for next lap */
/* optimization target: ringbuffer me! */
@@ -420,8 +417,8 @@
}else{
/* extrapolation mechanism; avoid harsh transients at edges */
for(i=0;i<input_ch;i++){
- preextrapolate_helper(in->data[i],input_size,
- f->cache[i],input_size);
+ preextrapolate_helper(in->data[i],input_size,
+ f->cache[i],input_size);
if(in->samples<in->size)
postextrapolate_helper(f->cache[i],input_size,
@@ -526,7 +523,6 @@
/* finish up the state feedabck */
if(!bypass){
- int j;
subband_feedback *ff=
(subband_feedback *)feedback_new(&f->feedpool,new_subband_feedback);
Modified: trunk/postfish/subband.h
===================================================================
--- trunk/postfish/subband.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/subband.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -49,7 +49,6 @@
typedef struct {
- float *freq_list;
int freq_bands;
float **ho_window;
float *ho_area;
@@ -60,7 +59,7 @@
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,
Modified: trunk/postfish/subpanel.c
===================================================================
--- trunk/postfish/subpanel.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/subpanel.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -116,7 +116,6 @@
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);
Added: trunk/postfish/suppress.c
===================================================================
--- trunk/postfish/suppress.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/suppress.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -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 <fftw3.h>
+#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;i<suppress_freqs;i++){
+ for(j=0;j<input_ch;j++){
+ memset(&sss.iirS[i][j],0,sizeof(iir_state));
+ memset(&sss.iirT[i][j],0,sizeof(iir_state));
+ memset(&sss.iirR[i][j],0,sizeof(iir_state));
+ }
+ }
+}
+
+static void filter_set(float msec,
+ iir_filter *filter,
+ int attackp,
+ int order){
+ float alpha;
+ float corner_freq= 500./msec;
+
+ /* make sure the chosen frequency doesn't require a lookahead
+ greater than what's available */
+ if(impulse_freq4(input_size*2-sss.ss.qblocksize*3)*1.01>corner_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;i<suppress_freqs;i++){
+ sss.iirS[i]=calloc(input_ch,sizeof(iir_state));
+ sss.iirT[i]=calloc(input_ch,sizeof(iir_state));
+ sss.iirR[i]=calloc(input_ch,sizeof(iir_state));
+ }
+ return 0;
+}
+
+static void suppress_work(float **peakfeed,float **rmsfeed){
+ int i,j,k,l;
+ float smoothms=sset.smooth*.1;
+ float triggerms=sset.trigger*.1;
+ float releasems=sset.release*.1;
+ iir_filter *trigger=&sss.trigger;
+ iir_filter *smooth=&sss.smooth;
+ iir_filter *release=&sss.release;
+ int ahead;
+
+ if(smoothms!=smooth->ms)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<suppress_freqs;i++){
+
+ if(suppress_active){
+ float fast[input_size];
+ float slow[input_size];
+ float multiplier = 1.-1000./sset.ratio[i];
+
+ for(j=0;j<input_ch;j++){
+ if(sset.linkp){
+ if(j==0){
+ memset(fast,0,sizeof(fast));
+ float scale=1./input_ch;
+ for(l=0;l<input_ch;l++){
+ float *x=sss.ss.lap[i][l]+ahead;
+ for(k=0;k<input_size;k++)
+ fast[k]+=x[k]*x[k];
+ }
+ for(k=0;k<input_size;k++)
+ fast[k]*=scale;
+
+ //_analysis("rms",i,fast,input_size,0,offset);
+
+ }
+
+ }else{
+ float *x=sss.ss.lap[i][j]+ahead;
+ for(k=0;k<input_size;k++)
+ fast[k]=x[k]*x[k];
+ }
+
+
+ if(j==0 || sset.linkp==0){
+
+ compute_iir_symmetric4(fast, input_size, &sss.iirS[i][j],
+ smooth);
+
+ //_analysis("smooth",i,fast,input_size,1,offset);
+
+ compute_iir_freefall1(fast, input_size, &sss.iirT[i][j],
+ trigger);
+ memcpy(slow,fast,sizeof(slow));
+ compute_iir_freefall1(slow, input_size, &sss.iirR[i][j],
+ release);
+
+ //_analysis("fast",i,fast,input_size,1,offset);
+ //_analysis("slow",i,slow,input_size,1,offset);
+ for(k=0;k<input_size;k++)
+ fast[k]=fromdB_a((todB_a(slow+k)-todB_a(fast+k))*.5*multiplier);
+ //_analysis("adj",i,fast,input_size,1,offset);
+ }
+
+
+ {
+ float *x=sss.ss.lap[i][j];
+ for(k=0;k<input_size;k++)
+ if(fast[k]<1.)
+ x[k]*=fast[k];
+ }
+ }
+ }
+ }
+}
+
+time_linkage *suppress_read(time_linkage *in){
+ int bypass=!(suppress_active);
+
+ return subband_read(in,&sss.ss,&sss.sw,
+ suppress_work,bypass);
+}
+
+
Added: trunk/postfish/suppress.h
===================================================================
--- trunk/postfish/suppress.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/suppress.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -0,0 +1,46 @@
+/*
+ *
+ * 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"
+
+#define suppress_freqs 8
+static const float suppress_freq_list[suppress_freqs+1]={
+ 125,250,500,1000,2000,4000,8000,16000,9e10
+};
+
+static char * const suppress_freq_labels[suppress_freqs]={
+ "125","250","500","1k","2k","4k","8k","16k"
+};
+
+typedef struct {
+ sig_atomic_t ratio[suppress_freqs];
+ sig_atomic_t smooth;
+ sig_atomic_t trigger;
+ sig_atomic_t release;
+ sig_atomic_t linkp;
+} suppress_settings;
+
+extern void suppress_reset();
+extern int suppress_load(void);
+extern time_linkage *suppress_read(time_linkage *in);
+
Added: trunk/postfish/suppresspanel.c
===================================================================
--- trunk/postfish/suppresspanel.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/suppresspanel.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -0,0 +1,242 @@
+/*
+ *
+ * postfish
+ *
+ * Copyright (C) 2002-2004 Monty
+ *
+ * Postfish is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Postfish is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Postfish; see the file COPYING. If not, write to the
+ * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ */
+
+#include "postfish.h"
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#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<suppress_freqs;i++){
+ GtkWidget *label=gtk_label_new(suppress_freq_labels[i]);
+ gtk_widget_set_name(label,"scalemarker");
+
+ bars[i].readoutc=READOUT(readout_new("1.55:1"));
+ bars[i].cslider=multibar_slider_new(4,compand_labels,compand_levels,1);
+ bars[i].number=i;
+
+ multibar_callback(MULTIBAR(bars[i].cslider),compand_change,bars+i);
+ multibar_thumb_set(MULTIBAR(bars[i].cslider),1,0);
+
+ gtk_misc_set_alignment(GTK_MISC(label),1,.5);
+
+ gtk_table_attach(GTK_TABLE(table),label,0,1,i+3,i+4,
+ GTK_FILL,0,0,0);
+
+ gtk_table_attach(GTK_TABLE(table),bars[i].cslider,1,4,i+3,i+4,
+ GTK_FILL|GTK_EXPAND,GTK_EXPAND,5,0);
+ gtk_table_attach(GTK_TABLE(table),GTK_WIDGET(bars[i].readoutc),4,5,
+ i+3,i+4,0,0,0,0);
+ }
+ subpanel_show_all_but_toplevel(panel);
+
+}
+
Added: trunk/postfish/suppresspanel.h
===================================================================
--- trunk/postfish/suppresspanel.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/suppresspanel.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -0,0 +1,26 @@
+/*
+ *
+ * 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 suppresspanel_create(postfish_mainpanel *mp,
+ GtkWidget *windowbutton,
+ GtkWidget *activebutton);
Modified: trunk/postfish/version.h
===================================================================
--- trunk/postfish/version.h 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/version.h 2004-04-14 04:50:38 UTC (rev 6506)
@@ -1,2 +1,2 @@
#define VERSION "$Id: version.h,v 1.44 2004/03/17 10:37:04 xiphmont Exp $ "
-/* DO NOT EDIT: Automated versioning hack [Wed Mar 17 05:34:18 EST 2004] */
+/* DO NOT EDIT: Automated versioning hack [Wed Apr 14 00:46:49 EDT 2004] */
Modified: trunk/postfish/windowbutton.c
===================================================================
--- trunk/postfish/windowbutton.c 2004-04-10 20:07:05 UTC (rev 6505)
+++ trunk/postfish/windowbutton.c 2004-04-14 04:50:38 UTC (rev 6506)
@@ -57,6 +57,11 @@
}
gdk_draw_line(window,light_gc,x,y,x,y+size-2);
break;
+ case GTK_SHADOW_NONE:
+ break;
+ case GTK_SHADOW_ETCHED_OUT:
+ /* unimplemented, unused */
+ break;
}
}
--- >8 ----
List archives: http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body. No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.
More information about the commits
mailing list