[xiph-cvs] r6774 - trunk/postfish
xiphmont at xiph.org
xiphmont at xiph.org
Fri May 28 18:17:49 PDT 2004
Author: xiphmont
Date: 2004-05-28 21:17:47 -0400 (Fri, 28 May 2004)
New Revision: 6774
Added:
trunk/postfish/config.c
trunk/postfish/config.h
trunk/postfish/outpanel.c
trunk/postfish/outpanel.h
trunk/postfish/reverbpanel.c
trunk/postfish/reverbpanel.h
Modified:
trunk/postfish/Makefile
trunk/postfish/clippanel.c
trunk/postfish/clippanel.h
trunk/postfish/compandpanel.c
trunk/postfish/compandpanel.h
trunk/postfish/declip.c
trunk/postfish/declip.h
trunk/postfish/eq.c
trunk/postfish/eq.h
trunk/postfish/eqpanel.c
trunk/postfish/eqpanel.h
trunk/postfish/feedback.c
trunk/postfish/input.c
trunk/postfish/input.h
trunk/postfish/limit.c
trunk/postfish/limit.h
trunk/postfish/limitpanel.c
trunk/postfish/limitpanel.h
trunk/postfish/main.c
trunk/postfish/mainpanel.c
trunk/postfish/mainpanel.h
trunk/postfish/mix.c
trunk/postfish/mix.h
trunk/postfish/mixpanel.c
trunk/postfish/mixpanel.h
trunk/postfish/multicompand.c
trunk/postfish/multicompand.h
trunk/postfish/output.c
trunk/postfish/output.h
trunk/postfish/postfish-gtkrc
trunk/postfish/postfish.h
trunk/postfish/readout.c
trunk/postfish/reverb.c
trunk/postfish/reverb.h
trunk/postfish/singlecomp.c
trunk/postfish/singlecomp.h
trunk/postfish/singlepanel.c
trunk/postfish/singlepanel.h
trunk/postfish/subband.c
trunk/postfish/subpanel.c
trunk/postfish/subpanel.h
trunk/postfish/suppress.c
trunk/postfish/suppress.h
trunk/postfish/suppresspanel.c
trunk/postfish/suppresspanel.h
trunk/postfish/version.h
Log:
Having Postfish around in a state where I keep tinkering on it is
still proving distracting.
So that's it. I'm calling this a prerelease commit and putting it
out of mind. I'll come back when OggFile hits beta.
Have at.
<p><p>Modified: trunk/postfish/Makefile
===================================================================
--- trunk/postfish/Makefile 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/Makefile 2004-05-29 01:17:47 UTC (rev 6774)
@@ -3,14 +3,19 @@
# and Fuck its little dog Libtool too
-ADD_DEF= -DUGLY_IEEE754_FLOAT32_HACK=1 -maltivec
+# The PPC build *must* use -maltivec, even if the target is a non-altivec machine
-# use for PPC with altivec. IF YOU HAVE ALTIVEC, YOU MUST USE THIS
-# LINE, otherwise FFTW3 will randomly crash whenever it uses Altivec
-# and any math denormalizes.
-
#ADD_DEF= -DUGLY_IEEE754_FLOAT32_HACK=1 -maltivec
+# use the below for x86 and most other platforms where 'float' is 32 bit IEEE754
+
+ADD_DEF= -DUGLY_IEEE754_FLOAT32_HACK=1
+
+# use the below for anything without IEE754 floats (eg, VAX)
+
+# ADD_DEF=
+
+
CC=gcc
LD=gcc
INSTALL=install
@@ -23,12 +28,14 @@
declip.c reconstruct.c multicompand.c windowbutton.c subpanel.c \
feedback.c freq.c eq.c eqpanel.c compandpanel.c subband.c lpc.c \
bessel.c suppresspanel.c suppress.c singlecomp.c singlepanel.c \
- limit.c limitpanel.c mute.c mixpanel.c mix.c reverb.c reverbpanel.c
+ limit.c limitpanel.c mute.c mixpanel.c mix.c reverb.c reverbpanel.c \
+ outpanel.c config.c
OBJ = main.o mainpanel.o multibar.o readout.o input.o output.o clippanel.o \
declip.o reconstruct.o multicompand.o windowbutton.o subpanel.o \
feedback.o freq.o eq.o eqpanel.o compandpanel.o subband.o lpc.o \
bessel.o suppresspanel.o suppress.o singlecomp.o singlepanel.o \
- limit.o limitpanel.o mute.o mixpanel.o mix.o reverb.o reverbpanel.o
+ limit.o limitpanel.o mute.o mixpanel.o mix.o reverb.o reverbpanel.o \
+ outpanel.o config.o
GCF = -DETCDIR=\\\"$(ETCDIR)\\\" `pkg-config --cflags gtk+-2.0` -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED
all:
Modified: trunk/postfish/clippanel.c
===================================================================
--- trunk/postfish/clippanel.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/clippanel.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -29,25 +29,25 @@
#include "mainpanel.h"
#include "subpanel.h"
#include "declip.h"
+#include "config.h"
-extern sig_atomic_t *declip_active;
-extern sig_atomic_t declip_visible;
-extern int input_ch;
-extern int input_size;
-extern int input_rate;
-extern sig_atomic_t declip_converge;
+static GtkWidget **feedback_bars;
+static GtkWidget **trigger_bars;
-GtkWidget **feedback_bars;
-GtkWidget **trigger_bars;
+static GtkWidget *width_bar;
+static GtkWidget *samplereadout;
+static GtkWidget *msreadout;
+static GtkWidget *hzreadout;
-GtkWidget *samplereadout;
-GtkWidget *msreadout;
-GtkWidget *hzreadout;
-GtkWidget *depth_readout;
-GtkWidget *limit_readout;
+static GtkWidget *depth_bar;
+static GtkWidget *depth_readout;
+static GtkWidget *limit_bar;
+static GtkWidget *limit_readout;
-GtkWidget *mainpanel_inbar;
+static GtkWidget *mainpanel_inbar;
+static subpanel_generic *panel;
+
typedef struct {
GtkWidget *slider;
GtkWidget *readout;
@@ -55,6 +55,37 @@
int number;
} clipslider;
+void clippanel_state_to_config(int bank){
+ config_set_vector("clippanel_active",bank,0,0,0,input_ch,declip_active);
+ config_set_integer("clippanel_width",bank,0,0,0,0,declip_pending_blocksize);
+ config_set_integer("clippanel_convergence",bank,0,0,0,0,declip_convergence);
+ config_set_integer("clippanel_throttle",bank,0,0,0,0,declip_iterations);
+ config_set_vector("clippanel_trigger",bank,0,0,0,input_ch,declip_chtrigger);
+}
+
+void clippanel_state_from_config(int bank){
+ int i;
+ config_get_vector("clippanel_active",bank,0,0,0,input_ch,declip_active);
+ config_get_sigat("clippanel_width",bank,0,0,0,0,&declip_pending_blocksize);
+ config_get_sigat("clippanel_convergence",bank,0,0,0,0,&declip_convergence);
+ config_get_sigat("clippanel_throttle",bank,0,0,0,0,&declip_iterations);
+ config_get_vector("clippanel_trigger",bank,0,0,0,input_ch,declip_chtrigger);
+
+ {
+ int i=0,j=declip_pending_blocksize;
+ while(j>64){j>>=1;i++;}
+ multibar_thumb_set(MULTIBAR(width_bar),i,0);
+ }
+ multibar_thumb_set(MULTIBAR(depth_bar),declip_convergence*-.1,0);
+ multibar_thumb_set(MULTIBAR(limit_bar),declip_iterations*.1,0);
+
+ for(i=0;i<input_ch;i++){
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(panel->subpanel_activebutton[i]),
+ declip_active[i]);
+ multibar_thumb_set(MULTIBAR(trigger_bars[i]),declip_chtrigger[i]*.0001,0);
+ }
+}
+
static void trigger_slider_change(GtkWidget *w,gpointer in){
char buffer[80];
clipslider *p=(clipslider *)in;
@@ -66,8 +97,7 @@
sprintf(buffer,"%3.0fdB",todB(linear));
readout_set(READOUT(p->readoutdB),buffer);
- declip_settrigger(linear,p->number);
-
+ declip_chtrigger[p->number]=rint(linear*10000.);
}
static void blocksize_slider_change(GtkWidget *w,gpointer in){
@@ -83,8 +113,8 @@
sprintf(buffer,"%5dHz",(int)rint(input_rate*2./blocksize));
readout_set(READOUT(hzreadout),buffer);
-
- declip_setblock(blocksize);
+
+ declip_pending_blocksize=blocksize;
}
static void depth_slider_change(GtkWidget *w,gpointer in){
@@ -94,7 +124,7 @@
sprintf(buffer,"%3ddB",(int)dB);
readout_set(READOUT(depth_readout),buffer);
- declip_setconvergence(fromdB(-dB));
+ declip_convergence=rint(-dB*10.);
}
static void limit_slider_change(GtkWidget *w,gpointer in){
@@ -104,7 +134,7 @@
sprintf(buffer,"%3d%%",(int)percent);
readout_set(READOUT(limit_readout),buffer);
- declip_setiterations(percent*.01);
+ declip_iterations=rint(percent*10.);
}
static void active_callback(gpointer in,int activenum){
@@ -120,11 +150,6 @@
float levels[3]={0.,10.,100.};
int block_choices=0;
- subpanel_generic *panel=subpanel_create(mp,windowbutton[0],activebutton,
- declip_active,&declip_visible,
- "_Declipping filter setup",NULL,
- 0,input_ch);
-
GtkWidget *framebox=gtk_hbox_new(1,0);
GtkWidget *framebox_right=gtk_vbox_new(0,0);
GtkWidget *blocksize_box=gtk_vbox_new(0,0);
@@ -135,6 +160,11 @@
GtkWidget *limit_box=gtk_vbox_new(0,0);
GtkWidget *channel_table=gtk_table_new(input_ch,5,0);
+ panel=subpanel_create(mp,windowbutton[0],activebutton,
+ declip_active,&declip_visible,
+ "_Declipping filter setup",NULL,
+ 0,input_ch);
+
subpanel_set_active_callback(panel,0,active_callback);
gtk_widget_set_name(blocksize_box,"choiceframe");
@@ -182,10 +212,11 @@
gtk_table_attach(GTK_TABLE(table),hzreadout,1,2,3,4,GTK_FILL,0,5,0);
gtk_container_add(GTK_CONTAINER(blocksize_box),table);
+ width_bar=slider;
multibar_thumb_increment(MULTIBAR(slider),1.,1.);
multibar_callback(MULTIBAR(slider),blocksize_slider_change,0);
- multibar_thumb_set(MULTIBAR(slider),2.,0);
+ multibar_thumb_set(MULTIBAR(slider),4.,0);
}
gtk_container_add(GTK_CONTAINER(blocksize_frame),blocksize_box);
@@ -214,6 +245,7 @@
gtk_container_add(GTK_CONTAINER(converge_box),table);
+ depth_bar=slider;
multibar_thumb_increment(MULTIBAR(slider),1.,10.);
multibar_callback(MULTIBAR(slider),depth_slider_change,0);
multibar_thumb_set(MULTIBAR(slider),60.,0);
@@ -244,6 +276,7 @@
gtk_container_add(GTK_CONTAINER(limit_box),table);
+ limit_bar=slider;
multibar_thumb_increment(MULTIBAR(slider),1.,10.);
multibar_callback(MULTIBAR(slider),limit_slider_change,0);
multibar_thumb_set(MULTIBAR(slider),100.,0);
Modified: trunk/postfish/clippanel.h
===================================================================
--- trunk/postfish/clippanel.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/clippanel.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -28,3 +28,6 @@
GtkWidget **activebutton);
extern void clippanel_feedback(int workp);
extern void clippanel_reset(void);
+
+extern void clippanel_state_from_config(int bank);
+extern void clippanel_state_to_config(int bank);
Modified: trunk/postfish/compandpanel.c
===================================================================
--- trunk/postfish/compandpanel.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/compandpanel.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -31,14 +31,8 @@
#include "feedback.h"
#include "multicompand.h"
#include "compandpanel.h"
+#include "config.h"
-extern int input_ch;
-extern int input_size;
-extern int input_rate;
-
-extern multicompand_settings multi_master_set;
-extern multicompand_settings *multi_channel_set;
-
typedef struct {
GtkWidget *label;
GtkWidget *slider;
@@ -49,11 +43,13 @@
} cbar;
typedef struct{
+ Multibar *s;
Readout *r;
sig_atomic_t *v;
} callback_arg_rv;
typedef struct{
+ Multibar *s;
Readout *r0;
Readout *r1;
sig_atomic_t *v0;
@@ -66,6 +62,21 @@
} callback_arg_mi;
typedef struct multi_panel_state{
+ subpanel_generic *panel;
+
+ GtkWidget *over_rms;
+ GtkWidget *over_peak;
+ GtkWidget *over_softknee;
+
+ GtkWidget *under_rms;
+ GtkWidget *under_peak;
+ GtkWidget *under_softknee;
+
+ GtkWidget *base_rms;
+ GtkWidget *base_peak;
+
+ GtkWidget *octave[3];
+
callback_arg_rv over_compand;
callback_arg_rv under_compand;
callback_arg_rv base_compand;
@@ -92,6 +103,127 @@
static multi_panel_state *master_panel;
static multi_panel_state **channel_panel;
+
+static void compandpanel_state_to_config_helper(int bank,multicompand_settings *s,int A){
+ int i;
+ config_set_integer("multicompand_active",bank,A,0,0,0,s->panel_active);
+ config_set_integer("multicompand_freqbank",bank,A,0,0,0,s->active_bank);
+ for(i=0;i<multicomp_banks;i++){
+ config_set_vector("multicompand_under_thresh",bank,A,i,0,multicomp_freqs_max,s->bc[i].static_u);
+ config_set_vector("multicompand_over_thresh",bank,A,i,0,multicomp_freqs_max,s->bc[i].static_o);
+ }
+
+ config_set_integer("multicompand_over_set",bank,A,0,0,0,s->over_mode);
+ config_set_integer("multicompand_over_set",bank,A,0,0,1,s->over_softknee);
+ config_set_integer("multicompand_over_set",bank,A,0,0,2,s->over_ratio);
+ config_set_integer("multicompand_over_set",bank,A,0,0,3,s->over_attack);
+ config_set_integer("multicompand_over_set",bank,A,0,0,4,s->over_decay);
+ config_set_integer("multicompand_over_set",bank,A,0,0,5,s->over_lookahead);
+
+ config_set_integer("multicompand_under_set",bank,A,0,0,0,s->under_mode);
+ config_set_integer("multicompand_under_set",bank,A,0,0,1,s->under_softknee);
+ config_set_integer("multicompand_under_set",bank,A,0,0,2,s->under_ratio);
+ config_set_integer("multicompand_under_set",bank,A,0,0,3,s->under_attack);
+ config_set_integer("multicompand_under_set",bank,A,0,0,4,s->under_decay);
+ config_set_integer("multicompand_under_set",bank,A,0,0,5,s->under_lookahead);
+
+ config_set_integer("multicompand_base_set",bank,A,0,0,0,s->base_mode);
+ config_set_integer("multicompand_base_set",bank,A,0,0,2,s->base_ratio);
+ config_set_integer("multicompand_base_set",bank,A,0,0,3,s->base_attack);
+ config_set_integer("multicompand_base_set",bank,A,0,0,4,s->base_decay);
+}
+
+void compandpanel_state_to_config(int bank){
+ int i;
+ compandpanel_state_to_config_helper(bank,&multi_master_set,0);
+ for(i=0;i<input_ch;i++)
+ compandpanel_state_to_config_helper(bank,multi_channel_set+i,i+1);
+}
+
+static void static_octave(GtkWidget *w,gpointer in);
+static void compandpanel_state_from_config_helper(int bank,multicompand_settings *s,
+ multi_panel_state *p,int A){
+
+ int i;
+ config_get_sigat("multicompand_active",bank,A,0,0,0,&s->panel_active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->panel->subpanel_activebutton[0]),s->panel_active);
+
+ config_get_sigat("multicompand_freqbank",bank,A,0,0,0,&s->active_bank);
+ for(i=0;i<multicomp_banks;i++){
+ config_get_vector("multicompand_under_thresh",bank,A,i,0,multicomp_freqs_max,s->bc[i].static_u);
+ config_get_vector("multicompand_over_thresh",bank,A,i,0,multicomp_freqs_max,s->bc[i].static_o);
+ }
+
+ config_get_sigat("multicompand_over_set",bank,A,0,0,0,&s->over_mode);
+ if(s->over_mode)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->over_peak),1);
+ else
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->over_rms),1);
+
+ config_get_sigat("multicompand_over_set",bank,A,0,0,1,&s->over_softknee);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->over_softknee),s->over_softknee);
+ config_get_sigat("multicompand_over_set",bank,A,0,0,2,&s->over_ratio);
+ multibar_thumb_set(p->over_compand.s,1000./s->over_ratio,0);
+ config_get_sigat("multicompand_over_set",bank,A,0,0,3,&s->over_attack);
+ multibar_thumb_set(p->over_timing.s,s->over_attack*.1,0);
+ config_get_sigat("multicompand_over_set",bank,A,0,0,4,&s->over_decay);
+ multibar_thumb_set(p->over_timing.s,s->over_decay*.1,1);
+ config_get_sigat("multicompand_over_set",bank,A,0,0,5,&s->over_lookahead);
+ multibar_thumb_set(p->over_lookahead.s,s->over_lookahead*.1,0);
+
+ config_get_sigat("multicompand_under_set",bank,A,0,0,0,&s->under_mode);
+ if(s->under_mode)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->under_peak),1);
+ else
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->under_rms),1);
+
+ config_get_sigat("multicompand_under_set",bank,A,0,0,1,&s->under_softknee);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->under_softknee),s->under_softknee);
+ config_get_sigat("multicompand_under_set",bank,A,0,0,2,&s->under_ratio);
+ multibar_thumb_set(p->under_compand.s,1000./s->under_ratio,0);
+ config_get_sigat("multicompand_under_set",bank,A,0,0,3,&s->under_attack);
+ multibar_thumb_set(p->under_timing.s,s->under_attack*.1,0);
+ config_get_sigat("multicompand_under_set",bank,A,0,0,4,&s->under_decay);
+ multibar_thumb_set(p->under_timing.s,s->under_decay*.1,1);
+ config_get_sigat("multicompand_under_set",bank,A,0,0,5,&s->under_lookahead);
+ multibar_thumb_set(p->under_lookahead.s,s->under_lookahead*.1,0);
+
+ config_get_sigat("multicompand_base_set",bank,A,0,0,0,&s->base_mode);
+ if(s->base_mode)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->base_peak),1);
+ else
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->base_rms),1);
+ config_get_sigat("multicompand_base_set",bank,A,0,0,2,&s->base_ratio);
+ multibar_thumb_set(p->base_compand.s,1000./s->base_ratio,0);
+ config_get_sigat("multicompand_base_set",bank,A,0,0,3,&s->base_attack);
+ multibar_thumb_set(p->base_timing.s,s->base_attack*.1,0);
+ config_get_sigat("multicompand_base_set",bank,A,0,0,4,&s->base_decay);
+ multibar_thumb_set(p->base_timing.s,s->base_decay*.1,1);
+
+ /* setting the active bank also redisplays all the sliders */
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->octave[s->active_bank]),1);
+ /* safe to call blindly; if the above already triggered the work, this is a no op */
+ switch(s->active_bank){
+ case 0:
+ static_octave(0,&p->octave_full);
+ break;
+ case 1:
+ static_octave(0,&p->octave_half);
+ break;
+ case 2:
+ static_octave(0,&p->octave_third);
+ break;
+ }
+}
+
+void compandpanel_state_from_config(int bank){
+ int i;
+ compandpanel_state_from_config_helper(bank,&multi_master_set,master_panel,0);
+ for(i=0;i<input_ch;i++)
+ compandpanel_state_from_config_helper(bank,multi_channel_set+i,channel_panel[i],i+1);
+}
+
+
static void compand_change(GtkWidget *w,gpointer in){
callback_arg_rv *ca=(callback_arg_rv *)in;
char buffer[80];
@@ -509,10 +641,11 @@
float per_levels[9]={0,12.5,25,37.5,50,62.5,75,87.5,100};
char *per_labels[9]={"0%","","25%","","50%","","75%","","100%"};
- multi_panel_state *ps=calloc(1,sizeof(multi_panel_state));
+ multi_panel_state *ps=calloc(1,sizeof(*ps));
ps->inactive_updatep=1;
ps->bank_active=2;
ps->ms=ms;
+ ps->panel=panel;
GtkWidget *hbox=gtk_hbox_new(0,0);
GtkWidget *sliderbox=gtk_vbox_new(0,0);
@@ -590,6 +723,10 @@
gtk_container_set_border_width(GTK_CONTAINER(sliderframe),4);
+ ps->octave[0]=octave_a;
+ ps->octave[1]=octave_b;
+ ps->octave[2]=octave_c;
+
}
gtk_box_pack_start(GTK_BOX(panel->subpanel_box),hbox,0,0,0);
@@ -637,6 +774,9 @@
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);
+ ps->under_rms=rms_button;
+ ps->under_peak=peak_button;
+ ps->under_softknee=knee_button;
}
/* under compand: ratio */
@@ -646,6 +786,7 @@
GtkWidget *readout=readout_new("1.55:1");
GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1);
+ ps->under_compand.s=MULTIBAR(slider);
ps->under_compand.r=READOUT(readout);
ps->under_compand.v=&ps->ms->under_ratio;
@@ -669,6 +810,7 @@
GtkWidget *readout1=readout_new(" 100ms");
GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2);
+ ps->under_timing.s=MULTIBAR(slider);
ps->under_timing.r0=READOUT(readout0);
ps->under_timing.r1=READOUT(readout1);
ps->under_timing.v0=&ps->ms->under_attack;
@@ -695,6 +837,7 @@
GtkWidget *readout=readout_new("100%");
GtkWidget *slider=multibar_slider_new(9,per_labels,per_levels,1);
+ ps->under_lookahead.s=MULTIBAR(slider);
ps->under_lookahead.r=READOUT(readout);
ps->under_lookahead.v=&ps->ms->under_lookahead;
@@ -733,6 +876,9 @@
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);
+ ps->over_rms=rms_button;
+ ps->over_peak=peak_button;
+ ps->over_softknee=knee_button;
}
/* over compand: ratio */
@@ -742,6 +888,7 @@
GtkWidget *readout=readout_new("1.55:1");
GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1);
+ ps->over_compand.s=MULTIBAR(slider);
ps->over_compand.r=READOUT(readout);
ps->over_compand.v=&ps->ms->over_ratio;
@@ -765,6 +912,7 @@
GtkWidget *readout1=readout_new(" 100ms");
GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2);
+ ps->over_timing.s=MULTIBAR(slider);
ps->over_timing.r0=READOUT(readout0);
ps->over_timing.r1=READOUT(readout1);
ps->over_timing.v0=&ps->ms->over_attack;
@@ -791,6 +939,7 @@
GtkWidget *readout=readout_new("100%");
GtkWidget *slider=multibar_slider_new(9,per_labels,per_levels,1);
+ ps->over_lookahead.s=MULTIBAR(slider);
ps->over_lookahead.r=READOUT(readout);
ps->over_lookahead.v=&ps->ms->over_lookahead;
@@ -825,6 +974,8 @@
G_CALLBACK (mode_peak), &ps->ms->base_mode);
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);
+ ps->base_rms=rms_button;
+ ps->base_peak=peak_button;
}
/* base compand: ratio */
@@ -834,6 +985,7 @@
GtkWidget *readout=readout_new("1.55:1");
GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1);
+ ps->base_compand.s=MULTIBAR(slider);
ps->base_compand.r=READOUT(readout);
ps->base_compand.v=&ps->ms->base_ratio;
@@ -857,6 +1009,7 @@
GtkWidget *readout1=readout_new(" 100ms");
GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2);
+ ps->base_timing.s=MULTIBAR(slider);
ps->base_timing.r0=READOUT(readout0);
ps->base_timing.r1=READOUT(readout1);
ps->base_timing.v0=&ps->ms->base_attack;
Modified: trunk/postfish/compandpanel.h
===================================================================
--- trunk/postfish/compandpanel.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/compandpanel.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -31,5 +31,7 @@
extern void compandpanel_feedback(int displayit);
extern void compandpanel_reset(void);
+extern void compandpanel_state_to_config(int bank);
+extern void compandpanel_state_from_config(int bank);
Added: trunk/postfish/config.c
===================================================================
--- trunk/postfish/config.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/config.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -0,0 +1,264 @@
+/*
+ *
+ * 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 "config.h"
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+typedef struct {
+ char *key;
+ int bank;
+ int A;
+ int B;
+ int C;
+ int vals;
+ int *vec;
+ char *string;
+} configentry;
+
+static int configentries=0;
+static configentry *config_list=0;
+
+static int look_for_key(char *key,int bank,int A, int B, int C){
+ int i;
+ for(i=0;i<configentries;i++)
+ if(!strcmp(key,config_list[i].key) &&
+ config_list[i].bank==bank &&
+ config_list[i].A==A &&
+ config_list[i].B==B &&
+ config_list[i].C==C)return i;
+ return -1;
+}
+
+/* query the loaded config; this is just an interface to pre-parsed
+ input */
+const char *config_get_string(char *key,int bank, int A, int B, int C){
+ int i=look_for_key(key,bank,A,B,C);
+ if(i==-1)return NULL;
+
+ return config_list[i].string;
+}
+
+int config_get_integer(char *key,int bank, int A, int B, int C,int valnum, int *val){
+ int i=look_for_key(key,bank,A,B,C);
+ if(i==-1)return -1;
+ if(valnum<config_list[i].vals){
+ *val=config_list[i].vec[valnum];
+ return 0;
+ }
+ return -1;
+}
+
+int config_get_sigat(char *key,int bank, int A, int B, int C,int valnum, sig_atomic_t *val){
+ int ival=*val;
+ int ret=config_get_integer(key, bank, A, B, C,valnum, &ival);
+ *val=ival;
+ return ret;
+}
+
+int config_get_vector(char *key,int bank, int A, int B, int C,int n, sig_atomic_t *v){
+ int i=look_for_key(key,bank,A,B,C),j;
+ if(i==-1)return -1;
+
+ for(j=0;j<n && j<config_list[i].vals;j++)
+ v[j]=config_list[i].vec[j];
+ return 0;
+}
+
+static configentry *old_or_new(char *key,int bank,int A, int B, int C){
+ int i=look_for_key(key,bank,A,B,C);
+
+ if(i==-1){
+ /* create a new entry */
+ i=configentries;
+ configentries++;
+ if(config_list){
+ config_list=realloc(config_list,sizeof(*config_list)*configentries);
+ memset(&config_list[i],0,sizeof(*config_list));
+ }else{
+ config_list=calloc(1,sizeof(*config_list));
+ }
+ config_list[i].key=strdup(key);
+ config_list[i].bank=bank;
+ config_list[i].A=A;
+ config_list[i].B=B;
+ config_list[i].C=C;
+ }
+ return config_list+i;
+}
+
+static void extend_vec(configentry *c,int n){
+ if(n>c->vals){
+ if(!c->vec)
+ c->vec=calloc(n,sizeof(*c->vec));
+ else{
+ c->vec=realloc(c->vec,n*sizeof(*c->vec));
+ memset(c->vec+c->vals,0,(n-c->vals)*sizeof(*c->vec));
+ }
+ c->vals=n;
+ }
+}
+
+/* dump changes back into existing local config state; this is mostly
+ an elaborate means of meging changes into an existing file that may
+ be a superset of what's currently running */
+void config_set_string(char *key,int bank, int A, int B, int C, const char *s){
+ configentry *c=old_or_new(key,bank,A,B,C);
+ c->string=strdup(s);
+}
+
+void config_set_integer(char *key,int bank, int A, int B, int C, int valnum, int val){
+ configentry *c=old_or_new(key,bank,A,B,C);
+ extend_vec(c,valnum+1);
+ c->vec[valnum]=val;
+}
+
+void config_set_vector(char *key,int bank, int A, int B, int C,int n, sig_atomic_t *v){
+ int i;
+ configentry *c=old_or_new(key,bank,A,B,C);
+ extend_vec(c,n);
+ for(i=0;i<n;i++)
+ c->vec[i]=v[i];
+}
+
+int config_load(char *filename){
+ FILE *f=fopen(filename,"r");
+ char key[80];
+ int bank,A,B,C,width,rev;
+ int errflag=0;
+
+ fprintf(stderr,"Loading state configuration file %s... ",filename);
+
+ sprintf(key,"[file beginning]");
+
+ if(!f){
+ fprintf(stderr,"No config file %s; will be created on save/exit.\n",filename);
+ return 0;
+ }
+
+ /* search for magic */
+ if(fscanf(f,"Postfish rev %d",&rev)!=1 || rev!=2){
+ fprintf(stderr,"File %s is not a postfish state configuration file.\n",filename);
+ fclose(f);
+ return -1;
+ }
+
+ /* load file */
+ while(!feof(f)){
+ int c=fgetc(f);
+ switch(c){
+ case '(': /* string type input */
+
+ if (fscanf(f,"%79s bank%d A%d B%d C%d l%d \"",
+ key,&bank,&A,&B,&C,&width)==6){
+ char *buffer=calloc(width+1,sizeof(*buffer));
+ for(c=0;c<width;c++)buffer[c]=fgetc(f);
+
+ config_set_string(key,bank,A,B,C,buffer);
+ free(buffer);
+ fscanf(f,"\" )");
+ errflag=0;
+ }else{
+ if(!errflag){
+ fprintf(stderr,"Configuration file parse error after %s\n",key);
+ errflag=1;
+ }
+ }
+
+ break;
+ case '[': /* vector type input */
+ if (fscanf(f,"%79s bank%d A%d B%d C%d v%d \"",
+ key,&bank,&A,&B,&C,&width)==6){
+ int *vec=calloc(width,sizeof(*vec));
+ for(c=0;c<width;c++){
+ if(fscanf(f,"%d",vec+c)!=1){
+ if(!errflag){
+ fprintf(stderr,"Configuration file parse error after %s\n",key);
+ errflag=1;
+ break;
+ }
+ }
+ }
+ fscanf(f," ]");
+
+ config_set_vector(key,bank,A,B,C,width,vec);
+ free(vec);
+ errflag=0;
+ }else{
+ if(!errflag){
+ fprintf(stderr,"Configuration file parse error after %s\n",key);
+ errflag=1;
+ }
+ }
+
+ break;
+ default:
+ /* whitespace OK, other characters indicate a parse error */
+ if(!isspace(c) && !errflag && c!=EOF){
+ fprintf(stderr,"Configuration file parse error after %s\n",key);
+ errflag=1;
+ }
+
+ break;
+ }
+ }
+
+ fclose(f);
+ fprintf(stderr,"done.\n");
+ return 0;
+}
+
+/* save the config */
+void config_save(char *filename){
+ int i,j;
+ FILE *f=fopen(filename,"w");
+
+ fprintf(stderr,"Saving state to %s ...",filename);
+
+ if(!f){
+ fprintf(stderr,"\nUnable to save config file %s: %s\n",filename,strerror(errno));
+ return;
+ }
+
+ fprintf(f,"Postfish rev 2\n");
+
+ for(i=0;i<configentries;i++){
+ configentry *c=config_list+i;
+ if(c->string)
+ fprintf(f,"(%s bank%d A%d B%d C%d l%d \"%s\" )\n",
+ c->key,c->bank,c->A,c->B,c->C,strlen(c->string),c->string);
+ if(c->vec){
+ fprintf(f,"[%s bank%d A%d B%d C%d v%d ",
+ c->key,c->bank,c->A,c->B,c->C,c->vals);
+ for(j=0;j<c->vals;j++)
+ fprintf(f,"%d ",c->vec[j]);
+
+ fprintf(f,"]\n");
+ }
+ }
+ fclose(f);
+ fprintf(stderr," done.\n");
+}
+
Added: trunk/postfish/config.h
===================================================================
--- trunk/postfish/config.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/config.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -0,0 +1,32 @@
+/*
+ *
+ * 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 const char *config_get_string(char *key,int bank, int A, int B, int C);
+extern int config_get_integer(char *key,int bank, int A, int B, int C,int valnum, int *val);
+extern int config_get_sigat(char *key,int bank, int A, int B, int C,int valnum, sig_atomic_t *val);
+extern int config_get_vector(char *key,int bank, int A, int B, int C,int n, sig_atomic_t *v);
+extern void config_set_string(char *key,int bank, int A, int B, int C, const char *s);
+extern void config_set_vector(char *key,int bank, int A, int B, int C,int n, sig_atomic_t *v);
+extern void config_set_integer(char *key,int bank, int A, int B, int C, int valnum, int val);
+extern int config_load(char *filename);
+extern void config_save(char *filename);
Modified: trunk/postfish/declip.c
===================================================================
--- trunk/postfish/declip.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/declip.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -31,7 +31,6 @@
extern int input_rate;
extern int input_ch;
extern int input_size;
-extern int inbytes;
/* accessed only in playback thread/setup */
@@ -60,10 +59,10 @@
sig_atomic_t declip_visible=0;
-static float *chtrigger=0;
-static sig_atomic_t pending_blocksize=0;
-static float convergence=0.;
-static float iterations=0.;
+sig_atomic_t *declip_chtrigger=0;
+sig_atomic_t declip_pending_blocksize=0;
+sig_atomic_t declip_convergence=0;
+sig_atomic_t declip_iterations=0;
/* feedback! */
typedef struct declip_feedback{
@@ -152,9 +151,9 @@
int i,j;
declip_active=calloc(input_ch,sizeof(*declip_active));
declip_prev_active=calloc(input_ch,sizeof(*declip_prev_active));
- chtrigger=malloc(input_ch*sizeof(*chtrigger));
+ declip_chtrigger=malloc(input_ch*sizeof(*declip_chtrigger));
for(i=0;i<input_ch;i++)
- chtrigger[i]=1.;
+ declip_chtrigger[i]=10000;
out.channels=input_ch;
out.data=malloc(input_ch*sizeof(*out.data));
@@ -170,7 +169,7 @@
for(i=0;i<input_ch;i++)
lap[i]=malloc(input_size*sizeof(**lap));
- window=malloc(input_size*2*sizeof(window));
+ window=malloc(input_size*2*sizeof(*window));
{
/* alloc for largest possible blocksize */
@@ -178,8 +177,8 @@
int loestpad=1-rint(fromBark(toBark(0.)-width)*blocksize*2/input_rate);
int hiestpad=rint(fromBark(toBark(input_rate*.5)+width)*blocksize*2/input_rate)+loestpad;
widthlookup=malloc((hiestpad+1)*sizeof(*widthlookup));
- freq=fftwf_malloc((blocksize*2+2)*sizeof(freq));
- work=fftwf_malloc((blocksize*2)*sizeof(freq));
+ freq=fftwf_malloc((blocksize*2+2)*sizeof(*freq));
+ work=fftwf_malloc((blocksize*2)*sizeof(*work));
for(i=0,j=32;j<=blocksize*2;i++,j*=2){
fftwf_weight=fftwf_plan_dft_r2c_1d(j,work,
@@ -190,39 +189,10 @@
}
reconstruct_init(32,input_size*4);
- pending_blocksize=input_size*2;
+ declip_pending_blocksize=input_size*2;
return(0);
}
-int declip_setblock(int n){
- if(n<32)return -1;
- if(n>input_size*2)return -1;
- pending_blocksize=n;
- return 0;
-}
-
-int declip_settrigger(float trigger,int ch){
- if(ch<0 || ch>=input_ch)return -1;
- pthread_mutex_lock(&master_mutex);
- chtrigger[ch]=trigger-(1./(1<<(inbytes*8-1)))-(1./(1<<(inbytes*8-2)));
- pthread_mutex_unlock(&master_mutex);
- return 0;
-}
-
-int declip_setiterations(float it){
- pthread_mutex_lock(&master_mutex);
- iterations=it;
- pthread_mutex_unlock(&master_mutex);
- return 0;
-}
-
-int declip_setconvergence(float c){
- pthread_mutex_lock(&master_mutex);
- convergence=c;
- pthread_mutex_unlock(&master_mutex);
- return 0;
-}
-
/* called only in playback thread */
int declip_reset(void){
/* reset cached pipe state */
@@ -312,17 +282,16 @@
int total[input_ch];
float peak[input_ch];
u_int32_t active=0;
- int next_blocksize=pending_blocksize;
+ int next_blocksize=declip_pending_blocksize;
int orig_blocksize;
float local_convergence;
float local_iterations;
- pthread_mutex_lock(&master_mutex);
- local_convergence=convergence;
- local_iterations=iterations;
- memcpy(local_trigger,chtrigger,sizeof(local_trigger));
- pthread_mutex_unlock(&master_mutex);
+ for(i=0;i<input_ch;i++)
+ local_trigger[i]=declip_chtrigger[i]*.0001;
+ local_iterations=declip_iterations*.0001;
+ local_convergence=fromdB(declip_convergence*.1);
memset(count,0,sizeof(count));
memset(peak,0,sizeof(peak));
@@ -379,9 +348,9 @@
}
}
- }else{
- /* no declipping to do, so direct cache/lap buffer rotation */
+ }//else no declipping to do, so direct cache/lap buffer rotation */
+ {
float *temp=cache[i];
cache[i]=in->data[i];
in->data[i]=temp;
Modified: trunk/postfish/declip.h
===================================================================
--- trunk/postfish/declip.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/declip.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -22,10 +22,14 @@
*/
extern int declip_load(void);
-extern int declip_setblock(int n);
-extern int declip_settrigger(float trigger,int ch);
-extern int declip_setiterations(float x);
-extern int declip_setconvergence(float x);
extern int declip_reset(void);
extern time_linkage *declip_read(time_linkage *in);
extern int pull_declip_feedback(int *clip,float *peak,int *total);
+
+extern sig_atomic_t *declip_active;
+extern sig_atomic_t declip_pending_blocksize;
+extern sig_atomic_t *declip_chtrigger;
+extern sig_atomic_t declip_convergence;
+extern sig_atomic_t declip_iterations;
+extern sig_atomic_t declip_visible;
+
Modified: trunk/postfish/eq.c
===================================================================
--- trunk/postfish/eq.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/eq.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -27,8 +27,6 @@
#include "freq.h"
#include "eq.h"
-extern int input_size;
-
typedef struct{
freq_state eq;
Modified: trunk/postfish/eq.h
===================================================================
--- trunk/postfish/eq.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/eq.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -56,3 +56,7 @@
extern void eq_set(eq_settings *eq,int freq, float value);
extern time_linkage *eq_read_master(time_linkage *in);
extern time_linkage *eq_read_channel(time_linkage *in);
+
+extern eq_settings eq_master_set;
+extern eq_settings *eq_channel_set;
+
Modified: trunk/postfish/eqpanel.c
===================================================================
--- trunk/postfish/eqpanel.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/eqpanel.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -31,14 +31,8 @@
#include "feedback.h"
#include "freq.h"
#include "eq.h"
+#include "config.h"
-extern int input_ch;
-extern int input_size;
-extern int input_rate;
-
-extern eq_settings eq_master_set;
-extern eq_settings *eq_channel_set;
-
typedef struct {
GtkWidget *slider;
GtkWidget *readout;
@@ -46,9 +40,46 @@
int number;
} bar;
-static bar *m_bars;
-static bar **c_bars;
+typedef struct {
+ subpanel_generic *panel;
+ bar *bars;
+} eq_panel_state;
+static eq_panel_state *master_panel;
+static eq_panel_state **channel_panel;
+
+static void eqpanel_state_to_config_helper(int bank,eq_settings *s,int A){
+ config_set_integer("eq_active",bank,A,0,0,0,s->panel_active);
+ config_set_vector("eq_settings",bank,A,0,0,eq_freqs,s->settings);
+}
+
+void eqpanel_state_to_config(int bank){
+ int i;
+ eqpanel_state_to_config_helper(bank,&eq_master_set,0);
+ for(i=0;i<input_ch;i++)
+ eqpanel_state_to_config_helper(bank,eq_channel_set+i,i+1);
+}
+
+static void eqpanel_state_from_config_helper(int bank,eq_settings *s,
+ eq_panel_state *p,int A){
+
+ int i;
+ config_get_sigat("eq_active",bank,A,0,0,0,&s->panel_active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->panel->subpanel_activebutton[0]),s->panel_active);
+
+ config_get_vector("eq_settings",bank,A,0,0,eq_freqs,s->settings);
+ for(i=0;i<eq_freqs;i++)
+ multibar_thumb_set(MULTIBAR(p->bars[i].slider),s->settings[i]*.1,0);
+
+}
+
+void eqpanel_state_from_config(int bank){
+ int i;
+ eqpanel_state_from_config_helper(bank,&eq_master_set,master_panel,0);
+ for(i=0;i<input_ch;i++)
+ eqpanel_state_from_config_helper(bank,eq_channel_set+i,channel_panel[i],i+1);
+}
+
static void slider_change(GtkWidget *w,gpointer in){
char buffer[80];
bar *b=(bar *)in;
@@ -61,7 +92,7 @@
}
-static bar *eqpanel_create_helper(postfish_mainpanel *mp,
+static eq_panel_state *eqpanel_create_helper(postfish_mainpanel *mp,
subpanel_generic *panel,
eq_settings *es){
@@ -73,7 +104,11 @@
GtkWidget *slidertable=gtk_table_new(eq_freqs,3,0);
bar *bars=calloc(eq_freqs,sizeof(*bars));
-
+ eq_panel_state *p=calloc(1,sizeof(*p));
+
+ p->bars=bars;
+ p->panel=panel;
+
for(i=0;i<eq_freqs;i++){
const char *labeltext=eq_freq_labels[i];
@@ -104,7 +139,7 @@
gtk_box_pack_start(GTK_BOX(panel->subpanel_box),slidertable,1,1,4);
subpanel_show_all_but_toplevel(panel);
- return bars;
+ return p;
}
void eqpanel_create_master(postfish_mainpanel *mp,
@@ -118,14 +153,14 @@
"_Equalizer (master)",shortcut,
0,1);
- m_bars=eqpanel_create_helper(mp,panel,&eq_master_set);
+ master_panel=eqpanel_create_helper(mp,panel,&eq_master_set);
}
void eqpanel_create_channel(postfish_mainpanel *mp,
GtkWidget **windowbutton,
GtkWidget **activebutton){
int i;
- c_bars=malloc(input_ch*sizeof(*c_bars));
+ channel_panel=malloc(input_ch*sizeof(*channel_panel));
/* a panel for each channel */
for(i=0;i<input_ch;i++){
@@ -139,7 +174,7 @@
&eq_channel_set[i].panel_visible,
buffer,0,i,1);
- c_bars[i]=eqpanel_create_helper(mp,panel,eq_channel_set+i);
+ channel_panel[i]=eqpanel_create_helper(mp,panel,eq_channel_set+i);
}
}
@@ -161,7 +196,7 @@
if(pull_eq_feedback_master(peakfeed,rmsfeed)==1)
for(i=0;i<eq_freqs;i++)
- multibar_set(MULTIBAR(m_bars[i].slider),rmsfeed[i],peakfeed[i],
+ multibar_set(MULTIBAR(master_panel->bars[i].slider),rmsfeed[i],peakfeed[i],
OUTPUT_CHANNELS,(displayit && eq_master_set.panel_visible));
@@ -176,7 +211,7 @@
rms[j]=rmsfeed[i][j];
peak[j]=peakfeed[i][j];
- multibar_set(MULTIBAR(c_bars[j][i].slider),rms,peak,
+ multibar_set(MULTIBAR(channel_panel[j]->bars[i].slider),rms,peak,
input_ch,(displayit && eq_channel_set[j].panel_visible));
}
}
@@ -186,10 +221,10 @@
void eqpanel_reset(void){
int i,j;
for(i=0;i<eq_freqs;i++)
- multibar_reset(MULTIBAR(m_bars[i].slider));
+ multibar_reset(MULTIBAR(master_panel->bars[i].slider));
for(i=0;i<eq_freqs;i++)
for(j=0;j<input_ch;j++)
- multibar_reset(MULTIBAR(c_bars[j][i].slider));
+ multibar_reset(MULTIBAR(channel_panel[j]->bars[i].slider));
}
Modified: trunk/postfish/eqpanel.h
===================================================================
--- trunk/postfish/eqpanel.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/eqpanel.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -30,3 +30,6 @@
GtkWidget **activebutton);
extern void eqpanel_feedback(int workp);
extern void eqpanel_reset(void);
+
+extern void eqpanel_state_to_config(int bank);
+extern void eqpanel_state_from_config(int bank);
Modified: trunk/postfish/feedback.c
===================================================================
--- trunk/postfish/feedback.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/feedback.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -24,18 +24,20 @@
#include "postfish.h"
#include "feedback.h"
+static pthread_mutex_t feedback_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+
feedback_generic *feedback_new(feedback_generic_pool *pool,
feedback_generic *(*constructor)(void)){
feedback_generic *ret;
- pthread_mutex_lock(&master_mutex);
+ pthread_mutex_lock(&feedback_mutex);
if(pool->feedback_pool){
ret=pool->feedback_pool;
pool->feedback_pool=pool->feedback_pool->next;
- pthread_mutex_unlock(&master_mutex);
+ pthread_mutex_unlock(&feedback_mutex);
return ret;
}
- pthread_mutex_unlock(&master_mutex);
+ pthread_mutex_unlock(&feedback_mutex);
ret=constructor();
return ret;
@@ -45,7 +47,7 @@
feedback_generic *f){
f->next=NULL;
- pthread_mutex_lock(&master_mutex);
+ pthread_mutex_lock(&feedback_mutex);
if(!pool->feedback_list_tail){
pool->feedback_list_tail=f;
pool->feedback_list_head=f;
@@ -53,13 +55,13 @@
pool->feedback_list_head->next=f;
pool->feedback_list_head=f;
}
- pthread_mutex_unlock(&master_mutex);
+ pthread_mutex_unlock(&feedback_mutex);
}
feedback_generic *feedback_pull(feedback_generic_pool *pool){
feedback_generic *f;
- pthread_mutex_lock(&master_mutex);
+ pthread_mutex_lock(&feedback_mutex);
if(pool->feedback_list_tail){
f=pool->feedback_list_tail;
@@ -67,33 +69,33 @@
if(!pool->feedback_list_tail)pool->feedback_list_head=0;
}else{
- pthread_mutex_unlock(&master_mutex);
+ pthread_mutex_unlock(&feedback_mutex);
return 0;
}
- pthread_mutex_unlock(&master_mutex);
+ pthread_mutex_unlock(&feedback_mutex);
return(f);
}
void feedback_old(feedback_generic_pool *pool,
feedback_generic *f){
- pthread_mutex_lock(&master_mutex);
+ pthread_mutex_lock(&feedback_mutex);
f->next=pool->feedback_pool;
pool->feedback_pool=f;
- pthread_mutex_unlock(&master_mutex);
+ pthread_mutex_unlock(&feedback_mutex);
}
/* are there multiple feedback outputs waiting or just one (a metric
of 'are we behind?') */
int feedback_deep(feedback_generic_pool *pool){
if(pool){
- pthread_mutex_lock(&master_mutex);
+ pthread_mutex_lock(&feedback_mutex);
if(pool->feedback_list_tail)
if(pool->feedback_list_tail->next){
- pthread_mutex_unlock(&master_mutex);
+ pthread_mutex_unlock(&feedback_mutex);
return 1;
}
- pthread_mutex_unlock(&master_mutex);
+ pthread_mutex_unlock(&feedback_mutex);
}
return 0;
}
Modified: trunk/postfish/input.c
===================================================================
--- trunk/postfish/input.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/input.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -30,14 +30,14 @@
static off_t cursor=0;
sig_atomic_t loop_active;
-int seekable;
+int input_seekable;
int input_rate;
int input_ch;
-int inbytes;
-static int signp;
int input_size;
+pthread_mutex_t input_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+
typedef struct {
FILE *f;
@@ -45,8 +45,27 @@
off_t end;
off_t data;
+ int bytes;
+ int signp;
+ int endian;
+ char *name;
+
} file_entry;
+typedef struct{
+ int ch;
+
+ int files;
+ file_entry *file_list;
+
+ int current_file_entry_number;
+ file_entry *current_file_entry;
+
+} group_entry;
+
+static int groups=0;
+static group_entry *group_list=0;
+
typedef struct input_feedback{
feedback_generic parent_class;
off_t cursor;
@@ -56,22 +75,18 @@
static feedback_generic_pool feedpool;
-static file_entry *file_list=NULL;
-static int file_entries=0;
-static int current_file_entry_number=-1;
-static file_entry *current_file_entry=NULL;
static time_linkage out;
void input_Acursor_set(off_t c){
- pthread_mutex_lock(&master_mutex);
+ pthread_mutex_lock(&input_mutex);
Acursor=c;
- pthread_mutex_unlock(&master_mutex);
+ pthread_mutex_unlock(&input_mutex);
}
void input_Bcursor_set(off_t c){
- pthread_mutex_lock(&master_mutex);
+ pthread_mutex_lock(&input_mutex);
Bcursor=c;
- pthread_mutex_unlock(&master_mutex);
+ pthread_mutex_unlock(&input_mutex);
}
off_t input_time_to_cursor(const char *t){
@@ -125,7 +140,7 @@
if(h<0)h=0;
return ((off_t)hd + (off_t)s*100 + (off_t)m*60*100 + (off_t)h*60*60*100) *
- input_rate / 100 * inbytes * input_ch;
+ input_rate / 100;
}
void time_fix(char *buffer){
@@ -145,7 +160,6 @@
void input_cursor_to_time(off_t cursor,char *t){
int h,m,s,hd;
- cursor/=input_ch*inbytes;
h=cursor/60/60/input_rate;
cursor%=(off_t)60*60*input_rate;
@@ -159,151 +173,388 @@
time_fix(t);
}
-int input_load(int n,char *list[]){
- char *fname="stdin";
- int stdinp=0,i,j,ch=0,rate=0;
- off_t total=0;
+void input_parse(char *filename,int newgroup){
+ if(newgroup){
+ /* add a group */
+
+ if(!groups){
+ group_list=calloc(1,sizeof(*group_list));
+ }else{
+ group_list=realloc(group_list,sizeof(*group_list)*(groups+1));
+ memset(group_list+groups,0,sizeof(*group_list));
+ }
+ groups++;
+ }
+
+ {
+ group_entry *g=group_list+groups-1;
+ file_entry *fe;
+
+ if(g->files==0){
+ g->file_list=calloc(1,sizeof(*g->file_list));
+ }else{
+ g->file_list=realloc(g->file_list,
+ sizeof(*g->file_list)*(g->files+1));
+ memset(g->file_list+g->files,0,sizeof(*g->file_list));
+ }
+ fe=g->file_list+g->files;
+ g->files++;
+
+ fe->name=strdup(filename);
+ }
+}
- if(n==0){
+/* Macros to read header data */
+#define READ_U32_LE(buf) \
+ (((buf)[3]<<24)|((buf)[2]<<16)|((buf)[1]<<8)|((buf)[0]&0xff))
+
+#define READ_U16_LE(buf) \
+ (((buf)[1]<<8)|((buf)[0]&0xff))
+
+#define READ_U32_BE(buf) \
+ (((buf)[0]<<24)|((buf)[1]<<16)|((buf)[2]<<8)|((buf)[3]&0xff))
+
+#define READ_U16_BE(buf) \
+ (((buf)[0]<<8)|((buf)[1]&0xff))
+
+double read_IEEE80(unsigned char *buf){
+ int s=buf[0]&0xff;
+ int e=((buf[0]&0x7f)<<8)|(buf[1]&0xff);
+ double f=((unsigned long)(buf[2]&0xff)<<24)|
+ ((buf[3]&0xff)<<16)|
+ ((buf[4]&0xff)<<8) |
+ (buf[5]&0xff);
+
+ if(e==32767){
+ if(buf[2]&0x80)
+ return HUGE_VAL; /* Really NaN, but this won't happen in reality */
+ else{
+ if(s)
+ return -HUGE_VAL;
+ else
+ return HUGE_VAL;
+ }
+ }
+
+ f=ldexp(f,32);
+ f+= ((buf[6]&0xff)<<24)|
+ ((buf[7]&0xff)<<16)|
+ ((buf[8]&0xff)<<8) |
+ (buf[9]&0xff);
+
+ return ldexp(f, e-16446);
+}
+
+static int find_chunk(FILE *in, char *type, unsigned int *len, int endian){
+ unsigned int i;
+ unsigned char buf[8];
+
+ while(1){
+ if(fread(buf,1,8,in) <8)return 0;
+
+ if(endian)
+ *len = READ_U32_BE(buf+4);
+ else
+ *len = READ_U32_LE(buf+4);
+
+ if(memcmp(buf,type,4)){
+
+ if((*len) & 0x1)(*len)++;
+
+ for(i=0;i<*len;i++)
+ if(fgetc(in)==EOF)return 0;
+
+ }else return 1;
+ }
+}
+
+int input_load(void){
+
+ int stdinp=0,i,k;
+
+ input_ch=0;
+
+ if(groups==0){
/* look at stdin... is it a file, pipe, tty...? */
if(isatty(STDIN_FILENO)){
fprintf(stderr,
"Postfish requires input either as a list of contiguous WAV\n"
"files on the command line, or WAV data piped|redirected to\n"
- "stdin.\n");
+ "stdin. postfish -h will give more details.\n");
return 1;
}
stdinp=1; /* file coming in via stdin */
- file_entries=1;
- }else
- file_entries=n;
-
- file_list=calloc(file_entries,sizeof(file_entry));
- for(i=0;i<file_entries;i++){
- FILE *f;
- if(stdinp){
- int newfd=dup(STDIN_FILENO);
- f=fdopen(newfd,"rb");
- }else{
- f=fopen(list[i],"rb");
- fname=list[i];
- }
+ group_list=calloc(1,sizeof(*group_list));
+ group_list[0].file_list=calloc(1,sizeof(*group_list[0].file_list));
- if(f){
- unsigned char buffer[81];
- off_t filelength;
- int datap=0;
- int fmtp=0;
- file_list[i].f=f;
-
- /* parse header (well, sort of) and get file size */
- seekable=(fseek(f,0,SEEK_CUR)?0:1);
- if(!seekable){
- filelength=-1;
+ groups=1;
+ group_list[0].files=1;
+ group_list[0].file_list[0].name="stdin";
+ }
+
+ for(k=0;k<groups;k++){
+ group_entry *g=group_list+k;
+ off_t total=0;
+
+ for(i=0;i<g->files;i++){
+ file_entry *fe=g->file_list+i;
+ FILE *f;
+ char *fname="stdin";
+
+ if(stdinp){
+ int newfd=dup(STDIN_FILENO);
+ f=fdopen(newfd,"rb");
}else{
- fseek(f,0,SEEK_END);
- filelength=ftello(f);
- fseek(f,0,SEEK_SET);
+ fname=g->file_list[i].name;
+ f=fopen(fname,"rb");
}
- fread(buffer,1,12,f);
- if(strncmp(buffer,"RIFF",4) || strncmp(buffer+8,"WAVE",4)){
- fprintf(stderr,"%s: Not a WAVE file.\n",fname);
- return 1;
- }
+ /* Crappy! Use a lib to do this for pete's sake! */
+ if(f){
+ unsigned char headerid[12];
+ off_t filelength;
+ fe->f=f;
+
+ /* parse header (well, sort of) and get file size */
+ input_seekable=(fseek(f,0,SEEK_CUR)?0:1);
+ if(!input_seekable){
+ filelength=-1;
+ }else{
+ fseek(f,0,SEEK_END);
+ filelength=ftello(f);
+ fseek(f,0,SEEK_SET);
+ }
- while(fread(buffer,1,8,f)==8){
- unsigned long chunklen=
- buffer[4]|(buffer[5]<<8)|(buffer[6]<<16)|(buffer[7]<<24);
+ fread(headerid,1,12,f);
+ if(!strncmp(headerid,"RIFF",4) && !strncmp(headerid+8,"WAVE",4)){
+ unsigned int chunklen;
- if(!strncmp(buffer,"fmt ",4)){
- int ltype;
+ if(find_chunk(f,"fmt ",&chunklen,0)){
+ int ltype;
+ int lch;
+ int lrate;
+ int lbits;
+ unsigned char *buf=alloca(chunklen);
+
+ fread(buf,1,chunklen,f);
+
+ ltype = READ_U16_LE(buf);
+ lch = READ_U16_LE(buf+2);
+ lrate = READ_U32_LE(buf+4);
+ lbits = READ_U16_LE(buf+14);
+
+ if(ltype!=1){
+ fprintf(stderr,"%s:\n\tWAVE file not PCM.\n",fname);
+ return 1;
+ }
+
+ fe->bytes=(lbits+7)/8;
+ fe->signp=0;
+ fe->endian=0;
+ if(fe->bytes>1)fe->signp=1;
+
+ if(lrate<4000 || lrate>192000){
+ fprintf(stderr,"%s:\n\tSampling rate out of bounds\n",fname);
+ return 1;
+ }
+
+ if(k==0 && i==0){
+ input_rate=lrate;
+ }else if(input_rate!=lrate){
+ fprintf(stderr,"%s:\n\tInput files must all be same sampling rate.\n",fname);
+ return 1;
+ }
+
+ if(i==0){
+ g->ch=lch;
+ input_ch+=lch;
+ }else{
+ if(g->ch!=lch){
+ fprintf(stderr,"%s:\n\tInput files must all have same number of channels.\n",fname);
+ return 1;
+ }
+ }
+
+ if(find_chunk(f,"data",&chunklen,0)){
+ off_t pos=ftello(f);
+
+ if(input_seekable)
+ filelength=
+ (filelength-pos)/
+ (g->ch*fe->bytes)*
+ (g->ch*fe->bytes)+pos;
+
+ if(chunklen==0UL ||
+ chunklen==0x7fffffffUL ||
+ chunklen==0xffffffffUL){
+ if(filelength==-1){
+ fe->begin=total;
+ total=fe->end=-1;
+ fprintf(stderr,"%s: Incomplete header; assuming stream.\n",fname);
+ }else{
+ fe->begin=total;
+ total=fe->end=total+(filelength-pos)/(g->ch*fe->bytes);
+ fprintf(stderr,"%s: Incomplete header; using actual file size.\n",fname);
+ }
+ }else if(filelength==-1 || chunklen+pos<=filelength){
+ fe->begin=total;
+ total=fe->end=total+ (chunklen/(g->ch*fe->bytes));
+ fprintf(stderr,"%s: Using declared file size.\n",fname);
+
+ }else{
+ fe->begin=total;
+ total=fe->end=total+(filelength-pos)/(g->ch*fe->bytes);
+ fprintf(stderr,"%s: File truncated; Using actual file size.\n",fname);
+ }
+ fe->data=ftello(f);
+ } else {
+ fprintf(stderr,"%s: WAVE file has no \"data\" chunk following \"fmt \".\n",fname);
+ return 1;
+ }
+ }else{
+ fprintf(stderr,"%s: WAVE file has no \"fmt \" chunk.\n",fname);
+ return 1;
+ }
+
+ }else if(!strncmp(headerid,"FORM",4) && !strncmp(headerid+8,"AIF",3)){
+ unsigned int len;
+ int aifc=0;
+ if(headerid[11]=='C')aifc=1;
+ unsigned char *buffer;
+ char buf2[8];
+
int lch;
+ int lbits;
int lrate;
- int lbits;
-
- if(chunklen>80){
- fprintf(stderr,"%s: WAVE file fmt chunk too large to parse.\n",fname);
+
+ /* look for COMM */
+ if(!find_chunk(f, "COMM", &len,1)){
+ fprintf(stderr,"%s: AIFF file has no \"COMM\" chunk.\n",fname);
return 1;
}
- fread(buffer,1,chunklen,f);
- ltype=buffer[0] |(buffer[1]<<8);
- lch= buffer[2] |(buffer[3]<<8);
- lrate=buffer[4] |(buffer[5]<<8)|(buffer[6]<<16)|(buffer[7]<<24);
- lbits=buffer[14]|(buffer[15]<<8);
+ if(len < 18 || (aifc && len<22)) {
+ fprintf(stderr,"%s: AIFF COMM chunk is truncated.\n",fname);
+ return 1;
+ }
+
+ buffer = alloca(len);
- if(ltype!=1){
- fprintf(stderr,"%s: WAVE file not PCM.\n",fname);
+ if(fread(buffer,1,len,f) < len){
+ fprintf(stderr, "%s: Unexpected EOF in reading AIFF header\n",fname);
return 1;
}
+ lch = READ_U16_BE(buffer);
+ lbits = READ_U16_BE(buffer+6);
+ lrate = (int)read_IEEE80(buffer+8);
+
+ fe->endian = 1; // default
+
+ fe->bytes=(lbits+7)/8;
+ fe->signp=1;
+
+ if(lrate<4000 || lrate>192000){
+ fprintf(stderr,"%s:\n\tSampling rate out of bounds\n",fname);
+ return 1;
+ }
+
+ if(k==0 && i==0){
+ input_rate=lrate;
+ }else if(input_rate!=lrate){
+ fprintf(stderr,"%s:\n\tInput files must all be same sampling rate.\n",fname);
+ return 1;
+ }
+
if(i==0){
- ch=lch;
- rate=lrate;
- inbytes=lbits/8;
- if(inbytes>1)signp=1;
+ g->ch=lch;
+ input_ch+=lch;
}else{
- if(ch!=lch){
- fprintf(stderr,"%s: WAVE files must all have same number of channels.\n",fname);
+ if(g->ch!=lch){
+ fprintf(stderr,"%s:\n\tInput files must all have same number of channels.\n",fname);
return 1;
}
- if(rate!=lrate){
- fprintf(stderr,"%s: WAVE files must all be same sampling rate.\n",fname);
+ }
+
+ if(aifc){
+ if(!memcmp(buffer+18, "NONE", 4)) {
+ fe->endian = 1;
+ }else if(!memcmp(buffer+18, "sowt", 4)) {
+ fe->endian = 0;
+ }else{
+ fprintf(stderr, "%s: Postfish supports only linear PCM AIFF-C files.\n",fname);
return 1;
}
- if(inbytes!=lbits/8){
- fprintf(stderr,"%s: WAVE files must all be same sample width.\n",fname);
- return 1;
- }
}
- fmtp=1;
- } else if(!strncmp(buffer,"data",4)){
- off_t pos=ftello(f);
- if(!fmtp){
- fprintf(stderr,"%s: WAVE fmt chunk must preceed data chunk.\n",fname);
+
+ if(!find_chunk(f, "SSND", &len, 1)){
+ fprintf(stderr,"%s: AIFF file has no \"SSND\" chunk.\n",fname);
return 1;
}
- datap=1;
+
+ if(fread(buf2,1,8,f) < 8){
+ fprintf(stderr,"%s: Unexpected EOF reading AIFF header\n",fname);
+ return 1;
+ }
- if(seekable)
- filelength=(filelength-pos)/(ch*inbytes)*(ch*inbytes)+pos;
+ {
+ int loffset = READ_U32_BE(buf2);
+ int lblocksize = READ_U32_BE(buf2+4);
- if(chunklen==0UL ||
- chunklen==0x7fffffffUL ||
- chunklen==0xffffffffUL){
- file_list[i].begin=total;
- total=file_list[i].end=0;
- fprintf(stderr,"%s: Incomplete header; assuming stream.\n",fname);
- }else if(filelength==-1 || chunklen+pos<=filelength){
- file_list[i].begin=total;
- total=file_list[i].end=total+chunklen;
- fprintf(stderr,"%s: Using declared file size.\n",fname);
- }else{
- file_list[i].begin=total;
- total=file_list[i].end=total+filelength-pos;
- fprintf(stderr,"%s: Using actual file size.\n",fname);
+ /* swallow some data */
+ for(i=0;i<loffset;i++)
+ if(fgetc(f)==EOF)break;
+
+ if( lblocksize == 0 && (lbits == 32 || lbits == 24 || lbits == 16 || lbits == 8)){
+
+ off_t pos=ftello(f);
+
+ if(input_seekable)
+ filelength=
+ (filelength-pos)/
+ (g->ch*fe->bytes)*
+ (g->ch*fe->bytes)+pos;
+
+ if(len==0UL ||
+ len==0x7fffffffUL ||
+ len==0xffffffffUL){
+ if(filelength==-1){
+ fe->begin=total;
+ total=fe->end=-1;
+ fprintf(stderr,"%s: Incomplete header; assuming stream.\n",fname);
+ }else{
+ fe->begin=total;
+ total=fe->end=total+(filelength-pos)/(g->ch*fe->bytes);
+ fprintf(stderr,"%s: Incomplete header; using actual file size.\n",fname);
+ }
+ }else if(filelength==-1 || (len+pos-loffset-8)<=filelength){
+ fe->begin=total;
+ total=fe->end=total+ ((len-loffset-8)/(g->ch*fe->bytes));
+ fprintf(stderr,"%s: Using declared file size.\n",fname);
+
+ }else{
+ fe->begin=total;
+ total=fe->end=total+(filelength-pos)/(g->ch*fe->bytes);
+ fprintf(stderr,"%s: File truncated; Using actual file size.\n",fname);
+ }
+ fe->data=pos;
+ }else{
+ fprintf(stderr, "%s: Postfish supports only linear PCM AIFF-C files.\n",fname);
+ return 1;
+ }
}
- file_list[i].data=ftello(f);
-
- break;
+
} else {
- fprintf(stderr,"%s: Unknown chunk type %c%c%c%c; skipping.\n",fname,
- buffer[0],buffer[1],buffer[2],buffer[3]);
- for(j=0;j<(int)chunklen;j++)
- if(fgetc(f)==EOF)break;
+
+ fprintf(stderr,"%s: Postfish supports only linear PCM WAV and AIFF[-C] files.\n",fname);
+ return 1;
}
- }
- if(!datap){
- fprintf(stderr,"%s: WAVE file has no data chunk.\n",fname);
+ }else{
+ fprintf(stderr,"%s: Unable to open file.\n",fname);
return 1;
}
-
- }else{
- fprintf(stderr,"%s: Unable to open file.\n",fname);
- return 1;
}
}
@@ -326,230 +577,349 @@
4000: 256 */
- if(rate<6000){
+ if(input_rate<6000){
input_size=256;
- }else if(rate<15000){
+ }else if(input_rate<15000){
input_size=512;
- }else if(rate<25000){
+ }else if(input_rate<25000){
input_size=1024;
- }else if(rate<50000){
+ }else if(input_rate<50000){
input_size=2048;
- }else if(rate<100000){
+ }else if(input_rate<100000){
input_size=4096;
}else
input_size=8192;
- input_ch=out.channels=ch;
- input_rate=rate;
- out.data=malloc(sizeof(*out.data)*ch);
- for(i=0;i<ch;i++)
- out.data[i]=malloc(sizeof(*out.data[0])*input_size);
+ out.channels=input_ch;
+
+ out.data=malloc(sizeof(*out.data)*input_ch);
+ for(i=0;i<input_ch;i++)
+ out.data[i]=malloc(sizeof(**out.data)*input_size);
return 0;
}
-off_t input_seek(off_t pos){
- int i;
+off_t input_seek_i(off_t pos,int ps){
+ int i,k;
+ int flag=0;
+ off_t maxpos=0;
if(pos<0)pos=0;
- if(!seekable){
- current_file_entry=file_list;
- current_file_entry_number=0;
+ if(!input_seekable){
+ for(i=0;i<groups;i++){
+ group_list[i].current_file_entry=group_list[i].file_list;
+ group_list[i].current_file_entry_number=0;
+ }
return -1;
}
- for(i=0;i<file_entries;i++){
- current_file_entry=file_list+i;
- current_file_entry_number=i;
- if(current_file_entry->begin<=pos && current_file_entry->end>pos){
- fseeko(current_file_entry->f,
- pos-current_file_entry->begin+current_file_entry->data,
- SEEK_SET);
- pthread_mutex_lock(&master_mutex);
- cursor=pos;
- playback_seeking=1;
- pthread_mutex_unlock(&master_mutex);
- return cursor;
+ pthread_mutex_lock(&input_mutex);
+ if(ps)playback_seeking=1;
+
+ /* seek has to happen correctly in all groups */
+ for(k=0;k<groups;k++){
+ group_entry *g=group_list+k;
+
+ for(i=0;i<g->files;i++){
+ file_entry *fe=g->current_file_entry=g->file_list+i;
+ g->current_file_entry_number=i;
+
+ if(fe->begin<=pos && fe->end>pos){
+ flag=1;
+ fseeko(fe->f,
+ (pos-fe->begin)*(g->ch*fe->bytes)+fe->data,
+ SEEK_SET);
+ break;
+ }
}
+
+ if(i==g->files){
+ /* this group isn't that long; seek to the end of it */
+ file_entry *fe=g->current_file_entry;
+
+ fseeko(fe->f,(fe->end-fe->begin)*(g->ch*fe->bytes)+fe->data,SEEK_SET);
+
+ if(fe->end>maxpos)maxpos=fe->end;
+ }
}
- i--;
- pos=current_file_entry->end;
- fseeko(current_file_entry->f,
- pos-current_file_entry->begin+current_file_entry->data,
- SEEK_SET);
- pthread_mutex_lock(&master_mutex);
- cursor=pos;
- playback_seeking=1;
- pthread_mutex_unlock(&master_mutex);
+ if(flag){
+ cursor=pos;
+ pthread_mutex_unlock(&input_mutex);
+ }else{
+ cursor=maxpos;
+ pthread_mutex_unlock(&input_mutex);
+ }
+
return cursor;
}
+off_t input_seek(off_t pos){
+ return input_seek_i(pos,1);
+}
+
off_t input_time_seek_rel(float s){
- off_t ret;
- pthread_mutex_lock(&master_mutex);
- ret=input_seek(cursor+input_rate*inbytes*input_ch*s);
- pthread_mutex_unlock(&master_mutex);
- return ret;
+ return input_seek(cursor+input_rate*s);
}
static feedback_generic *new_input_feedback(void){
input_feedback *ret=malloc(sizeof(*ret));
- ret->rms=malloc((input_ch+2)*sizeof(*ret->rms));
- ret->peak=malloc((input_ch+2)*sizeof(*ret->peak));
+ ret->rms=malloc(input_ch*sizeof(*ret->rms));
+ ret->peak=malloc(input_ch*sizeof(*ret->peak));
return (feedback_generic *)ret;
}
static void push_input_feedback(float *peak,float *rms, off_t cursor){
- int n=input_ch+2;
input_feedback *f=(input_feedback *)
feedback_new(&feedpool,new_input_feedback);
f->cursor=cursor;
- memcpy(f->rms,rms,n*sizeof(*rms));
- memcpy(f->peak,peak,n*sizeof(*peak));
+ memcpy(f->rms,rms,input_ch*sizeof(*rms));
+ memcpy(f->peak,peak,input_ch*sizeof(*peak));
feedback_push(&feedpool,(feedback_generic *)f);
}
int pull_input_feedback(float *peak,float *rms,off_t *cursor){
input_feedback *f=(input_feedback *)feedback_pull(&feedpool);
- 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);
+ if(rms)memcpy(rms,f->rms,sizeof(*rms)*input_ch);
+ if(peak)memcpy(peak,f->peak,sizeof(*peak)*input_ch);
if(cursor)*cursor=f->cursor;
feedback_old(&feedpool,(feedback_generic *)f);
return 1;
}
+static void LEconvert(float **data,
+ unsigned char *readbuf, int dataoff,
+ int ch,int bytes, int signp, int n){
+ int i,j,k=0;
+ int32_t val;
+ int32_t xor=(signp?0:0x80000000UL);
+ float scale=1./2147483648.;
+
+ k=0;
+ switch(bytes){
+ case 1:
+
+ for(i=dataoff;i<dataoff+n;i++)
+ for(j=0;j<ch;j++){
+ val=(readbuf[k]<<24)^xor;
+ data[j][i]=(val==0x7f000000?1.:val*scale);
+ k++;
+ }
+ break;
+
+ case 2:
+
+ for(i=dataoff;i<dataoff+n;i++)
+ for(j=0;j<ch;j++){
+ val=((readbuf[k]<<16)|(readbuf[k+1]<<24))^xor;
+ data[j][i]=(val==0x7fff0000?1.:val*scale);
+ k+=2;
+ }
+ break;
+
+ case 3:
+
+ for(i=dataoff;i<dataoff+n;i++)
+ for(j=0;j<ch;j++){
+ val=((readbuf[k]<<8)|(readbuf[k+1]<<16)|(readbuf[k+2]<<24))^xor;
+ data[j][i]=(val==0x7fffff00?1.:val*scale);
+ k+=3;
+ }
+ break;
+
+ case 4:
+
+ for(i=dataoff;i<dataoff+n;i++)
+ for(j=0;j<ch;j++){
+ val=((readbuf[k])|(readbuf[k+1]<<8)|(readbuf[k+2]<<16)|(readbuf[k+3]<<24))^xor;
+ data[j][i]=(val==0x7fffffff?1.:val*scale);
+ k+=4;
+ }
+ break;
+ }
+}
+
+static void BEconvert(float **data,
+ unsigned char *readbuf, int dataoff,
+ int ch,int bytes, int signp, int n){
+ int i,j,k=0;
+ int32_t val;
+ int32_t xor=(signp?0:0x80000000UL);
+ float scale=1./2147483648.;
+
+ k=0;
+ switch(bytes){
+ case 1:
+
+ for(i=dataoff;i<dataoff+n;i++)
+ for(j=0;j<ch;j++){
+ val=(readbuf[k]<<24)^xor;
+ data[j][i]=(val==0x7f000000?1.:val*scale);
+ k++;
+ }
+ break;
+
+ case 2:
+
+ for(i=dataoff;i<dataoff+n;i++)
+ for(j=0;j<ch;j++){
+ val=((readbuf[k+1]<<16)|(readbuf[k]<<24))^xor;
+ data[j][i]=(val==0x7fff0000?1.:val*scale);
+ k+=2;
+ }
+ break;
+
+ case 3:
+
+ for(i=dataoff;i<dataoff+n;i++)
+ for(j=0;j<ch;j++){
+ val=((readbuf[k+2]<<8)|(readbuf[k+1]<<16)|(readbuf[k]<<24))^xor;
+ data[j][i]=(val==0x7fffff00?1.:val*scale);
+ k+=3;
+ }
+ break;
+
+ case 4:
+
+ for(i=dataoff;i<dataoff+n;i++)
+ for(j=0;j<ch;j++){
+ val=((readbuf[k+3])|(readbuf[k+2]<<8)|(readbuf[k+1]<<16)|(readbuf[k]<<24))^xor;
+ data[j][i]=(val==0x7fffffff?1.:val*scale);
+ k+=4;
+ }
+ break;
+ }
+}
+
+static void zero(float **data, int dataoff, int ch, int n){
+ int i,j;
+
+ for(i=dataoff;i<dataoff+n;i++)
+ for(j=0;j<ch;j++)
+ data[j][i]=0;
+}
+
+/* no locking within as the only use of input_read is locked in the
+ playback thread (must be locked there because the real lock needs
+ to avoid a seeking race) */
+
time_linkage *input_read(void){
- int read_b=0,i,j,k;
- int toread_b=input_size*out.channels*inbytes;
- unsigned char *readbuf;
- float *rms=alloca(sizeof(*rms)*(out.channels+2));
- float *peak=alloca(sizeof(*peak)*(out.channels+2));
+ int h,i,j;
+ int groupread_s=0;
- memset(rms,0,sizeof(*rms)*(out.channels+2));
- memset(peak,0,sizeof(*peak)*(out.channels+2));
+ float *rms=alloca(sizeof(*rms)*(out.channels));
+ float *peak=alloca(sizeof(*peak)*(out.channels));
- pthread_mutex_lock(&master_mutex);
+ memset(rms,0,sizeof(*rms)*(out.channels));
+ memset(peak,0,sizeof(*peak)*(out.channels));
+
out.samples=0;
/* the non-streaming case */
- if(!loop_active &&
- cursor>=current_file_entry->end &&
- current_file_entry->end!=-1){
- pthread_mutex_unlock(&master_mutex);
- goto tidy_up;
+ if(!loop_active && input_seekable){
+ for(i=0;i<groups;i++)
+ if(cursor<group_list[i].file_list[group_list[i].files-1].end)
+ break;
+ if(i==groups)goto tidy_up;
}
/* the streaming case */
- if(feof(current_file_entry->f) &&
- current_file_entry_number+1>=file_entries){
- pthread_mutex_unlock(&master_mutex);
+ if(!input_seekable && feof(group_list[0].current_file_entry->f)){
goto tidy_up;
}
- pthread_mutex_unlock(&master_mutex);
- readbuf=alloca(toread_b);
+ /* If we're A-B looping, we might need several loops/seeks */
+ while(groupread_s<input_size){
+ int chcount=0;
+ int max_read_s=0;
- while(toread_b){
- off_t ret;
- off_t read_this_loop=current_file_entry->end-cursor;
- if(read_this_loop>toread_b)read_this_loop=toread_b;
+ if(loop_active && cursor>=Bcursor){
+ input_seek_i(Acursor,0);
+ }
- ret=fread(readbuf+read_b,1,read_this_loop,current_file_entry->f);
+ /* each read section is by group */
+ for(h=0;h<groups;h++){
+ group_entry *g=group_list+h;
+ int toread_s=input_size-groupread_s;
+ int fileread_s=0;
+
+ if(input_seekable && loop_active && toread_s>Bcursor-cursor)
+ toread_s = Bcursor-cursor;
+
+ /* inner loop in case the read spans multiple files within the group */
+ while(toread_s){
+ file_entry *fe=g->current_file_entry;
+ off_t ret;
- pthread_mutex_lock(&master_mutex);
+ /* span forward to next file entry in the group? */
+ if(cursor+fileread_s>=fe->end &&
+ g->current_file_entry_number+1<g->files){
+ fe=++g->current_file_entry;
+ g->current_file_entry_number++;
+ fseeko(fe->f,fe->data,SEEK_SET);
+ }
- if(ret>0){
- read_b+=ret;
- toread_b-=ret;
- cursor+=ret;
- }else{
- if(current_file_entry_number+1>=file_entries){
+ /* perform read/conversion of this file entry */
+ {
+ off_t read_this_loop=fe->end-cursor-fileread_s;
+ unsigned char readbuf[input_size*(g->ch*fe->bytes)];
+ if(read_this_loop>toread_s)read_this_loop=toread_s;
+
+ ret=fread(readbuf,1,read_this_loop*(g->ch*fe->bytes),fe->f);
+
+ if(ret>0){
+ ret/=(g->ch*fe->bytes);
+
+ if(fe->endian)
+ BEconvert(out.data+chcount,readbuf,
+ fileread_s+groupread_s,g->ch,fe->bytes,fe->signp,ret);
+ else
+ LEconvert(out.data+chcount,readbuf,
+ fileread_s+groupread_s,g->ch,fe->bytes,fe->signp,ret);
+
+ fileread_s+=ret;
+ toread_s-=ret;
- /* end of file before full frame */
- memset(readbuf+read_b,0,toread_b);
- toread_b=0;
+ }else{
+ if(g->current_file_entry_number+1>=g->files){
+ /* end of group before full frame */
+ zero(out.data+chcount,fileread_s+groupread_s,g->ch,toread_s);
+ toread_s=0;
+ }
+ }
+ }
}
- }
- if(loop_active && cursor>=Bcursor){
- pthread_mutex_unlock(&master_mutex);
- input_seek(Acursor);
- }else{
- if(cursor>=current_file_entry->end){
- pthread_mutex_unlock(&master_mutex);
- if(current_file_entry_number+1<file_entries){
- current_file_entry_number++;
- current_file_entry++;
- fseeko(current_file_entry->f,current_file_entry->data,SEEK_SET);
- }
- }else
- pthread_mutex_unlock(&master_mutex);
+ if(max_read_s<fileread_s)max_read_s=fileread_s;
+ chcount+=g->ch;
}
- }
- out.samples=read_b/out.channels/inbytes;
-
- k=0;
- for(i=0;i<out.samples;i++){
- float mean=0.;
- float divrms=0.;
+ groupread_s+=max_read_s;
+ cursor+=max_read_s;
- for(j=0;j<out.channels;j++){
- float dval;
- long val=0;
- switch(inbytes){
- case 1:
- val=(readbuf[k]<<24);
- break;
- case 2:
- val=(readbuf[k]<<16)|(readbuf[k+1]<<24);
- break;
- case 3:
- val=(readbuf[k]<<8)|(readbuf[k+1]<<16)|(readbuf[k+2]<<24);
- break;
- case 4:
- val=(readbuf[k])|(readbuf[k+1]<<8)|(readbuf[k+2]<<16)|(readbuf[k+3]<<24);
- break;
- }
- if(signp)
- dval=out.data[j][i]=val/2147483648.;
- else
- dval=out.data[j][i]=(val^0x80000000UL)/2147483648.;
+ if(!loop_active || cursor<Bcursor) break;
- if(fabs(dval)>peak[j])peak[j]=fabs(dval);
- rms[j]+= dval*dval;
- mean+=dval;
+ }
- k+=inbytes;
- }
+ out.samples=groupread_s;
- /* mean */
- mean/=j;
- if(fabs(mean)>peak[j])peak[j]=fabs(mean);
- rms[j]+= mean*mean;
-
- /* div */
+ for(i=0;i<groupread_s;i++)
for(j=0;j<out.channels;j++){
- float dval=mean-out.data[j][i];
- if(fabs(dval)>peak[out.channels+1])peak[out.channels+1]=fabs(dval);
- divrms+=dval*dval;
+ float dval=out.data[j][i];
+ dval*=dval;
+ if(dval>peak[j])peak[j]=dval;
+ rms[j]+= dval;
}
- rms[out.channels+1]+=divrms/out.channels;
-
- }
- for(j=0;j<out.channels+2;j++){
+ for(j=0;j<out.channels;j++)
rms[j]/=out.samples;
- rms[j]=sqrt(rms[j]);
- }
push_input_feedback(peak,rms,cursor);
tidy_up:
+
{
int tozero=input_size-out.samples;
if(tozero)
@@ -567,3 +937,4 @@
+
Modified: trunk/postfish/input.h
===================================================================
--- trunk/postfish/input.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/input.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -5,7 +5,8 @@
extern void time_fix(char *buffer);
extern off_t input_seek(off_t pos);
extern time_linkage *input_read(void);
-extern int input_load(int n,char *list[]);
+extern void input_parse(char *filename,int newgroup);
+extern int input_load(void);
extern int pull_input_feedback(float *peak,float *rms,off_t *cursor);
extern void input_reset(void);
extern off_t input_time_seek_rel(float s);
Modified: trunk/postfish/limit.c
===================================================================
--- trunk/postfish/limit.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/limit.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -41,6 +41,9 @@
int prev_active;
int initted;
+
+ float pthresh;
+ float pdepth;
} limit_state;
limit_settings limitset;
@@ -109,7 +112,7 @@
int limit_reset(void){
/* reset cached pipe state */
while(pull_limit_feedback(NULL,NULL));
- memset(limitstate.iir,0,limitstate.out.channels*sizeof(&limitstate.iir));
+ memset(limitstate.iir,0,limitstate.out.channels*sizeof(*limitstate.iir));
limitstate.initted=0;
return 0;
}
@@ -133,6 +136,7 @@
float thresh=limitset.thresh/10.-.01;
float depth=limitset.depth;
+
float localpeak;
float localatt;
@@ -144,14 +148,17 @@
return &limitstate.out;
}
+ depth=depth*.2;
+ depth*=depth;
+
if(!limitstate.initted){
limitstate.initted=1;
limitstate.prev_active=activeC;
+
+ limitstate.pthresh=thresh;
+ limitstate.pdepth=depth;
}
- depth=depth*.2;
- depth*=depth;
-
for(i=0;i<ch;i++){
localpeak=0.;
localatt=0.;
@@ -162,16 +169,26 @@
float *inx=in->data[i];
float *x=limitstate.out.data[i];
+
+ float prev_thresh=limitstate.pthresh;
+ float prev_depth=limitstate.pdepth;
+
+ float thresh_add=(thresh-prev_thresh)/input_size;
+ float depth_add=(depth-prev_depth)/input_size;
+
/* '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 knee=limit_knee(dB-prev_thresh,prev_depth)+prev_thresh;
float att=dB-knee;
if(att>localatt)localatt=att;
x[k]=att;
+
+ prev_depth+=depth_add;
+ prev_thresh+=thresh_add;
}
compute_iir_decayonly2(x,input_size,limitstate.iir+i,&limitstate.decay);
@@ -242,6 +259,9 @@
limitstate.out.active=in->active;
limitstate.prev_active=activeC;
+ limitstate.pthresh=thresh;
+ limitstate.pdepth=depth;
+
return &limitstate.out;
}
Modified: trunk/postfish/limit.h
===================================================================
--- trunk/postfish/limit.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/limit.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -31,3 +31,7 @@
extern int limit_load(int ch);
extern int limit_reset(void);
extern time_linkage *limit_read(time_linkage *in);
+
+extern sig_atomic_t limit_active;
+extern sig_atomic_t limit_visible;
+extern limit_settings limitset;
Modified: trunk/postfish/limitpanel.c
===================================================================
--- trunk/postfish/limitpanel.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/limitpanel.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -31,17 +31,35 @@
#include "feedback.h"
#include "limit.h"
#include "limitpanel.h"
+#include "config.h"
-extern sig_atomic_t limit_active;
-extern sig_atomic_t limit_visible;
-extern int input_size;
-extern int input_rate;
-
-extern limit_settings limitset;
-
+static GtkWidget *active;
static GtkWidget *t_slider;
+static GtkWidget *k_slider;
+static GtkWidget *d_slider;
static GtkWidget *a_slider;
+void limitpanel_state_to_config(int bank){
+ config_set_integer("limit_active",bank,0,0,0,0,limit_active);
+ config_set_integer("limit_set",bank,0,0,0,0,limitset.thresh);
+ config_set_integer("limit_set",bank,0,0,0,1,limitset.depth);
+ config_set_integer("limit_set",bank,0,0,0,2,limitset.decay);
+}
+
+void limitpanel_state_from_config(int bank){
+ config_get_sigat("limit_active",bank,0,0,0,0,&limit_active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(active),limit_active);
+
+ config_get_sigat("limit_set",bank,0,0,0,0,&limitset.thresh);
+ multibar_thumb_set(MULTIBAR(t_slider),limitset.thresh*.1,0);
+
+ config_get_sigat("limit_set",bank,0,0,0,1,&limitset.depth);
+ multibar_thumb_set(MULTIBAR(k_slider),limitset.depth*.1,0);
+
+ config_get_sigat("limit_set",bank,0,0,0,2,&limitset.decay);
+ multibar_thumb_set(MULTIBAR(d_slider),limitset.decay*.1,0);
+}
+
static void limit_change(GtkWidget *w,gpointer in){
char buffer[80];
Readout *r=(Readout *)in;
@@ -126,9 +144,14 @@
GtkWidget *slider2=multibar_slider_new(5,labels2,levels2,1);
GtkWidget *slider3=multibar_slider_new(6,timing_labels,timing_levels,1);
+ active=activebutton;
+
t_slider=multibar_new(9,labels,levels,1,HI_DECAY);
a_slider=multibar_new(4,rlabels,rlevels,0,0);
+ k_slider=slider2;
+ d_slider=slider3;
+
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);
Modified: trunk/postfish/limitpanel.h
===================================================================
--- trunk/postfish/limitpanel.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/limitpanel.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -28,3 +28,5 @@
extern void limitpanel_reset(void);
+extern void limitpanel_state_to_config(int bank);
+extern void limitpanel_state_from_config(int bank);
Modified: trunk/postfish/main.c
===================================================================
--- trunk/postfish/main.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/main.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -28,8 +28,11 @@
/* sound playback code is OSS-specific for now */
#include "postfish.h"
+#include <signal.h>
+#include <getopt.h>
#include <fenv.h> // Thank you C99!
#include <fftw3.h>
+#include <gtk/gtk.h>
#include "input.h"
#include "output.h"
#include "declip.h"
@@ -41,19 +44,168 @@
#include "mute.h"
#include "mix.h"
#include "reverb.h"
+#include "version.h"
+#include "config.h"
+#include "mainpanel.h"
-pthread_mutex_t master_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
-
-int outfileno=-1;
int eventpipe[2];
+sig_atomic_t main_looping;
+char *configfile="postfish-staterc";
+char *version;
+static void cleanup(void){
+ save_state();
+}
+
+void clean_exit(int sig){
+ signal(sig,SIG_IGN);
+ if(sig!=SIGINT){
+ fprintf(stderr,
+ "\nTrapped signal %d; saving state and exiting!\n"
+ "This signal almost certainly indicates a bug in the Postfish;\n"
+ "If this version of Postfish is newer than a few months old,\n"
+ "please email a detailed report of the crash along with\n"
+ "processor type, OS version, FFTW3 version, and as much\n"
+ "information as possible about what caused the crash. The best\n"
+ "possible report will outline the exact steps needed to\n"
+ "reproduce the error, ensuring that we at Xiph can fix the\n"
+ "bug as quickly as possible.\n\n"
+ "-- monty at xiph.org, Postfish revision %s\n\n",sig,version);
+ configfile="postfish-staterc-crashsave";
+ cleanup();
+ exit(0);
+
+ }
+
+ /* otherwise we want a clean SIGINT exit */
+ if(main_looping)
+ gtk_main_quit();
+ else{
+ cleanup();
+ exit(0);
+ }
+}
+
+const char *optstring = "-c:gh";
+
+struct option options [] = {
+ {"configuration-file",required_argument,NULL,'c'},
+ {"group",no_argument,NULL,'g'},
+ {"help",no_argument,NULL,'h'},
+
+ {NULL,0,NULL,0}
+};
+
+static void usage(FILE *f){
+ fprintf( f,
+"\nthe Postfish, revision %s\n\n"
+
+"USAGE:\n"
+" postfish [options] infile [infile]+ [-g infile [infile]+]+ > output\n\n"
+
+"OPTIONS:\n"
+" -c --configuration-file : load state from alternate configuration file\n"
+" -g --group : place following input files in a new channel\n"
+" grouping\n"
+" -h --help : print this help\n\n"
+"INPUT:\n\n"
+
+" Postfish takes WAV/AIFF input either from stdin or from a list of files\n"
+" specified on the command line. A list of input files is handled as\n"
+" time-continguous entries, each holding audio data that continues at\n"
+" the instant the previous file ends. Files may also be arranged into\n"
+" groups with -g; each group represents additional input channels\n"
+" parallel to preceeding groups. All input files must be the same\n"
+" sampling rate. Files in a group must have the same number of\n"
+" channels.\n\n"
+
+" Examples:\n\n"
+" Files a.wav, b.wav, c.wav and d.wav are all four channels and\n"
+" ten minutes each.\n\n"
+
+" postfish a.wav b.wav c.wav d.wav \n"
+" This command line treats the input as forty minutes of four channel\n"
+" audio in the order a.wav, b.wav, c.wav, d.wav.\n\n"
+
+" postfish a.wav b.wav -g c.wav d.wav \n"
+" This command line treats the input as twenty minutes of eight channel\n"
+" audio. Channels 1-4 are taken from files a.wav and b.wav while channels\n"
+" 5-8 are taken from files c.wav and d.wav.\n\n"
+
+" cat a.wav | postfish \n"
+" This command line sends a.wav to Postfish as a non-seekable stream\n"
+" of four-channel data. If the WAV (or AIFF) header is complete, Postfish\n"
+" obeys the length encoded in the header and halts after processing to\n"
+" that length. If the data length in the header is unset (0 or -1),\n"
+" Postfish will continue processing data until EOF on stdin.\n\n"
+
+"OUTPUT:\n\n"
+
+" Postfish writes output to stdout.\n\n"
+
+" If stdout is piped, the output is nonseekable and Postfish marks the\n"
+" produced header incomplete (length of -1). Stopping and re-starting\n"
+" processing writes a fresh stream to stdout.\n\n"
+
+" If stdout is redirected to a file, Postfish will write a complete header\n"
+" upon processing halt or program exit. If processing halts and restarts,\n"
+" the file is re-written from scratch.\n\n"
+
+" If stdout is a pipe or redirected to a file, the user may specify\n"
+" parallel audio monitor through the audio device using the 'mOn' activator\n"
+" button in the main panel's 'master' section, or on the output config\n"
+" panel. The audio device selected for playback is configurable on the\n"
+" output config panel.\n\n"
+
+" If stdout is redirected to an audio device, output is sent to that audio\n"
+" device exclusively and the 'mOn' activator on the main panel will not\n"
+" be available.\n\n"
+
+"STATE/CONFIG:\n\n"
+
+" By default, persistent panel state is loaded from the file \n"
+" 'postfish-staterc' in the current working directory. Postfish rewrites\n"
+" this file with all current panel state upon exit. -c specifies loading\n"
+" from and saving to an alternate configuration file name.\n\n",version);
+
+}
+
+void parse_command_line(int argc, char **argv){
+ int c,long_option_index;
+ int newgroup=1;
+
+ while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){
+ switch(c){
+ case 1:
+ /* file name that belongs to current group */
+ input_parse(optarg,newgroup);
+ newgroup=0;
+ break;
+ case 'c':
+ /* alternate configuration file */
+ configfile=strdup(optarg);
+ break;
+ case 'g':
+ /* start a new file/channel group */
+ newgroup=1;
+ break;
+ case 'h':
+ usage(stdout);
+ exit(0);
+ default:
+ usage(stderr);
+ exit(0);
+ }
+ }
+}
+
int look_for_wisdom(char *filename){
int ret;
FILE *f=fopen(filename,"r");
if(!f)return 0;
ret=fftwf_import_wisdom_from_file(f);
fclose(f);
-
+
if(ret)
fprintf(stderr,"Found valid postfish-wisdomrc file at %s\n",filename);
else
@@ -61,10 +213,33 @@
return(ret);
}
+static int sigill=0;
+void sigill_handler(int sig){
+ /* make sure */
+ if(sig==SIGILL)sigill=1;
+}
+
int main(int argc, char **argv){
- int configfd=-1;
int wisdom=0;
+ version=strstr(VERSION,"version.h");
+ if(version){
+ char *versionend=strchr(version,' ');
+ if(versionend)versionend=strchr(versionend+1,' ');
+ if(versionend)versionend=strchr(versionend+1,' ');
+ if(versionend)versionend=strchr(versionend+1,' ');
+ if(versionend){
+ int len=versionend-version-9;
+ version=strdup(version+10);
+ version[len-1]=0;
+ }
+ }else{
+ version="";
+ }
+
+ /* parse command line and open all the input files */
+ parse_command_line(argc, argv);
+
/* We do not care about FPEs; rather, underflow is nominal case, and
its better to ignore other traps in production than to crash the
app. Please inform the FPU of this. */
@@ -74,14 +249,16 @@
/* Linux Altivec support has a very annoying problem; by default,
math on denormalized floats will simply crash the program. FFTW3
- uses Altivec, so boom.
+ uses Altivec, so boom, but only random booms.
By the C99 spec, the above exception configuration is also
supposed to handle Altivec config, but doesn't. So we use the
- below ugliness. */
+ below ugliness to both handle altivec and non-alitvec PPC. */
#ifdef __PPC
#include <altivec.h>
+ signal(SIGILL,sigill_handler);
+
#if (defined __GNUC__) && (__GNUC__ == 3) && ! (defined __APPLE_CC__)
__vector unsigned short noTrap =
(__vector unsigned short){0,0,0,0,0,0,0x1,0};
@@ -139,8 +316,16 @@
"window because this information must be regenerated each time Postfish runs.\n");
}
- /* parse command line and open all the input files */
- if(input_load(argc-1,argv+1))exit(1);
+ /* probe outputs */
+ output_probe_stdout(STDOUT_FILENO);
+ output_probe_monitor();
+
+ /* open all the input files */
+ if(input_load())exit(1);
+
+ /* load config file */
+ if(config_load(configfile))exit(1);
+
/* set up filter chains */
if(declip_load())exit(1);
if(eq_load(OUTPUT_CHANNELS))exit(1);
@@ -152,21 +337,6 @@
if(mix_load(OUTPUT_CHANNELS))exit(1);
if(plate_load(OUTPUT_CHANNELS))exit(1);
- /* look at stdout... do we have a file or device? */
- if(!isatty(STDOUT_FILENO)){
- /* assume this is the file/device for output */
- outfileno=dup(STDOUT_FILENO);
- dup2(STDERR_FILENO,STDOUT_FILENO);
- }
-
- /* load config */
-#if 0
- {
- configfd=open(".postfishrc",O_RDWR|O_CREAT,0666);
- if(configfd>=0)load_settings(configfd);
- }
-#endif
-
/* easiest way to inform gtk of changes and not deal with locking
issues around the UI */
if(pipe(eventpipe)){
@@ -177,13 +347,17 @@
}
input_seek(0);
+
+ main_looping=0;
+
+ signal(SIGINT,clean_exit);
+ signal(SIGSEGV,clean_exit);
+
mainpanel_go(argc,argv,input_ch);
output_halt_playback();
- //save_settings(configfd);
- if(configfd>=0)close(configfd);
-
+ cleanup();
return(0);
}
Modified: trunk/postfish/mainpanel.c
===================================================================
--- trunk/postfish/mainpanel.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/mainpanel.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -28,12 +28,94 @@
#include "buttonicons.h"
#include "multibar.h"
#include "readout.h"
-#include "version.h"
#include "input.h"
#include "output.h"
#include "mainpanel.h"
#include "windowbutton.h"
+#include "config.h"
+static postfish_mainpanel p;
+extern char *configfile;
+
+static void action_setb_to(postfish_mainpanel *p,const char *time);
+static void action_seta_to(postfish_mainpanel *p,const char *time);
+
+
+static void mainpanel_state_to_config(int bank){
+ int i;
+ float f;
+
+ f=multibar_get_value(MULTIBAR(p.masterdB_s),0);
+ i=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p.masterdB_a));
+
+ config_set_integer("mainpanel_master_att",bank,0,0,0,0,rint(f*10));
+ config_set_integer("mainpanel_master_att_active",bank,0,0,0,0,i);
+
+ config_set_string("mainpanel_cue_A",0,0,0,0,gtk_entry_get_text(GTK_ENTRY(p.entry_a)));
+ config_set_string("mainpanel_cue_B",0,0,0,0,gtk_entry_get_text(GTK_ENTRY(p.entry_b)));
+ config_set_integer("mainpanel_loop",0,0,0,0,0,
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p.cue_b)));
+
+ for(i=0;i<input_ch || i<OUTPUT_CHANNELS;i++)
+ config_set_integer("mainpanel_VU_show",0,0,0,0,i,
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p.channelshow[i])));
+
+ clippanel_state_to_config(bank);
+ compandpanel_state_to_config(bank);
+ singlepanel_state_to_config(bank);
+ suppresspanel_state_to_config(bank);
+ eqpanel_state_to_config(bank);
+ reverbpanel_state_to_config(bank);
+ limitpanel_state_to_config(bank);
+ outpanel_state_to_config(bank);
+ mixpanel_state_to_config(bank);
+
+}
+
+static void mainpanel_state_from_config(int bank){
+
+ int val,i;
+ const char *string;
+
+ if(!config_get_integer("mainpanel_master_att",bank,0,0,0,0,&val))
+ multibar_thumb_set(MULTIBAR(p.masterdB_s),val*.1,0);
+
+ if(!config_get_integer("mainpanel_master_att_active",bank,0,0,0,0,&val))
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p.masterdB_a),val);
+
+ /* A/B state are saved but *not* banked */
+ if((string=config_get_string("mainpanel_cue_A",0,0,0,0)))
+ action_seta_to(&p,string);
+ if((string=config_get_string("mainpanel_cue_B",0,0,0,0)))
+ action_setb_to(&p,string);
+ if(!config_get_integer("mainpanel_loop",0,0,0,0,0,&val))
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p.cue_b),val);
+
+ for(i=0;i<input_ch || i<OUTPUT_CHANNELS;i++)
+ if(!config_get_integer("mainpanel_VU_show",0,0,0,0,i,&val))
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p.channelshow[i]),val);
+
+ clippanel_state_from_config(bank);
+ compandpanel_state_from_config(bank);
+ singlepanel_state_from_config(bank);
+ suppresspanel_state_from_config(bank);
+ eqpanel_state_from_config(bank);
+ reverbpanel_state_from_config(bank);
+ limitpanel_state_from_config(bank);
+ outpanel_state_from_config(bank);
+ mixpanel_state_from_config(bank);
+
+}
+
+void save_state(){
+ mainpanel_state_to_config(0);
+ config_save(configfile);
+}
+
+static void savestatei(GtkWidget *dummy, gpointer in){
+ save_state();
+}
+
static void meterhold_reset(postfish_mainpanel *p){
p->inpeak=-200;
p->outpeak=-200;
@@ -210,8 +292,7 @@
}
-static void action_seta(GtkWidget *widget,postfish_mainpanel *p){
- const char *time=readout_get(READOUT(p->cue));
+static void action_seta_to(postfish_mainpanel *p,const char *time){
gtk_entry_set_text(GTK_ENTRY(p->entry_a),time);
{
@@ -224,38 +305,42 @@
loop_active=0;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->cue_b),0);
}
+ input_Acursor_set(cursora);
}
}
-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);
+static void action_seta(GtkWidget *widget,postfish_mainpanel *p){
+ const char *time=readout_get(READOUT(p->cue));
+ action_seta_to(p,time);
+}
+
+static void action_setb_to(postfish_mainpanel *p,const char *time){
+ off_t cursora,cursorb;
- time=readout_get(READOUT(p->cue));
cursorb=input_time_to_cursor(time);
gtk_entry_set_text(GTK_ENTRY(p->entry_b),time);
- {
- const char *time=gtk_entry_get_text(GTK_ENTRY(p->entry_a));
- off_t cursora=input_time_to_cursor(time),cursorb;
- time=gtk_entry_get_text(GTK_ENTRY(p->entry_b));
- cursorb=input_time_to_cursor(time);
-
- if(cursora>=cursorb && loop_active){
- loop_active=0;
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->cue_b),0);
- }
+ time=gtk_entry_get_text(GTK_ENTRY(p->entry_a));
+ cursora=input_time_to_cursor(time);
+
+ if(cursora>=cursorb && loop_active){
+ loop_active=0;
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->cue_b),0);
}
+ input_Bcursor_set(cursorb);
+
}
+static void action_setb(GtkWidget *widget,postfish_mainpanel *p){
+ const char *time= time=readout_get(READOUT(p->cue));
+ action_setb_to(p,time);
+}
+
static void shutdown(void){
gtk_main_quit ();
}
-sig_atomic_t master_att;
static void masterdB_change(GtkWidget *dummy, gpointer in){
postfish_mainpanel *p=in;
char buf[80];
@@ -334,6 +419,8 @@
case GDK_3:
case GDK_4:
case GDK_5:
+ if(pos==4 || pos==7 || pos==10)pos++;
+
if(pos>12)return TRUE;
{
char buffer[15];
@@ -551,6 +638,7 @@
#define CHANNEL_EFFECTS 7
#define MASTER_EFFECTS 7
+extern char *version;
void mainpanel_create(postfish_mainpanel *panel,char **chlabels){
char *text_bar[7]={"[bksp]","[<]","[,]","[space]","[.]","[>]","[end]"};
@@ -559,12 +647,13 @@
GdkBitmap *xbm_bar[7];
GtkWidget *gim_bar[7];
- GtkWidget *topplace,*topal;
+ GtkWidget *topplace,*topal,*topalb;
GtkWidget *topframe=gtk_frame_new (NULL);
GtkWidget *toplabel=gtk_label_new (NULL);
GtkWidget *quitbutton=gtk_button_new_with_mnemonic("_quit");
+ GtkWidget *savebutton=gtk_button_new_with_label("^save");
GtkWidget *mainbox=gtk_hbox_new(0,6);
GtkWidget *masterback=gtk_event_box_new();
@@ -591,20 +680,6 @@
panel->channeleffects=CHANNEL_EFFECTS;
char versionmarkup[240];
- char *version=strstr(VERSION,"version.h");
- if(version){
- char *versionend=strchr(version,' ');
- if(versionend)versionend=strchr(versionend+1,' ');
- if(versionend)versionend=strchr(versionend+1,' ');
- if(versionend)versionend=strchr(versionend+1,' ');
- if(versionend){
- int len=versionend-version-9;
- version=strdup(version+10);
- version[len-1]=0;
- }
- }else{
- version="";
- }
snprintf(versionmarkup,240," <span size=\"large\" weight=\"bold\" "
"style=\"italic\" foreground=\"dark blue\">"
"Postfish</span> <span size=\"small\" foreground=\"#606060\">"
@@ -613,10 +688,15 @@
topplace=gtk_table_new(1,1,0);
+ topalb=gtk_hbox_new(0,0);
topal=gtk_alignment_new(1,0,0,0);
gtk_widget_set_name(quitbutton,"quitbutton");
- gtk_container_add (GTK_CONTAINER(topal),quitbutton);
+
+ gtk_box_pack_start(GTK_BOX(topalb),savebutton,0,0,0);
+ gtk_box_pack_start(GTK_BOX(topalb),quitbutton,0,0,0);
+ gtk_container_add (GTK_CONTAINER(topal),topalb);
+
gtk_table_attach_defaults(GTK_TABLE(topplace),
topal,0,1,0,1);
@@ -625,11 +705,17 @@
gtk_container_add (GTK_CONTAINER (panel->toplevel), topplace);
gtk_container_set_border_width (GTK_CONTAINER (quitbutton), 3);
+ gtk_container_set_border_width (GTK_CONTAINER (savebutton), 3);
g_signal_connect (G_OBJECT (quitbutton), "clicked",
G_CALLBACK (shutdown), NULL);
+
+ g_signal_connect (G_OBJECT (savebutton), "clicked",
+ G_CALLBACK (savestatei), 0);
+ gtk_widget_add_accelerator (savebutton, "activate", panel->group, GDK_s, GDK_CONTROL_MASK, 0);
+
g_signal_connect (G_OBJECT (panel->toplevel), "key-press-event",
G_CALLBACK (mainpanel_keybinding), panel);
@@ -783,6 +869,7 @@
gtk_widget_add_accelerator (panel->masterdB_a, "activate", panel->group, GDK_t, 0, 0);
g_signal_connect_after (G_OBJECT(panel->masterdB_a), "clicked",
G_CALLBACK(masterdB_change), (gpointer)panel);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(panel->masterdB_a),1);
}
/* master action bar */
@@ -833,15 +920,24 @@
G_CALLBACK (action_ff), panel);
g_signal_connect (G_OBJECT (panel->deckactive[6]), "clicked",
G_CALLBACK (action_end), panel);
-
- gtk_widget_add_accelerator (panel->deckactive[0], "activate", panel->group, GDK_BackSpace, 0, 0);
- gtk_widget_add_accelerator (panel->deckactive[1], "activate", panel->group, GDK_less, 0, 0);
- gtk_widget_add_accelerator (panel->deckactive[2], "activate", panel->group, GDK_comma, 0, 0);
+
gtk_widget_add_accelerator (panel->deckactive[3], "activate", panel->group, GDK_space, 0, 0);
- gtk_widget_add_accelerator (panel->deckactive[4], "activate", panel->group, GDK_period, 0, 0);
- gtk_widget_add_accelerator (panel->deckactive[5], "activate", panel->group, GDK_greater, 0, 0);
- gtk_widget_add_accelerator (panel->deckactive[6], "activate", panel->group, GDK_End, 0, 0);
+ if(!input_seekable){
+ gtk_widget_set_sensitive(panel->deckactive[0],FALSE);
+ gtk_widget_set_sensitive(panel->deckactive[1],FALSE);
+ gtk_widget_set_sensitive(panel->deckactive[2],FALSE);
+ gtk_widget_set_sensitive(panel->deckactive[4],FALSE);
+ gtk_widget_set_sensitive(panel->deckactive[5],FALSE);
+ gtk_widget_set_sensitive(panel->deckactive[6],FALSE);
+ }else{
+ gtk_widget_add_accelerator (panel->deckactive[0], "activate", panel->group, GDK_BackSpace, 0, 0);
+ gtk_widget_add_accelerator (panel->deckactive[1], "activate", panel->group, GDK_less, 0, 0);
+ gtk_widget_add_accelerator (panel->deckactive[2], "activate", panel->group, GDK_comma, 0, 0);
+ gtk_widget_add_accelerator (panel->deckactive[4], "activate", panel->group, GDK_period, 0, 0);
+ gtk_widget_add_accelerator (panel->deckactive[5], "activate", panel->group, GDK_greater, 0, 0);
+ gtk_widget_add_accelerator (panel->deckactive[6], "activate", panel->group, GDK_End, 0, 0);
+ }
}
@@ -869,6 +965,7 @@
gtk_box_pack_start(GTK_BOX(cuebox),framea,1,1,3);
gtk_box_pack_start(GTK_BOX(cuebox),temp,0,0,0);
gtk_box_pack_start(GTK_BOX(cuebox),panel->entry_a,0,0,0);
+ if(!input_seekable)gtk_widget_set_sensitive(temp,FALSE);
temp=gtk_button_new_with_label(" A ");
gtk_widget_add_accelerator (temp, "activate", panel->group, GDK_A, GDK_SHIFT_MASK, 0);
@@ -882,6 +979,7 @@
G_CALLBACK (action_entryb), panel);
gtk_box_pack_start(GTK_BOX(cuebox),frameb,1,1,3);
gtk_box_pack_start(GTK_BOX(cuebox),temp,0,0,0);
+ if(!input_seekable)gtk_widget_set_sensitive(temp,FALSE);
temp=gtk_button_new_with_label(" B ");
gtk_widget_add_accelerator (temp, "activate", panel->group, GDK_B, GDK_SHIFT_MASK, 0);
@@ -998,7 +1096,7 @@
GtkWidget *ww=windowbutton_new("_Output ");
GtkWidget *std=gtk_toggle_button_new_with_label(" o ");
- GtkWidget *ply=gtk_toggle_button_new_with_label("play");
+ GtkWidget *ply=gtk_toggle_button_new_with_label("mOn");
GtkWidget *box=gtk_hbox_new(0,0);
GtkWidget *box2=gtk_hbox_new(1,0);
@@ -1009,7 +1107,8 @@
gtk_widget_set_sensitive(fw,FALSE);
gtk_widget_add_accelerator (std, "activate", panel->group, GDK_o, 0, 0);
- gtk_widget_add_accelerator (ply, "activate", panel->group, GDK_p, 0, 0);
+ gtk_widget_add_accelerator (ply, "activate", panel->group, GDK_O,
+ GDK_SHIFT_MASK, 0);
gtk_box_pack_start(GTK_BOX(box),ww,0,0,0);
gtk_box_pack_start(GTK_BOX(box),box2,1,1,2);
@@ -1022,7 +1121,10 @@
gtk_table_attach_defaults(GTK_TABLE(mastertable),box,0,1,7,8);
gtk_table_attach_defaults(GTK_TABLE(mastertable),std,1,2,7,8);
- //if(panel_create)(*panel_create)(p,ww,(shortcut?wa:0));
+ {
+ GtkWidget *active[2]={ply,std};
+ outpanel_create(panel,ww,active);
+ }
}
g_signal_connect (G_OBJECT (panel->toplevel), "delete_event",
@@ -1051,28 +1153,27 @@
if(!playback_seeking){
int current_p=!output_feedback_deep();
off_t time_cursor;
- int n=(input_ch>1?input_ch+2:input_ch);
- float *rms=alloca(sizeof(*rms)*(input_ch+2));
- float *peak=alloca(sizeof(*peak)*(input_ch+2));
+ float *rms=alloca(sizeof(*rms)*(input_ch+OUTPUT_CHANNELS));
+ float *peak=alloca(sizeof(*peak)*(input_ch+OUTPUT_CHANNELS));
if(pull_output_feedback(peak,rms)){
char buffer[14];
int i;
- for(i=0;i<n;i++){
- if(i<input_ch && peak[i]>=1.)
+ for(i=0;i<OUTPUT_CHANNELS;i++){
+ if(peak[i]>=1.)
multibar_setwarn(MULTIBAR(panel->outbar),current_p);
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(panel->channelshow[i]))){
- peak[i]=todB(peak[i]);
- rms[i]=todB(rms[i]);
-
+ peak[i]=todB(peak[i])*.5;
+ rms[i]=todB(rms[i])*.5;
+
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;
@@ -1080,14 +1181,14 @@
}
- multibar_set(MULTIBAR(panel->outbar),rms,peak,n,current_p);
+ multibar_set(MULTIBAR(panel->outbar),rms,peak,input_ch,current_p);
if(pull_input_feedback(peak,rms,&time_cursor)){
- for(i=0;i<n;i++){
+ for(i=0;i<input_ch;i++){
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(panel->channelshow[i]))){
- peak[i]=todB(peak[i]);
- rms[i]=todB(rms[i]);
-
+ peak[i]=todB(peak[i])*.5;
+ rms[i]=todB(rms[i])*.5;
+
if(peak[i]>panel->inpeak){
panel->inpeak=ceil(peak[i]);
sprintf(buffer,"%+4.0fdB",panel->inpeak);
@@ -1100,7 +1201,7 @@
}
}
- multibar_set(MULTIBAR(panel->inbar),rms,peak,n,current_p);
+ multibar_set(MULTIBAR(panel->inbar),rms,peak,input_ch,current_p);
input_cursor_to_time(time_cursor,buffer);
readout_set(READOUT(panel->cue),buffer);
}
@@ -1136,10 +1237,10 @@
}
#include <stdlib.h>
+extern sig_atomic_t main_looping;
void mainpanel_go(int argc,char *argv[], int ch){
- postfish_mainpanel p;
char *homedir=getenv("HOME");
- char *labels[11];
+ char *labels[33];
char buffer[20];
int i;
int found=0;
@@ -1196,30 +1297,21 @@
gtk_init (&argc, &argv);
memset(labels,0,sizeof(labels));
- switch(ch){
- case 1:
+ if(ch==1){
labels[0]="_1 mono";
- break;
- case 2:
+
+ for(i=1;i<OUTPUT_CHANNELS;i++){
+ sprintf(buffer,"_%d",i+1);
+ labels[i]=strdup(buffer);
+ }
+ }else if (ch==2){
labels[0]="_1 left";
labels[1]="_2 right";
- labels[2]="_y mid";
- labels[3]="_z side";
- break;
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- case 16:
+ for(i=2;i<OUTPUT_CHANNELS;i++){
+ sprintf(buffer,"_%d",i+1);
+ labels[i]=strdup(buffer);
+ }
+ }else if (ch>0 && ch<=MAX_INPUT_CHANNELS){
for(i=0;i<ch && i<9;i++){
sprintf(buffer,"_%d",i+1);
labels[i]=strdup(buffer);
@@ -1228,17 +1320,19 @@
sprintf(buffer,"%d_%d",(i+1)/10,(i+1)%10);
labels[i]=strdup(buffer);
}
- labels[i++]=strdup("_y mid");
- labels[i++]=strdup("_z div");
+ for(;i<OUTPUT_CHANNELS;i++){
+ sprintf(buffer,"_%d",i+1);
+ labels[i]=strdup(buffer);
+ }
- break;
- default:
- fprintf(stderr,"\nPostfish currently supports inputs of one to sixteen\n"
- "channels (current input request: %d channels)\n\n",ch);
+ }else{
+ fprintf(stderr,"\nPostfish currently supports inputs of 1 to %d\n"
+ "channels (current input request: %d channels)\n\n",(int)MAX_INPUT_CHANNELS,ch);
exit(1);
}
-
+
mainpanel_create(&p,labels);
+ mainpanel_state_from_config(0);
animate_fish(&p);
/* set up watching the event pipe */
@@ -1256,9 +1350,9 @@
}
-
+ /* the slight race here is cosmetic, so I'm not worrying about it */
+ main_looping=1;
gtk_main ();
}
-
Modified: trunk/postfish/mainpanel.h
===================================================================
--- trunk/postfish/mainpanel.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/mainpanel.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -34,6 +34,7 @@
#include "limitpanel.h"
#include "mixpanel.h"
#include "reverbpanel.h"
+#include "outpanel.h"
struct postfish_mainpanel{
GtkWidget *twirlimage;
@@ -55,8 +56,6 @@
GtkWidget *buttonactive[7];
GtkWidget *deckactive[7];
- GtkWidget *cue_b;
-
GtkWidget *inbar;
GtkWidget *outbar;
GtkWidget *inreadout;
@@ -65,16 +64,19 @@
float inpeak;
float outpeak;
- GtkWidget *channelshow[18]; /* support only up to 16 + mid/side */
+ GtkWidget *channelshow[MAX_INPUT_CHANNELS];
int channelrotate[10]; /* up to 16 channels, but only base 10 digits on the keyboard */
GtkWidget ***channel_wa;
int channeleffects;
GtkWidget *cue;
+ GtkWidget *cue_a;
GtkWidget *entry_a;
+ GtkWidget *set_a;
+ GtkWidget *cue_b;
GtkWidget *entry_b;
+ GtkWidget *set_b;
-
/* ui state */
int fishframe;
int fishframe_init;
@@ -83,4 +85,5 @@
};
-extern gboolean slider_keymodify(GtkWidget *w,GdkEventKey *event,gpointer in);
+extern void mainpanel_go(int n,char *list[],int ch);
+extern void save_state();
Modified: trunk/postfish/mix.c
===================================================================
--- trunk/postfish/mix.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/mix.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -262,6 +262,9 @@
memset(peak,0,sizeof(peak));
memset(rms,0,sizeof(rms));
+ /* eliminate asynch change possibility */
+ memcpy(ms.curr,mix_set,sizeof(*mix_set)*input_ch);
+
/* fillstate here is only used for lazy initialization/reset */
if(ms.fillstate==0){
/* zero the cache */
@@ -269,6 +272,7 @@
memset(ms.cacheP[i],0,sizeof(**ms.cacheP)*input_size);
memset(ms.cachePP[i],0,sizeof(**ms.cachePP)*input_size);
}
+ memcpy(ms.prev,ms.curr,sizeof(*mix_set)*input_ch);
ms.fillstate=1;
}
@@ -276,9 +280,6 @@
for(i=0;i<outch;i++)
memset(ms.out.data[i],0,sizeof(**ms.out.data)*input_size);
- /* eliminate asynch change possibility */
- memcpy(ms.curr,mix_set,sizeof(*mix_set)*input_ch);
-
/* a bit of laziness that may actually save CPU time by avoiding
special-cases later */
for(i=0;i<input_ch;i++){
@@ -292,8 +293,8 @@
/* input-by-input */
for(i=0;i<input_ch;i++){
- int feedit=mixpanel_visible[i] && mixpanel_active[i];
- int feeditM=atten_visible && mixpanel_active[i];
+ int feedit=mixpanel_visible[i];
+ int feeditM=atten_visible;
/* master feedback is a bit of a pain; the metrics we need aren't
produced by any of the mixdowns below. Do it by hand */
@@ -496,24 +497,30 @@
if(sourceM || sourceMP)
mixwork(in->data[i],ms.cacheP[i],ms.cachePP[i],
mix,
- att,del,ms.curr[i].insert_invert[k],
- attP,delP,ms.prev[i].insert_invert[k]);
+ (sourceM ? att : 0),
+ del,ms.curr[i].insert_invert[k],
+ (sourceMP ? attP : 0),
+ delP,ms.prev[i].insert_invert[k]);
/* reverbA */
if(sourceA || sourceAP)
if(inA)
mixwork(inA->data[i],ms.cachePA[i],ms.cachePPA[i],
mix,
- att,del,ms.curr[i].insert_invert[k],
- attP,delP,ms.prev[i].insert_invert[k]);
+ (sourceA ? att : 0),
+ del,ms.curr[i].insert_invert[k],
+ (sourceAP ? attP : 0),
+ delP,ms.prev[i].insert_invert[k]);
/* reverbB */
if(sourceB || sourceBP)
if(inB)
mixwork(inB->data[i],ms.cachePB[i],ms.cachePPB[i],
mix,
- att,del,ms.curr[i].insert_invert[k],
- attP,delP,ms.prev[i].insert_invert[k]);
+ (sourceB ? att : 0),
+ del,ms.curr[i].insert_invert[k],
+ (sourceBP ? attP : 0),
+ delP,ms.prev[i].insert_invert[k]);
/* mix into output */
for(j=0;j<OUTPUT_CHANNELS;j++){
Modified: trunk/postfish/mix.h
===================================================================
--- trunk/postfish/mix.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/mix.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -49,3 +49,8 @@
time_linkage *inB); // reverb channel
extern int pull_mix_feedback(float **peak,float **rms);
+extern mix_settings *mix_set;
+extern sig_atomic_t atten_visible;
+extern sig_atomic_t *mixpanel_active;
+extern sig_atomic_t *mixpanel_visible;
+
Modified: trunk/postfish/mixpanel.c
===================================================================
--- trunk/postfish/mixpanel.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/mixpanel.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -30,16 +30,8 @@
#include "subpanel.h"
#include "feedback.h"
#include "mix.h"
+#include "config.h"
-extern int input_ch;
-extern int input_size;
-extern int input_rate;
-
-extern mix_settings *mix_set;
-extern sig_atomic_t atten_visible;
-extern sig_atomic_t *mixpanel_active;
-extern sig_atomic_t *mixpanel_visible;
-
typedef struct {
GtkWidget *s;
GtkWidget *r;
@@ -48,10 +40,26 @@
/* only the sliders we need to save for feedback */
typedef struct {
+ subpanel_generic *panel;
+ slider_readout_pair **att;
+ slider_readout_pair **del;
+
GtkWidget **master;
} atten_panelsave;
typedef struct {
+ GtkWidget *insert_source[MIX_BLOCKS][3];
+ GtkWidget *insert_invert[MIX_BLOCKS];
+ slider_readout_pair *insert_att[MIX_BLOCKS];
+ slider_readout_pair *insert_del[MIX_BLOCKS];
+ GtkWidget *insert_dest[MIX_BLOCKS][OUTPUT_CHANNELS];
+
+ GtkWidget *destA[OUTPUT_CHANNELS];
+ GtkWidget *destB[OUTPUT_CHANNELS];
+ slider_readout_pair *place_AB;
+ slider_readout_pair *place_atten;
+ slider_readout_pair *place_delay;
+
GtkWidget *place[2];
GtkWidget *sub[MIX_BLOCKS];
} mix_panelsave;
@@ -59,6 +67,98 @@
static atten_panelsave atten_panel;
static mix_panelsave **mix_panels;
+static void mixblock_state_to_config(int bank, mix_settings *s,int A,int B){
+ config_set_vector("mixblock_source",bank,A,B,0,3,s->insert_source[B]);
+ config_set_integer("mixblock_set",bank,A,B,0,0,s->insert_invert[B]);
+ config_set_integer("mixblock_set",bank,A,B,0,1,s->insert_att[B]);
+ config_set_integer("mixblock_set",bank,A,B,0,2,s->insert_delay[B]);
+ config_set_vector("mixblock_dest",bank,A,B,0,OUTPUT_CHANNELS,s->insert_dest[B]);
+}
+
+static void mixdown_state_to_config(int bank, mix_settings *s,int A){
+ int i;
+ config_set_vector("mixplace_dest",bank,A,0,0,OUTPUT_CHANNELS,s->placer_destA);
+ config_set_vector("mixplace_dest",bank,A,1,0,OUTPUT_CHANNELS,s->placer_destB);
+ config_set_integer("mixplace_set",bank,A,0,0,0,s->placer_place);
+ config_set_integer("mixplace_set",bank,A,0,0,1,s->placer_att);
+ config_set_integer("mixplace_set",bank,A,0,0,2,s->placer_delay);
+ for(i=0;i<MIX_BLOCKS;i++)
+ mixblock_state_to_config(bank,s,A,i);
+}
+
+void mixpanel_state_to_config(int bank){
+ int i;
+ config_set_vector("mixdown_active",bank,0,0,0,input_ch,mixpanel_active);
+
+ for(i=0;i<input_ch;i++){
+ config_set_integer("mixdown_master_attenuate",bank,0,0,0,i,mix_set[i].master_att);
+ config_set_integer("mixdown_master_delay",bank,0,0,0,i,mix_set[i].master_delay);
+
+ mixdown_state_to_config(bank,mix_set+i,i);
+ }
+}
+
+static void mixblock_state_from_config(int bank, mix_settings *s,mix_panelsave *p,int A,int B){
+ int i;
+ config_get_vector("mixblock_source",bank,A,B,0,3,s->insert_source[B]);
+ for(i=0;i<3;i++)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->insert_source[B][i]),
+ s->insert_source[B][i]);
+
+ config_get_sigat("mixblock_set",bank,A,B,0,0,&s->insert_invert[B]);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->insert_invert[B]),
+ s->insert_invert[B]);
+
+ config_get_sigat("mixblock_set",bank,A,B,0,1,&s->insert_att[B]);
+ multibar_thumb_set(MULTIBAR(p->insert_att[B]->s),s->insert_att[B]*.1,0);
+
+ config_get_sigat("mixblock_set",bank,A,B,0,2,&s->insert_delay[B]);
+ multibar_thumb_set(MULTIBAR(p->insert_del[B]->s),s->insert_delay[B]*.01,0);
+
+ config_get_vector("mixblock_dest",bank,A,B,0,OUTPUT_CHANNELS,s->insert_dest[B]);
+ for(i=0;i<OUTPUT_CHANNELS;i++)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->insert_dest[B][i]),
+ s->insert_dest[B][i]);
+}
+
+static void mixdown_state_from_config(int bank, mix_settings *s, mix_panelsave *p, int A){
+ int i;
+ config_get_vector("mixplace_dest",bank,A,0,0,OUTPUT_CHANNELS,s->placer_destA);
+ config_get_vector("mixplace_dest",bank,A,1,0,OUTPUT_CHANNELS,s->placer_destB);
+ config_get_sigat("mixplace_set",bank,A,0,0,0,&s->placer_place);
+ config_get_sigat("mixplace_set",bank,A,0,0,1,&s->placer_att);
+ config_get_sigat("mixplace_set",bank,A,0,0,2,&s->placer_delay);
+
+ for(i=0;i<OUTPUT_CHANNELS;i++){
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->destA[i]),s->placer_destA[i]);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->destB[i]),s->placer_destB[i]);
+ }
+ multibar_thumb_set(MULTIBAR(p->place_AB->s),s->placer_place,0);
+ multibar_thumb_set(MULTIBAR(p->place_atten->s),s->placer_att*.1,0);
+ multibar_thumb_set(MULTIBAR(p->place_delay->s),s->placer_delay*.01,0);
+
+ for(i=0;i<MIX_BLOCKS;i++)
+ mixblock_state_from_config(bank,s,p,A,i);
+}
+
+void mixpanel_state_from_config(int bank){
+ int i;
+ config_get_vector("mixdown_active",bank,0,0,0,input_ch,mixpanel_active);
+
+ for(i=0;i<input_ch;i++){
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(atten_panel.panel->subpanel_activebutton[i]),
+ mixpanel_active[i]);
+
+ config_get_sigat("mixdown_master_attenuate",bank,0,0,0,i,&mix_set[i].master_att);
+ config_get_sigat("mixdown_master_delay",bank,0,0,0,i,&mix_set[i].master_delay);
+
+ multibar_thumb_set(MULTIBAR(atten_panel.att[i]->s),mix_set[i].master_att*.1,0);
+ multibar_thumb_set(MULTIBAR(atten_panel.del[i]->s),mix_set[i].master_delay*.01,0);
+
+ mixdown_state_from_config(bank,mix_set+i,mix_panels[i],i);
+ }
+}
+
static void dB_slider_change(GtkWidget *w,gpointer in){
char buffer[80];
slider_readout_pair *p=(slider_readout_pair *)in;
@@ -108,7 +208,7 @@
*val=gtk_toggle_button_get_active(b);
}
-static char *labels_dB[11]={""," 60","40","20","10","0","10","20","40","60","80"};
+static char *labels_dB[11]={""," -60","-40","-20","-10","0","10","20","40","60","80"};
static float levels_dB[11]={-80,-60,-40,-20,-10,0,10,20,40,60,80};
static char *labels_dBn[6]={"","-40","-20","-10","0","+10"};
@@ -151,9 +251,9 @@
/* crossplace controls */
{
- slider_readout_pair *AB=calloc(1,sizeof(AB));
- slider_readout_pair *att=calloc(1,sizeof(att));
- slider_readout_pair *del=calloc(1,sizeof(del));
+ slider_readout_pair *AB=calloc(1,sizeof(*AB));
+ slider_readout_pair *att=calloc(1,sizeof(*att));
+ slider_readout_pair *del=calloc(1,sizeof(*del));
GtkWidget *boxA=gtk_hbox_new(1,0);
GtkWidget *boxB=gtk_hbox_new(1,0);
@@ -175,6 +275,10 @@
att->val=&m->placer_att;
del->val=&m->placer_delay;
+ ps->place_AB=AB;
+ ps->place_atten=att;
+ ps->place_delay=del;
+
multibar_callback(MULTIBAR(AB->s),AB_slider_change,AB);
multibar_thumb_set(MULTIBAR(AB->s),100,0);
multibar_callback(MULTIBAR(att->s),dB_slider_change,att);
@@ -206,6 +310,8 @@
G_CALLBACK (toggle_callback),
(gpointer)&m->placer_destB[i]);
+ ps->destA[i]=bA;
+ ps->destB[i]=bB;
}
gtk_table_attach(GTK_TABLE(table),lA,0,2,6,7,
@@ -268,8 +374,8 @@
}
for(i=0;i<MIX_BLOCKS;i++){
- slider_readout_pair *att=calloc(1,sizeof(att));
- slider_readout_pair *del=calloc(1,sizeof(del));
+ slider_readout_pair *att=calloc(1,sizeof(*att));
+ slider_readout_pair *del=calloc(1,sizeof(*del));
GtkWidget *boxA=gtk_hbox_new(0,0);
GtkWidget *boxB=gtk_hbox_new(1,0);
@@ -286,6 +392,11 @@
gtk_misc_set_alignment(GTK_MISC(latt),1,.5);
gtk_misc_set_alignment(GTK_MISC(ldel),1,.5);
+ ps->insert_source[i][0]=bM;
+ ps->insert_source[i][1]=bA;
+ ps->insert_source[i][2]=bB;
+ ps->insert_invert[i]=bI;
+
att->s=multibar_slider_new(11,labels_dB,levels_dB,1);
del->s=multibar_slider_new(6,labels_del,levels_del,1);
att->r=readout_new("+00.0dB");
@@ -296,6 +407,9 @@
ps->sub[i]=multibar_new(6,labels_dBn,levels_dBn,0,
LO_ATTACK|LO_DECAY|HI_DECAY);
+ ps->insert_att[i]=att;
+ ps->insert_del[i]=del;
+
multibar_callback(MULTIBAR(att->s),dB_slider_change,att);
multibar_callback(MULTIBAR(del->s),ms_slider_change,del);
@@ -336,6 +450,8 @@
if(thisch%2 == j && i == 0)
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b),1);
+ ps->insert_dest[i][j]=b;
+
gtk_box_pack_start(GTK_BOX(boxB),b,1,1,0);
}
@@ -393,6 +509,7 @@
buffer,0,i,1);
mix_panels[i]=mixpanel_create_helper(mp,panel,mix_set+i,i);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(activebutton[i]),1);
}
}
@@ -408,8 +525,11 @@
GtkWidget *table=gtk_table_new(MIX_BLOCKS*3,5,0);
mix_panelsave *ps=calloc(1,sizeof(*ps));
- atten_panel.master=calloc(input_ch,sizeof(*atten_panel.master));
-
+ atten_panel.master=calloc(input_ch,sizeof(*atten_panel.master));
+ atten_panel.att=calloc(input_ch,sizeof(*atten_panel.att));
+ atten_panel.del=calloc(input_ch,sizeof(*atten_panel.del));
+ atten_panel.panel=panel;
+
for(i=0;i<input_ch;i++){
char buffer[80];
GtkWidget *l1=gtk_label_new("attenuation ");
@@ -423,11 +543,13 @@
sprintf(buffer,"channel/reverb %d VU",i+1);
GtkWidget *lV=gtk_label_new(buffer);
- slider_readout_pair *att=calloc(1,sizeof(att));
- slider_readout_pair *del=calloc(1,sizeof(del));
+ slider_readout_pair *att=calloc(1,sizeof(*att));
+ slider_readout_pair *del=calloc(1,sizeof(*del));
atten_panel.master[i]=multibar_new(6,labels_dBn,levels_dBn,0,
LO_ATTACK|LO_DECAY|HI_DECAY);
+ atten_panel.att[i]=att;
+ atten_panel.del[i]=del;
att->s=multibar_slider_new(11,labels_dB,levels_dB,1);
att->r=readout_new("+00.0dB");
@@ -471,7 +593,6 @@
gtk_table_attach(GTK_TABLE(table),del->r,3,4,1+i*3,2+i*3,
GTK_FILL|GTK_EXPAND,0,0,0);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(activebutton[i]),1);
}
gtk_box_pack_start(GTK_BOX(panel->subpanel_box),table,1,1,4);
Modified: trunk/postfish/mixpanel.h
===================================================================
--- trunk/postfish/mixpanel.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/mixpanel.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -31,3 +31,6 @@
GtkWidget **activebutton);
extern void mixpanel_feedback(int displayit);
extern void mixpanel_reset(void);
+
+extern void mixpanel_state_to_config(int bank);
+extern void mixpanel_state_from_config(int bank);
Modified: trunk/postfish/multicompand.c
===================================================================
--- trunk/postfish/multicompand.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/multicompand.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -28,10 +28,6 @@
#include "subband.h"
#include "bessel.h"
-extern int input_size;
-extern int input_rate;
-extern int input_ch;
-
/* feedback! */
typedef struct multicompand_feedback{
feedback_generic parent_class;
@@ -47,6 +43,16 @@
} peak_state;
typedef struct {
+ sig_atomic_t static_u[multicomp_freqs_max];
+ sig_atomic_t under_ratio;
+
+ sig_atomic_t static_o[multicomp_freqs_max];
+ sig_atomic_t over_ratio;
+
+ sig_atomic_t base_ratio;
+} atten_cache;
+
+typedef struct {
feedback_generic_pool feedpool;
subband_state ss;
@@ -66,10 +72,14 @@
peak_state *over_peak[multicomp_freqs_max];
peak_state *under_peak[multicomp_freqs_max];
peak_state *base_peak[multicomp_freqs_max];
+
+ atten_cache *prevset;
+ atten_cache *currset;
float **peak;
float **rms;
int ch;
+ int initstate;
} multicompand_state;
multicompand_settings multi_master_set;
@@ -139,12 +149,14 @@
reset_filters(&master_state);
reset_filters(&channel_state);
+ master_state.initstate=0;
+ channel_state.initstate=0;
}
static int multicompand_load_helper(multicompand_state *ms,int ch){
int i;
int qblocksize=input_size/8;
- memset(ms,0,sizeof(ms));
+ memset(ms,0,sizeof(*ms));
ms->ch=ch;
subband_load(&ms->ss,multicomp_freqs_max,qblocksize,ch);
@@ -171,6 +183,9 @@
ms->rms=calloc(multicomp_freqs_max,sizeof(*ms->rms));
for(i=0;i<multicomp_freqs_max;i++)ms->peak[i]=malloc(ms->ch*sizeof(**ms->peak));
for(i=0;i<multicomp_freqs_max;i++)ms->rms[i]=malloc(ms->ch*sizeof(**ms->rms));
+
+ ms->prevset=malloc(ch*sizeof(*ms->prevset));
+ ms->currset=malloc(ch*sizeof(*ms->currset));
return 0;
}
@@ -296,11 +311,14 @@
return (x>0.f?-x:0.f);
}
-static void over_compand(float *lx,float zerocorner,
+static void over_compand(float *lx,
+ float zerocorner,
+ float currcorner,
iir_filter *attack, iir_filter *decay,
iir_state *iir, peak_state *ps,
float lookahead,int mode,int knee,
- int ratio,
+ float prevratio,
+ float currratio,
float *adj){
int k;
float overdB[input_size];
@@ -308,13 +326,34 @@
run_filter(overdB,lx,input_size,lookahead,mode,iir,attack,decay,ps);
if(adj){
- float corner_multiplier= 1.- 1000./ratio;
- if(knee){
- for(k=0;k<input_size;k++)
- adj[k]+=soft_knee(overdB[k]-zerocorner)*corner_multiplier;
+ float ratio_multiplier= 1.- 1000./prevratio;
+
+ if(zerocorner!=currcorner || prevratio!=currratio){
+ /* slew limit these attenuators */
+ float ratio_add= ((1.- 1000./currratio)-ratio_multiplier)/input_size;
+ float corner_add= (currcorner-zerocorner)/input_size;
+
+ if(knee){
+ for(k=0;k<input_size;k++){
+ adj[k]+=soft_knee(overdB[k]-zerocorner)*ratio_multiplier;
+ ratio_multiplier+=ratio_add;
+ zerocorner+=corner_add;
+ }
+ }else{
+ for(k=0;k<input_size;k++){
+ adj[k]+=hard_knee(overdB[k]-zerocorner)*ratio_multiplier;
+ ratio_multiplier+=ratio_add;
+ zerocorner+=corner_add;
+ }
+ }
}else{
- for(k=0;k<input_size;k++)
- adj[k]+=hard_knee(overdB[k]-zerocorner)*corner_multiplier;
+ if(knee){
+ for(k=0;k<input_size;k++)
+ adj[k]+=soft_knee(overdB[k]-zerocorner)*ratio_multiplier;
+ }else{
+ for(k=0;k<input_size;k++)
+ adj[k]+=hard_knee(overdB[k]-zerocorner)*ratio_multiplier;
+ }
}
}
}
@@ -323,7 +362,8 @@
iir_filter *attack, iir_filter *decay,
iir_state *iir, peak_state *ps,
int mode,
- int ratio,
+ float prevratio,
+ float currratio,
float *adj){
int k;
float basedB[input_size];
@@ -332,17 +372,32 @@
iir,attack,decay,ps);
if(adj){
- float base_multiplier=1.-1000./ratio;
- for(k=0;k<input_size;k++)
- adj[k]-=(basedB[k]+adj[k])*base_multiplier;
+ float ratio_multiplier=1.-1000./prevratio;
+
+ if(prevratio!=currratio){
+ /* slew limit the attenuators */
+ float ratio_add= ((1.- 1000./currratio)-ratio_multiplier)/input_size;
+
+ for(k=0;k<input_size;k++){
+ adj[k]-=(basedB[k]+adj[k])*ratio_multiplier;
+ ratio_multiplier+=ratio_add;
+ }
+
+ }else{
+ for(k=0;k<input_size;k++)
+ adj[k]-=(basedB[k]+adj[k])*ratio_multiplier;
+ }
}
}
-static void under_compand(float *x,float zerocorner,
+static void under_compand(float *x,
+ float zerocorner,
+ float currcorner,
iir_filter *attack, iir_filter *decay,
iir_state *iir, peak_state *ps,
float lookahead,int mode,int knee,
- int ratio,
+ float prevratio,
+ float currratio,
float *adj){
int k;
float underdB[input_size];
@@ -351,13 +406,35 @@
iir,attack,decay,ps);
if(adj){
- float corner_multiplier=1000./ratio -1.;
- if(knee){
- for(k=0;k<input_size;k++)
- adj[k]=soft_knee(zerocorner-underdB[k])*corner_multiplier;
+ float ratio_multiplier=1000./prevratio - 1.;
+
+ if(zerocorner!=currcorner || prevratio!=currratio){
+ /* slew limit these attenuators */
+ float ratio_add= ((1000./currratio - 1.)-ratio_multiplier)/input_size;
+ float corner_add= (currcorner-zerocorner)/input_size;
+
+ if(knee){
+ for(k=0;k<input_size;k++){
+ adj[k]=soft_knee(zerocorner-underdB[k])*ratio_multiplier;
+ ratio_multiplier+=ratio_add;
+ zerocorner+=corner_add;
+ }
+ }else{
+ for(k=0;k<input_size;k++){
+ adj[k]=hard_knee(zerocorner-underdB[k])*ratio_multiplier;
+ ratio_multiplier+=ratio_add;
+ zerocorner+=corner_add;
+ }
+ }
+
}else{
- for(k=0;k<input_size;k++)
- adj[k]=hard_knee(zerocorner-underdB[k])*corner_multiplier;
+ if(knee){
+ for(k=0;k<input_size;k++)
+ adj[k]=soft_knee(zerocorner-underdB[k])*ratio_multiplier;
+ }else{
+ for(k=0;k<input_size;k++)
+ adj[k]=hard_knee(zerocorner-underdB[k])*ratio_multiplier;
+ }
}
}
}
@@ -370,11 +447,13 @@
}
static int multicompand_work_perchannel(multicompand_state *ms,
- float **peakfeed,
- float **rmsfeed,
- int maxbands,
- int channel,
- multicompand_settings *c){
+ float **peakfeed,
+ float **rmsfeed,
+ int maxbands,
+ int channel,
+ atten_cache *prevset,
+ atten_cache *currset,
+ multicompand_settings *c){
subband_state *ss=&ms->ss;
int active=(ss->effect_active1[channel] ||
ss->effect_active0[channel] ||
@@ -391,7 +470,22 @@
}else if(w==&sw[1]){
bank=1;
}else bank=2;
-
+
+ if(active){
+ for(i=0;i<multicomp_freqs_max;i++){
+ currset->static_u[i]=c->bc[bank].static_u[i];
+ currset->static_o[i]=c->bc[bank].static_o[i];
+ }
+
+ currset->under_ratio=c->under_ratio;
+ currset->over_ratio=c->over_ratio;
+ currset->base_ratio=c->base_ratio;
+
+ /* don't slew from an unknown value */
+ if(!ss->effect_activeP[channel] || !ms->initstate)
+ memcpy(prevset,currset,sizeof(*currset));
+ }
+
for(i=0;i<maxbands;i++){
float *x=ss->lap[i][channel];
@@ -405,7 +499,8 @@
settings. There are allocated, but unset; if overrange,
they're ignored in the compand worker */
under_compand(x,
- c->bc[bank].static_u[i],
+ prevset->static_u[i],
+ currset->static_u[i],
&ms->under_attack[channel],
&ms->under_decay[channel],
&ms->under_iir[i][channel],
@@ -413,11 +508,13 @@
c->under_lookahead/1000.,
c->under_mode,
c->under_softknee,
- c->under_ratio,
+ prevset->under_ratio,
+ currset->under_ratio,
(i>=w->freq_bands?0:adj));
over_compand(x,
- c->bc[bank].static_o[i],
+ prevset->static_o[i],
+ currset->static_o[i],
&ms->over_attack[channel],
&ms->over_decay[channel],
&ms->over_iir[i][channel],
@@ -425,34 +522,38 @@
c->over_lookahead/1000.,
c->over_mode,
c->over_softknee,
- c->over_ratio,
+ prevset->over_ratio,
+ currset->over_ratio,
(i>=w->freq_bands?0:adj));
}
- if(ss->visible1[channel] && !mute_channel_muted(ss->mutemask1,channel)){
- /* determine rms and peak for feedback */
- float max=-1.;
- int maxpos=-1;
- float rms=0.;
+ if(ss->visible1[channel]){
feedback_p=1;
-
- for(k=0;k<input_size;k++){
- float val=x[k]*x[k];
- if(val>max){
- max=val;
- maxpos=k;
+
+ if(!mute_channel_muted(ss->mutemask1,channel)){
+ /* determine rms and peak for feedback */
+ float max=-1.;
+ int maxpos=-1;
+ float rms=0.;
+
+ for(k=0;k<input_size;k++){
+ float val=x[k]*x[k];
+ if(val>max){
+ max=val;
+ maxpos=k;
+ }
+ rms+=val;
}
- rms+=val;
+ if(active){
+ peakfeed[i][channel]=todB(max)*.5+adj[maxpos];
+ rmsfeed[i][channel]=todB(rms/input_size)*.5+adj[maxpos];
+ }else{
+ peakfeed[i][channel]=todB(max)*.5;
+ rmsfeed[i][channel]=todB(rms/input_size)*.5;
+ }
}
- if(active){
- peakfeed[i][channel]=todB(max)*.5+adj[maxpos];
- rmsfeed[i][channel]=todB(rms/input_size)*.5+adj[maxpos];
- }else{
- peakfeed[i][channel]=todB(max)*.5;
- rmsfeed[i][channel]=todB(rms/input_size)*.5;
- }
}
if(active){
@@ -462,7 +563,8 @@
&ms->base_iir[i][channel],
&ms->base_peak[i][channel],
c->base_mode,
- c->base_ratio,
+ prevset->base_ratio,
+ currset->base_ratio,
(i>=w->freq_bands?0:adj));
if(ss->effect_activeC[channel]){
@@ -540,9 +642,16 @@
for(i=0;i<ms->ch;i++){
int maxbands=find_maxbands(&ms->ss,i);
if(maxbands>maxmaxbands)maxmaxbands=maxbands;
- if(multicompand_work_perchannel(ms, ms->peak, ms->rms, maxbands, i, &multi_master_set))
+ if(multicompand_work_perchannel(ms, ms->peak, ms->rms, maxbands, i,
+ &ms->prevset[i], &ms->currset[i], &multi_master_set))
bypass_visible=0;
}
+ {
+ atten_cache *temp=ms->prevset;
+ ms->prevset=ms->currset;
+ ms->currset=temp;
+ ms->initstate=1;
+ }
push_feedback(ms,bypass_visible,maxmaxbands);
}
@@ -562,9 +671,16 @@
for(i=0;i<ms->ch;i++){
int maxbands=find_maxbands(&ms->ss,i);
if(maxbands>maxmaxbands)maxmaxbands=maxbands;
- if(multicompand_work_perchannel(ms, ms->peak, ms->rms, maxbands, i, multi_channel_set+i))
+ if(multicompand_work_perchannel(ms, ms->peak, ms->rms, maxbands, i,
+ &ms->prevset[i], &ms->currset[i], multi_channel_set+i))
bypass_visible=0;
}
+ {
+ atten_cache *temp=ms->prevset;
+ ms->prevset=ms->currset;
+ ms->currset=temp;
+ ms->initstate=1;
+ }
push_feedback(ms,bypass_visible,maxmaxbands);
}
@@ -607,7 +723,6 @@
return subband_read(in, &master_state.ss, w, visible,active,
multicompand_work_master,&master_state);
-
}
time_linkage *multicompand_read_channel(time_linkage *in){
Modified: trunk/postfish/multicompand.h
===================================================================
--- trunk/postfish/multicompand.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/multicompand.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -60,7 +60,6 @@
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;
@@ -73,7 +72,6 @@
sig_atomic_t under_attack;
sig_atomic_t under_decay;
sig_atomic_t under_lookahead;
- sig_atomic_t under_trim;
sig_atomic_t active_bank;
@@ -90,4 +88,7 @@
extern int pull_multicompand_feedback_channel(float **peak,float **rms,int *bands);
extern int pull_multicompand_feedback_master(float **peak,float **rms,int *bands);
+extern multicompand_settings multi_master_set;
+extern multicompand_settings *multi_channel_set;
+
Added: trunk/postfish/outpanel.c
===================================================================
--- trunk/postfish/outpanel.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/outpanel.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -0,0 +1,341 @@
+/*
+ *
+ * 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 "output.h"
+#include "outpanel.h"
+#include "config.h"
+
+typedef struct {
+ GtkWidget *source[OUTPUT_CHANNELS];
+ GtkWidget *device;
+ GtkWidget *format;
+ GtkWidget *ch;
+ GtkWidget *depth;
+} outsub_state;
+
+typedef struct {
+ GtkWidget *monitor_active;
+ GtkWidget *stdout_active;
+
+ outsub_state monitor;
+ outsub_state stdout;
+} outpanel_state;
+
+outpanel_state state;
+
+void outpanel_state_to_config(int bank){
+ config_set_vector("output_active",bank,0,0,0,2,outset.panel_active);
+
+ config_set_vector("output_monitor_source",bank,0,0,0,OUTPUT_CHANNELS,outset.monitor.source);
+ config_set_integer("output_monitor_set",bank,0,0,0,0,outset.monitor.device);
+ config_set_integer("output_monitor_set",bank,0,0,0,1,outset.monitor.bytes);
+ config_set_integer("output_monitor_set",bank,0,0,0,2,outset.monitor.ch);
+ config_set_integer("output_monitor_set",bank,0,0,0,3,outset.monitor.format);
+
+ config_set_vector("output_stdout_source",bank,0,0,0,OUTPUT_CHANNELS,outset.stdout.source);
+ config_set_integer("output_stdout_set",bank,0,0,0,0,outset.stdout.device);
+ config_set_integer("output_stdout_set",bank,0,0,0,1,outset.stdout.bytes);
+ config_set_integer("output_stdout_set",bank,0,0,0,2,outset.stdout.ch);
+ config_set_integer("output_stdout_set",bank,0,0,0,3,outset.stdout.format);
+}
+
+void outpanel_state_from_config(int bank){
+ int i;
+
+ config_get_vector("output_active",bank,0,0,0,2,outset.panel_active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(state.monitor_active),outset.panel_active[0]);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(state.stdout_active),outset.panel_active[1]);
+
+ config_get_vector("output_monitor_source",bank,0,0,0,OUTPUT_CHANNELS,outset.monitor.source);
+ for(i=0;i<OUTPUT_CHANNELS;i++)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(state.monitor.source[i]),
+ outset.monitor.source[i]);
+
+ config_get_sigat("output_monitor_set",bank,0,0,0,0,&outset.monitor.device);
+ if(state.monitor.device)
+ gtk_option_menu_set_history(GTK_OPTION_MENU(state.monitor.device),outset.monitor.device);
+ config_get_sigat("output_monitor_set",bank,0,0,0,1,&outset.monitor.bytes);
+ if(state.monitor.depth)
+ gtk_option_menu_set_history(GTK_OPTION_MENU(state.monitor.depth),outset.monitor.bytes);
+ config_get_sigat("output_monitor_set",bank,0,0,0,2,&outset.monitor.ch);
+ if(state.monitor.ch)
+ gtk_option_menu_set_history(GTK_OPTION_MENU(state.monitor.ch),outset.monitor.ch);
+ config_get_sigat("output_monitor_set",bank,0,0,0,3,&outset.monitor.format);
+ if(state.monitor.format)
+ gtk_option_menu_set_history(GTK_OPTION_MENU(state.monitor.format),outset.monitor.format);
+
+
+ config_get_vector("output_stdout_source",bank,0,0,0,OUTPUT_CHANNELS,outset.stdout.source);
+ for(i=0;i<OUTPUT_CHANNELS;i++)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(state.stdout.source[i]),
+ outset.stdout.source[i]);
+
+ config_get_sigat("output_stdout_set",bank,0,0,0,0,&outset.stdout.device);
+ if(state.stdout.device)
+ gtk_option_menu_set_history(GTK_OPTION_MENU(state.stdout.device),outset.stdout.device);
+ config_get_sigat("output_stdout_set",bank,0,0,0,1,&outset.stdout.bytes);
+ if(state.stdout.depth)
+ gtk_option_menu_set_history(GTK_OPTION_MENU(state.stdout.depth),outset.stdout.bytes);
+ config_get_sigat("output_stdout_set",bank,0,0,0,2,&outset.stdout.ch);
+ if(state.stdout.ch)
+ gtk_option_menu_set_history(GTK_OPTION_MENU(state.stdout.ch),outset.stdout.ch);
+ config_get_sigat("output_stdout_set",bank,0,0,0,3,&outset.stdout.format);
+ if(state.stdout.format)
+ gtk_option_menu_set_history(GTK_OPTION_MENU(state.stdout.format),outset.stdout.format);
+
+
+}
+
+static void menuchange(GtkWidget *w,gpointer in){
+ sig_atomic_t *var=(sig_atomic_t *)in;
+
+ *var=gtk_option_menu_get_history(GTK_OPTION_MENU(w));
+}
+
+static void buttonchange(GtkWidget *w,gpointer in){
+ sig_atomic_t *var=(sig_atomic_t *)in;
+
+ *var=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
+}
+
+
+static GtkWidget *outpanel_subpanel(postfish_mainpanel *mp,
+ subpanel_generic *panel,
+ output_subsetting *set,
+ char *prompt,
+ int devp,
+ int active,
+ outsub_state *os){
+
+ GtkWidget *frame=gtk_frame_new(prompt);
+ GtkWidget *table=gtk_table_new(4,3,0);
+
+ GtkWidget *l1=gtk_label_new("active channels ");
+ GtkWidget *l2=gtk_label_new(devp?"output device ":"output format ");
+ GtkWidget *l3=gtk_label_new("output channels ");
+ GtkWidget *l4=gtk_label_new("output bit depth ");
+
+ GtkWidget *b1=gtk_hbox_new(1,0);
+ GtkWidget *b2=gtk_hbox_new(1,0);
+ GtkWidget *b3=gtk_hbox_new(1,0);
+ GtkWidget *b4=gtk_hbox_new(1,0);
+
+ gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_ETCHED_IN);
+ gtk_container_set_border_width(GTK_CONTAINER(table),4);
+
+ gtk_misc_set_alignment(GTK_MISC(l1),1.,.5);
+ gtk_misc_set_alignment(GTK_MISC(l2),1.,.5);
+ gtk_misc_set_alignment(GTK_MISC(l3),1.,.5);
+ gtk_misc_set_alignment(GTK_MISC(l4),1.,.5);
+
+ gtk_table_attach_defaults(GTK_TABLE(table),l1,0,1,0,1);
+ gtk_table_attach_defaults(GTK_TABLE(table),l2,0,1,1,2);
+ gtk_table_attach_defaults(GTK_TABLE(table),l3,0,1,2,3);
+ gtk_table_attach_defaults(GTK_TABLE(table),l4,0,1,3,4);
+
+ /* channel buttonx0rz */
+ {
+ int i;
+ char buffer[80];
+ for(i=0;i<OUTPUT_CHANNELS;i++){
+ GtkWidget *b;
+ sprintf(buffer," %d ",i+1);
+
+ b=gtk_toggle_button_new_with_label(buffer);
+
+ gtk_box_pack_start(GTK_BOX(b1),b,0,0,0);
+ // careful; this breaks (cosmetically) for OUTPUT_CHANNELS>8
+ gtk_widget_add_accelerator (b, "activate", mp->group, GDK_1+i, 0, 0);
+ gtk_widget_set_sensitive(b,active);
+ g_signal_connect (G_OBJECT (b), "clicked",
+ G_CALLBACK (buttonchange), &set->source[i]);
+
+ if(i<2)gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b),1);
+ os->source[i]=b;
+ }
+ gtk_table_attach_defaults(GTK_TABLE(table),b1,1,3,0,1);
+ }
+
+
+ {
+ int i;
+ GtkWidget *option_menu=gtk_option_menu_new();
+ GtkWidget *menu=gtk_menu_new();
+
+ if(devp){
+ /* device selection */
+ for(i=0;i<monitor_entries;i++){
+ GtkWidget *item=gtk_menu_item_new_with_label(monitor_list[i].name);
+ gtk_menu_shell_append (GTK_MENU_SHELL(menu),item);
+ }
+
+ if(i==0){
+ GtkWidget *item=gtk_menu_item_new_with_label("stdout");
+ gtk_menu_shell_append (GTK_MENU_SHELL(menu),item);
+ }
+
+ g_signal_connect (G_OBJECT (option_menu), "changed",
+ G_CALLBACK (menuchange), &set->device);
+
+ os->device=option_menu;
+ os->format=0;
+ }else{
+
+ /* format selection */
+ int i;
+ char *formats[]={"WAV","AIFF-C","raw (little endian)","raw (big endian)"};
+
+ for(i=0;i<4;i++){
+ GtkWidget *item=gtk_menu_item_new_with_label(formats[i]);
+ gtk_menu_shell_append (GTK_MENU_SHELL(menu),item);
+ }
+ g_signal_connect (G_OBJECT (option_menu), "changed",
+ G_CALLBACK (menuchange), &set->format);
+ os->format=option_menu;
+ os->device=0;
+ }
+
+ gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu),menu);
+ gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),0);
+
+ gtk_box_pack_start(GTK_BOX(b2),option_menu,1,1,0);
+
+ gtk_widget_set_sensitive(option_menu,active);
+ gtk_widget_set_sensitive(menu,active);
+
+ }
+ gtk_table_attach(GTK_TABLE(table),b2,1,2,1,2,GTK_FILL,0,0,0);
+
+
+ {
+ /* channels selection */
+ int i;
+ GtkWidget *option_menu=gtk_option_menu_new();
+ GtkWidget *menu=gtk_menu_new();
+ char *formats[]={"auto","1","2","4","6","8"};
+
+ for(i=0;i<6;i++){
+ GtkWidget *item=gtk_menu_item_new_with_label(formats[i]);
+ gtk_menu_shell_append (GTK_MENU_SHELL(menu),item);
+ }
+
+ gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu),menu);
+ gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),0);
+
+ gtk_box_pack_start(GTK_BOX(b3),option_menu,1,1,0);
+ gtk_widget_set_sensitive(option_menu,active);
+ gtk_widget_set_sensitive(menu,active);
+ g_signal_connect (G_OBJECT (option_menu), "changed",
+ G_CALLBACK (menuchange), &set->ch);
+ os->ch=option_menu;
+ }
+ gtk_table_attach(GTK_TABLE(table),b3,1,2,2,3,GTK_FILL,0,0,0);
+
+
+ {
+ /* bit depth selection */
+ int i;
+ GtkWidget *option_menu=gtk_option_menu_new();
+ GtkWidget *menu=gtk_menu_new();
+ char *formats[]={"auto","8","16","24"};
+
+ for(i=0;i<4;i++){
+ GtkWidget *item=gtk_menu_item_new_with_label(formats[i]);
+ gtk_menu_shell_append (GTK_MENU_SHELL(menu),item);
+ }
+
+ gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu),menu);
+ gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),0);
+
+ gtk_box_pack_start(GTK_BOX(b4),option_menu,1,1,0);
+ gtk_widget_set_sensitive(option_menu,active);
+ gtk_widget_set_sensitive(menu,active);
+
+ g_signal_connect (G_OBJECT (option_menu), "changed",
+ G_CALLBACK (menuchange), &set->bytes);
+
+ os->depth=option_menu;
+ }
+ gtk_table_attach(GTK_TABLE(table),b4,1,2,3,4,GTK_FILL,0,0,0);
+
+ gtk_table_set_row_spacing(GTK_TABLE(table),0,5);
+
+ gtk_container_add(GTK_CONTAINER(frame),table);
+ return frame;
+}
+
+void outpanel_create(postfish_mainpanel *mp,
+ GtkWidget *windowbutton,
+ GtkWidget **activebutton){
+
+ char *shortcuts[]={"mOn"," o "};
+
+ subpanel_generic *panel=subpanel_create(mp,windowbutton,activebutton,
+ outset.panel_active,
+ &outset.panel_visible,
+ "_Output configuration",shortcuts,
+ 0,2);
+
+ GtkWidget *box=gtk_hbox_new(1,0);
+ GtkWidget *monitor_panel=outpanel_subpanel(mp,panel,&outset.monitor,
+ " audio monitor output ",
+ 1,output_monitor_available,
+ &state.monitor);
+ GtkWidget *stdout_panel=outpanel_subpanel(mp,panel,&outset.stdout,
+ " standard output ",
+ output_stdout_device,
+ output_stdout_available,
+ &state.stdout);
+
+ gtk_box_pack_start(GTK_BOX(box),monitor_panel,0,0,0);
+ gtk_box_pack_start(GTK_BOX(box),stdout_panel,0,0,2);
+
+ if(!output_monitor_available)gtk_widget_set_sensitive(activebutton[0],0);
+ if(!output_monitor_available)gtk_widget_set_sensitive(panel->subpanel_activebutton[0],0);
+ if(!output_stdout_available)gtk_widget_set_sensitive(activebutton[1],0);
+ if(!output_stdout_available)gtk_widget_set_sensitive(panel->subpanel_activebutton[1],0);
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(activebutton[0]),1);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(activebutton[1]),1);
+
+ gtk_container_add(GTK_CONTAINER(panel->subpanel_box),box);
+ subpanel_show_all_but_toplevel(panel);
+
+ state.monitor_active=activebutton[0];
+ state.stdout_active=activebutton[1];
+}
+
+void outpanel_monitor_off(){
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(state.monitor_active),0);
+}
+
+void outpanel_stdout_off(){
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(state.stdout_active),0);
+}
Added: trunk/postfish/outpanel.h
===================================================================
--- trunk/postfish/outpanel.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/outpanel.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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 outpanel_create(postfish_mainpanel *mp,
+ GtkWidget *windowbutton,
+ GtkWidget **activebutton);
+
+extern void outpanel_state_to_config(int bank);
+extern void outpanel_state_from_config(int bank);
Modified: trunk/postfish/output.c
===================================================================
--- trunk/postfish/output.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/output.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -38,11 +38,14 @@
#include "mix.h"
#include "reverb.h"
+output_settings outset;
+
extern int input_size;
extern int input_rate;
sig_atomic_t playback_active=0;
sig_atomic_t playback_exit=0;
sig_atomic_t playback_seeking=0;
+sig_atomic_t master_att;
void output_reset(void){
/* empty feedback queues */
@@ -81,27 +84,25 @@
static feedback_generic *new_output_feedback(void){
output_feedback *ret=malloc(sizeof(*ret));
- ret->rms=malloc((input_ch+2)*sizeof(*ret->rms));
- ret->peak=malloc((input_ch+2)*sizeof(*ret->peak));
+ ret->rms=malloc(OUTPUT_CHANNELS*sizeof(*ret->rms));
+ ret->peak=malloc(OUTPUT_CHANNELS*sizeof(*ret->peak));
return (feedback_generic *)ret;
}
static void push_output_feedback(float *peak,float *rms){
- int n=input_ch+2;
output_feedback *f=(output_feedback *)
feedback_new(&feedpool,new_output_feedback);
- memcpy(f->rms,rms,n*sizeof(*rms));
- memcpy(f->peak,peak,n*sizeof(*peak));
+ memcpy(f->rms,rms,OUTPUT_CHANNELS*sizeof(*rms));
+ memcpy(f->peak,peak,OUTPUT_CHANNELS*sizeof(*peak));
feedback_push(&feedpool,(feedback_generic *)f);
}
int pull_output_feedback(float *peak,float *rms){
output_feedback *f=(output_feedback *)feedback_pull(&feedpool);
- 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);
+ if(rms)memcpy(rms,f->rms,sizeof(*rms)*OUTPUT_CHANNELS);
+ if(peak)memcpy(peak,f->peak,sizeof(*peak)*OUTPUT_CHANNELS);
feedback_old(&feedpool,(feedback_generic *)f);
return 1;
}
@@ -118,6 +119,70 @@
}
}
+static void PutNumBE(long num,FILE *f,int bytes){
+ switch(bytes){
+ case 4:
+ fputc((num>>24)&0xff,f);
+ case 3:
+ fputc((num>>16)&0xff,f);
+ case 2:
+ fputc((num>>8)&0xff,f);
+ case 1:
+ fputc(num&0xff,f);
+ }
+}
+
+/* Borrowed from sox */
+# define FloatToUnsigned(f) ((u_int32_t)(((int32_t)(f - 2147483648.0)) + 2147483647L) + 1)
+static void ConvertToIeeeExtended(double num, char *bytes){
+ int sign;
+ int expon;
+ double fMant, fsMant;
+ u_int32_t hiMant, loMant;
+
+ if (num < 0) {
+ sign = 0x8000;
+ num *= -1;
+ } else {
+ sign = 0;
+ }
+
+ if (num == 0) {
+ expon = 0; hiMant = 0; loMant = 0;
+ }
+ else {
+ fMant = frexp(num, &expon);
+ if ((expon > 16384) || !(fMant < 1)) { /* Infinity or NaN */
+ expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */
+ }
+ else { /* Finite */
+ expon += 16382;
+ if (expon < 0) { /* denormalized */
+ fMant = ldexp(fMant, expon);
+ expon = 0;
+ }
+ expon |= sign;
+ fMant = ldexp(fMant, 32);
+ fsMant = floor(fMant);
+ hiMant = FloatToUnsigned(fsMant);
+ fMant = ldexp(fMant - fsMant, 32);
+ fsMant = floor(fMant);
+ loMant = FloatToUnsigned(fsMant);
+ }
+ }
+
+ bytes[0] = expon >> 8;
+ bytes[1] = expon;
+ bytes[2] = hiMant >> 24;
+ bytes[3] = hiMant >> 16;
+ bytes[4] = hiMant >> 8;
+ bytes[5] = hiMant;
+ bytes[6] = loMant >> 24;
+ bytes[7] = loMant >> 16;
+ bytes[8] = loMant >> 8;
+ bytes[9] = loMant;
+}
+
static void WriteWav(FILE *f,long channels,long rate,long bits,long duration){
if(ftell(f)>0)
if(fseek(f,0,SEEK_SET))
@@ -136,14 +201,72 @@
PutNumLE(duration,f,4);
}
-static int isachr(FILE *f){
+void WriteAifc(FILE *f,long channels,long rate,long bits,long duration){
+ int bytes=(bits+7)/8;
+ long size=duration+86;
+ long frames=duration/bytes/channels;
+ char ieee[10];
+
+ if(ftell(f)>0)
+ if(fseek(f,0,SEEK_SET))
+ return;
+
+ /* Again, quick and dirty */
+
+ fprintf(f,"FORM");
+ if(duration>0)
+ PutNumBE(size-8,f,4);
+ else
+ PutNumBE(0,f,4);
+ fprintf(f,"AIFC");
+ fprintf(f,"FVER");
+ PutNumBE(4,f,4);
+ PutNumBE(2726318400UL,f,4);
+
+ fprintf(f,"COMM");
+ PutNumBE(38,f,4);
+ PutNumBE(channels,f,2);
+ if(duration>0)
+ PutNumBE(frames,f,4);
+ else
+ PutNumBE(-1,f,4);
+
+ PutNumBE(bits,f,2);
+ ConvertToIeeeExtended(rate,ieee);
+ fwrite(ieee,1,10,f);
+
+ fprintf(f,"NONE");
+ PutNumBE(14,f,1);
+ fprintf(f,"not compressed");
+ PutNumBE(0,f,1);
+
+ fprintf(f,"SSND");
+ if(duration>0)
+ PutNumBE(duration+8,f,4);
+ else
+ PutNumBE(0,f,4);
+
+ PutNumBE(0,f,4);
+ PutNumBE(0,f,4);
+
+}
+
+static int isachr(int f){
struct stat s;
- if(!fstat(fileno(f),&s))
+ if(!fstat(f,&s))
if(S_ISCHR(s.st_mode)) return 1;
return 0;
}
+static int isareg(int f){
+ struct stat s;
+
+ if(!fstat(f,&s))
+ if(S_ISREG(s.st_mode)) return 1;
+ return 0;
+}
+
static int ilog(long x){
int ret=-1;
@@ -154,93 +277,559 @@
return ret;
}
-static int outbytes;
-static FILE *playback_startup(int outfileno, int ch, int r, int *bep){
- FILE *playback_fd=NULL;
- int rate=r,channels=ch,ret;
+static int is_oss(int f){
+ struct stat s;
- if(outfileno==-1){
- playback_fd=fopen("/dev/dsp","wb");
+ if(isachr(f))
+ if(!fstat(f,&s)){
+ int major=(int)(s.st_rdev>>8)&0xff;
+ int minor=(int)(s.st_rdev&0xff);
+
+ // is this a Linux OSS audio device (Major 14) ?
+ if(major==14 && ((minor&0xf)==3 || (minor&0xf)==4))return 1;
+ }
+
+ return 0;
+}
+
+static int is_alsa(int f){
+ struct stat s;
+
+ if(isachr(f))
+ if(!fstat(f,&s)){
+ int type=(int)(s.st_rdev>>8);
+
+ // is this a Linux ALSA audio device (Major 116) ?
+ if(type==116)return 1;
+ }
+
+ return 0;
+}
+
+static int isaudio(int outfileno){
+ if(is_oss(outfileno))return 1;
+ if(is_alsa(outfileno))return 2;
+ return 0;
+}
+
+int output_stdout_available=0;
+int output_stdout_device=0; /* 0== file, 1==OSS, 2==ALSA */
+int output_monitor_available=0;
+
+int output_probe_stdout(int outfileno){
+ int ret;
+
+ if(isatty(outfileno)){
+ /* stdout is the terminal; disable stdout */
+ output_stdout_available=0;
+
+ }else if (isareg(outfileno)){
+ /* stdout is a regular file */
+ output_stdout_available=1;
+ output_stdout_device=0;
+
+ }else if((ret==isaudio(outfileno))){
+ /* stdout is an audio device */
+
+ output_stdout_available=1;
+ output_stdout_device=ret;
+
+ if(ret==2){
+ fprintf(stderr,
+ "\nStdout is pointing to an ALSA sound device;\n"
+ "Postfish does not yet support ALSA playback.\n\n");
+ exit(1);
+ }
}else{
- playback_fd=fdopen(dup(outfileno),"wb");
+ /* God only knows what stdout is. It might be /dev/null or some other.... treat it similar to file */
+
+ output_stdout_available=1;
+ output_stdout_device=0;
+
}
- if(!playback_fd){
- fprintf(stderr,"Unable to open output for playback\n");
- return NULL;
+ return 0;
+}
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+output_monitor_entry *monitor_list;
+int monitor_entries;
+
+static char *audio_dev_type[]={"file","OSS"};
+
+/* look for sound devices that actually exist */
+
+static void add_monitor(char *file, char *name,int type){
+ monitor_entries++;
+ if(monitor_list){
+ monitor_list=realloc(monitor_list,
+ monitor_entries*sizeof(*monitor_list));
+ }else
+ monitor_list=malloc(monitor_entries*sizeof(*monitor_list));
+
+ monitor_list[monitor_entries-1].file=strdup(file);
+ monitor_list[monitor_entries-1].name=strdup(name);
+ monitor_list[monitor_entries-1].type=type;
+
+ fprintf(stderr,"Found an output device (type %s): %s\n",
+ audio_dev_type[type],file);
+}
+
+static void output_probe_monitor_OSS(){
+ /* open /dev and search of major 14 */
+ DIR *d=opendir("/dev");
+ struct dirent *de;
+
+ if(d==NULL){
+ fprintf(stderr,"Odd; could not open /dev to look for audio devices.\n");
+ return;
}
+
+ while((de=readdir(d))){
+ struct stat s;
+ char buf[PATH_MAX];
+ snprintf(buf,PATH_MAX,"/dev/%s",de->d_name);
+ if(!stat(buf,&s)){
+
+ int major=(int)(s.st_rdev>>8)&0xff;
+ int minor=(int)(s.st_rdev&0xff);
+
+ // is this a Linux OSS dsp audio device (Major 14, minor 3,19,35...) ?
+ if(major==14 && (minor&0xf)==3){
+ int f=open(buf,O_RDWR|O_NONBLOCK);
+ if(f!=-1){
+ add_monitor(buf,de->d_name,1);
+ close(f);
+ }
+ }
+ }
+ }
+
+ closedir(d);
+}
- /* is this file a block device? */
- if(isachr(playback_fd)){
- long bytesperframe=input_size*ch*2;
- int fd=fileno(playback_fd);
- int format=AFMT_S16_NE;
- int fraglog=ilog(bytesperframe);
- int fragment=0x00040000|fraglog;
- outbytes=2;
+static int moncomp(const void *a, const void *b){
+ output_monitor_entry *ma=(output_monitor_entry *)a;
+ output_monitor_entry *mb=(output_monitor_entry *)b;
+ return(strcmp(ma->name,mb->name));
+}
+int output_probe_monitor(void ){
+ if(output_stdout_device!=0){
+ output_monitor_available=0;
+ return 0;
+ }
+
+ output_probe_monitor_OSS();
+
+ if(monitor_entries>0){
+ output_monitor_available=1;
+
+ /* sort the entries alphabetically by name */
+ qsort(monitor_list, monitor_entries, sizeof(*monitor_list), moncomp);
+ }
+
+ return 0;
+}
+
+#ifndef AFMT_S24_LE
+# define AFMT_S24_LE 0x00000800
+# define AFMT_S24_BE 0x00001000
+# define AFMT_U24_LE 0x00002000
+# define AFMT_U24_BE 0x00004000
+#endif
+
+static int OSS_playback_startup(FILE *f, int rate, int *ch, int *endian, int *bits,int *signp){
+ int fd=fileno(f);
+ int downgrade=0;
+ int failflag=1;
+ int local_ch=*ch;
+ int local_bits=*bits;
+
+ *endian=(AFMT_S16_NE==AFMT_S16_BE?1:0);
+
+ /* try to configure requested playback. If it fails, keep dropping back
+ until one works */
+ while(local_ch || local_bits>16){
+ int format;
+
+ switch(local_bits){
+ case 8:
+ format=AFMT_U8;
+ *signp=0;
+ break;
+ case 16:
+ format=AFMT_S16_NE;
+ *signp=1;
+ break;
+ case 24:
+ format=AFMT_S24_LE;
+ if(*endian)format=AFMT_S24_BE;
+ *signp=1;
+ break;
+ }
+
/* try to lower the DSP delay; this ioctl may fail gracefully */
- ret=ioctl(fd,SNDCTL_DSP_SETFRAGMENT,&fragment);
- if(ret){
- fprintf(stderr,"Could not set DSP fragment size; continuing.\n");
+ {
+
+ long bytesperframe=input_size*local_ch*2;
+ int fraglog=ilog(bytesperframe);
+ int fragment=0x00040000|fraglog;
+
+ int ret=ioctl(fd,SNDCTL_DSP_SETFRAGMENT,&fragment);
+ if(ret){
+ fprintf(stderr,"Could not set DSP fragment size; continuing.\n");
+ }
}
+
+ /* format, channels, rate */
+ {
+ int temp=format;
+ int ret=ioctl(fd,SNDCTL_DSP_SETFMT,&temp);
+ if(ret || format!=temp) goto failset;
+ }
+
+ {
+ int temp=local_ch;
+ int ret=ioctl(fd,SNDCTL_DSP_CHANNELS,&temp);
+ if(ret || temp!=local_ch) goto failset;
+ }
+
+ {
+ int temp=rate;
+ int ret=ioctl(fd,SNDCTL_DSP_SPEED,&temp);
+ if(ret || temp!=rate) goto failset;
+ }
+
+ failflag=0;
+ break;
+
+ failset:
+ downgrade=1;
+
+ /* first try decreasing bit depth */
+ if(local_bits==24){
+ local_bits=16;
+ }else{
+
+ /* next, drop channels */
+ local_bits=*bits;
+ local_ch--;
+ }
+
+ ioctl(fd,SNDCTL_DSP_RESET);
+ }
- ret=ioctl(fd,SNDCTL_DSP_SETFMT,&format);
- if(ret || format!=AFMT_S16_NE){
- fprintf(stderr,"Could not set AFMT_S16_NE playback\n");
- exit(1);
+ if(failflag || downgrade)
+ fprintf(stderr,"Unable to set playback for %d bits, %d channels, %dHz\n",
+ *bits,*ch,rate);
+ if(downgrade && !failflag)
+ fprintf(stderr,"\tUsing %d bits, %d channels, %dHz instead\n",
+ local_bits,local_ch,rate);
+ if(failflag)return -1;
+
+ *bits=local_bits;
+ *ch=local_ch;
+
+ return 0;
+}
+
+static int output_startup(FILE *f, int devtype, int format, int rate, int *ch, int *endian, int *bits,int *signp){
+ switch(devtype){
+ case 0: // pipe, regular file or file device
+ switch(format){
+ case 0:
+ /* WAVE format */
+ ftruncate(fileno(f),0);
+ WriteWav(f,*ch,rate,*bits,-1);
+ *endian=0;
+ *signp=1;
+ if(*bits==8)*signp=0;
+ break;
+ case 1:
+ /* AIFF-C format */
+ ftruncate(fileno(f),0);
+ WriteAifc(f,*ch,rate,*bits,-1);
+ *endian=1;
+ *signp=1;
+ break;
+ case 2:
+ /* raw little endian */
+ *endian=0;
+ *signp=1;
+ if(*bits==8)*signp=0;
+ break;
+ case 3:
+ /* raw big endian */
+ *endian=1;
+ *signp=1;
+ if(*bits==8)*signp=0;
+ break;
+ default:
+ fprintf(stderr,"Unsupported output file format selected!\n");
+ return -1;
}
- ret=ioctl(fd,SNDCTL_DSP_CHANNELS,&channels);
- if(ret || channels!=ch){
- fprintf(stderr,"Could not set %d channel playback\n",ch);
- exit(1);
+ return 0;
+
+ case 1: // OSS playback
+ return OSS_playback_startup(f, rate, ch, endian, bits, signp);
+
+ default: // undefined for now
+ fprintf(stderr,"Unsupported playback device selected\n");
+ return -1;
+ }
+}
+
+static void output_halt(FILE *f,int devtype,int format, int rate, int ch, int endian, int bits,int signp,
+ off_t bytecount){
+ switch(devtype){
+ case 0:
+ switch(format){
+ case 0:
+ WriteWav(f,ch,rate,bits,bytecount); // will complete header only if stream is seekable
+ break;
+ case 1:
+ WriteAifc(f,ch,rate,bits,bytecount); // will complete header only if stream is seekable
+ break;
}
- ret=ioctl(fd,SNDCTL_DSP_SPEED,&rate);
- if(ret || r!=rate){
- fprintf(stderr,"Could not set %dHz playback\n",r);
- exit(1);
+ break;
+ case 1: // OSS
+ {
+ int fd=fileno(f);
+ ioctl(fd,SNDCTL_DSP_RESET);
}
- }else{
- outbytes=3;
- WriteWav(playback_fd,ch,r,24,-1);
- *bep=0;
}
+}
- return playback_fd;
+static int outpack(time_linkage *link,unsigned char *audiobuf,
+ int ch,int bits,int endian,
+ int signp,int *source){
+ int bytes=(bits+7)>>3;
+ int32_t signxor=(signp?0:0x800000L);
+ int bytestep=bytes*(ch-1);
+
+ int endbytecase=endian*3+(bytes-1);
+ int j,i;
+ for(j=0;j<ch;j++){
+ unsigned char *o=audiobuf+bytes*j;
+ if(!mute_channel_muted(link->active,j) && source[j]){
+
+ float *d=link->data[j];
+
+ for(i=0;i<link->samples;i++){
+ float dval=d[i];
+ int32_t val=rint(dval*8388608.);
+ if(val>8388607)val=8388607;
+ if(val<-8388608)val=-8388608;
+ val ^= signxor;
+
+ switch(endbytecase){
+ case 2:
+ /* LE 24 */
+ *o++=val;
+ // fall through
+ case 1:
+ /* LE 16 */
+ *o++=val>>8;
+ // fall through
+ case 0:case 3:
+ /* 8 */
+ *o++=val>>16;
+ break;
+ case 4:
+ /* BE 16 */
+ *o++=val>>16;
+ *o++=val>>8;
+ break;
+ case 5:
+ /* BE 24 */
+ *o++=val>>16;
+ *o++=val>>8;
+ *o++=val;
+ break;
+ }
+
+ o+=bytestep;
+ }
+ }else{
+ for(i=0;i<link->samples;i++){
+ int32_t val = signxor;
+
+ switch(endbytecase){
+ case 2:case 5:
+ /* 24 */
+ *o++=val;
+ // fall through
+ case 1:case 4:
+ /* LE 16 */
+ *o++=val>>8;
+ // fall through
+ case 0:case 3:
+ /* 8 */
+ *o++=val>>16;
+ break;
+ }
+
+ o+=bytestep;
+ }
+ }
+ }
+ return bytes*ch*link->samples;
}
-/* playback must be halted to change blocksize. */
+extern pthread_mutex_t input_mutex;
+extern mix_settings *mix_set;
+
+/* playback must be halted for new output settings to take hold */
void *playback_thread(void *dummy){
- int audiobufsize=0,i,j,k;
- unsigned char *audiobuf=NULL;
+ int i,j,k;
+ unsigned char *audiobuf;
int bigendianp=(AFMT_S16_NE==AFMT_S16_BE?1:0);
- FILE *playback_fd=NULL;
- int setupp=0;
time_linkage *link;
int result;
- off_t count=0;
+ off_t output_bytecount=0;
- int ch=-1;
- long rate=-1;
+ int att_last=master_att;
/* for output feedback */
- float *rms=alloca(sizeof(*rms)*(input_ch+2));
- float *peak=alloca(sizeof(*peak)*(input_ch+2));
+ float *rms=alloca(sizeof(*rms)*OUTPUT_CHANNELS);
+ float *peak=alloca(sizeof(*peak)*OUTPUT_CHANNELS);
+ long offset=0;
+
+ /* monitor setup */
+ FILE *monitor_fd=NULL;
+ int monitor_bits;
+ int monitor_ch;
+ int monitor_endian=bigendianp;
+ int monitor_signp=1;
+ int monitor_started=0;
+ int monitor_devicenum=outset.monitor.device;
+
+ int stdout_bits;
+ int stdout_ch;
+ int stdout_endian;
+ int stdout_signp=1;
+ int stdout_started=0;
+ int stdout_format=outset.stdout.format;
+
+ /* inspect mixdown; how many channels are in use? */
+ {
+ for(j=OUTPUT_CHANNELS-1;j>=0;j--){
+ for(i=0;i<input_ch;i++){
+ mix_settings *m=mix_set+i;
+
+ if(m->placer_destA[j] ||
+ m->placer_destB[j])break;
+
+ for(k=0;k<MIX_BLOCKS;k++)
+ if(m->insert_dest[k][j])break;
+ if(k<MIX_BLOCKS)break;
+ }
+ if(i<input_ch)break;
+ }
+ monitor_ch=stdout_ch=j+1;
+ }
+
+ if(output_monitor_available){
+ int ch=outset.monitor.ch;
+ int bits=outset.monitor.bytes;
+
+ /* channels */
+ switch(ch){
+ case 0:
+ break;
+ case 1:case 2:
+ monitor_ch=ch;
+ break;
+ default:
+ monitor_ch=(ch-1)*2;
+ break;
+ }
+
+ /* bits */
+ switch(bits){
+ case 0:case 2:
+ /* 'auto', 16 */
+ monitor_bits=16;
+ break;
+ case 1:
+ monitor_bits=8;
+ break;
+ case 3:
+ monitor_bits=24;
+ break;
+ }
+ }
+
+ if(output_stdout_available){
+ int ch=outset.stdout.ch;
+ int bits=outset.stdout.bytes;
+
+ /* channels */
+ switch(ch){
+ case 0:
+ break;
+ case 1:case 2:
+ stdout_ch=ch;
+ break;
+ default:
+ stdout_ch=(ch-1)*2;
+ break;
+ }
+
+ /* bits */
+ switch(bits){
+ case 0:
+ if(output_stdout_device)
+ stdout_bits=16;
+ else
+ stdout_bits=24;
+ break;
+ case 1:
+ stdout_bits=8;
+ break;
+ case 2:
+ stdout_bits=16;
+ break;
+ case 3:
+ stdout_bits=24;
+ break;
+ }
+
+ }
+
+ audiobuf=malloc(input_size*OUTPUT_CHANNELS*4); // largest possible need
+
while(1){
+
+ /* the larger lock against seeking is primarily cosmetic, but
+ keeps the metadata strictly in sync. This lock is only against
+ seeks. */
+ pthread_mutex_lock(&input_mutex);
+
if(playback_seeking){
pipeline_reset();
playback_seeking=0;
}
+
+ if(playback_exit){
+ pthread_mutex_unlock(&input_mutex);
+ break;
+ }
+
+ offset+=input_size;
- if(playback_exit)break;
-
/* get data */
link=input_read();
result=link->samples;
+ pthread_mutex_unlock(&input_mutex);
+
+ /* channel pipeline */
link=mute_read(link);
result|=link->samples;
-
link=declip_read(link);
result|=link->samples;
link=multicompand_read_channel(link);
@@ -263,6 +852,7 @@
result|=link->samples;
}
+ /* master pipeline */
link=multicompand_read_master(link);
result|=link->samples;
link=singlecomp_read_master(link);
@@ -271,18 +861,33 @@
result|=link->samples;
link=plate_read_master(link);
result|=link->samples;
-
+
if(!result)break;
/************/
/* master att */
if(link->samples>0){
- float scale=fromdB(master_att/10.);
- for(i=0;i<link->samples;i++)
- for(j=0;j<link->channels;j++)
- link->data[j][i]*=scale;
- }
+ int att=master_att;
+ if(att==att_last){
+ float scale=fromdB(att/10.);
+
+ for(i=0;i<link->samples;i++)
+ for(j=0;j<link->channels;j++)
+ link->data[j][i]*=scale;
+ }else{
+ /* slew-limit the scaling */
+ float scale=fromdB(att_last*.1);
+ float mult=fromdB((att-att_last)*.1 / input_size);
+
+ for(i=0;i<link->samples;i++){
+ for(j=0;j<link->channels;j++)
+ link->data[j][i]*=scale;
+ scale*=mult;
+ }
+ att_last=att;
+ }
+ }
link=limit_read(link);
@@ -290,132 +895,141 @@
if(link->samples>0){
- memset(rms,0,sizeof(*rms)*(input_ch+2));
- memset(peak,0,sizeof(*peak)*(input_ch+2));
- ch=link->channels;
- rate=input_rate;
+ /* final limiting and conversion */
+
+ /* monitor output */
+ if(output_monitor_available){
+ if(outset.panel_active[0]){
+
+ /* lazy playback init */
+ if(!monitor_started){
- /* temporary! */
- if(ch>2)ch=2;
-
- /* lazy playbak setup; we couldn't do it until we had rate and
- channel information from the pipeline */
- if(!setupp){
- playback_fd=playback_startup(outfileno,ch,rate,&bigendianp);
- if(!playback_fd){
- playback_active=0;
- playback_exit=0;
- return NULL;
+ /* nonblocking open... just in case this is an exclusive
+ use device currently used by something else */
+ int mfd=open(monitor_list[monitor_devicenum].file,O_RDWR|O_NONBLOCK);
+ if(mfd==-1){
+ fprintf(stderr,"unable to open audio monitor device %s for playback.\n",
+ monitor_list[monitor_devicenum].file);
+ outpanel_monitor_off();
+ }else{
+ fcntl(mfd,F_SETFL,0); /* unset non-blocking */
+ monitor_fd=fdopen(dup(mfd),"wb");
+ close(mfd);
+ if(monitor_fd==NULL){
+ fprintf(stderr,"unable to fdopen audio monitor device %s for playback.\n",
+ monitor_list[monitor_devicenum].file);
+ outpanel_monitor_off();
+ }else{
+ if(output_startup(monitor_fd,monitor_list[monitor_devicenum].type,0,input_rate,
+ &monitor_ch,&monitor_endian,&monitor_bits,&monitor_signp)){
+ outpanel_monitor_off();
+ fclose(monitor_fd);
+ monitor_fd=NULL;
+ }else
+ monitor_started=1;
+ }
+ }
+ }
+
+ if(monitor_started){
+ int outbytes=outpack(link,audiobuf,monitor_ch,
+ monitor_bits,monitor_endian,monitor_signp,
+ outset.monitor.source);
+
+ fwrite(audiobuf,1,outbytes,monitor_fd);
+ }
+ }else{
+ if(monitor_started){
+ /* halt playback */
+ output_halt(monitor_fd,monitor_list[monitor_devicenum].type,0,input_rate,monitor_ch,
+ monitor_endian,monitor_bits,monitor_signp,-1);
+ fclose(monitor_fd);
+ monitor_fd=NULL;
+ monitor_started=0;
+ }
}
- setupp=1;
}
- if(audiobufsize<ch*link->samples*outbytes){
- audiobufsize=ch*link->samples*outbytes;
- if(audiobuf)
- audiobuf=realloc(audiobuf,sizeof(*audiobuf)*audiobufsize);
- else
- audiobuf=malloc(sizeof(*audiobuf)*audiobufsize);
- }
-
- /* final limiting and conversion */
+ /* standard output */
+ if(output_stdout_available){
+ if(outset.panel_active[1]){
- for(k=0,i=0;i<link->samples;i++){
- float mean=0.;
- float divrms=0.;
-
- for(j=0;j<ch;j++){
- float dval=link->data[j][i];
+ /* lazy playback/header init */
+ if(!stdout_started){
+ if(output_startup(stdout,output_stdout_device,stdout_format,input_rate,
+ &stdout_ch,&stdout_endian,&stdout_bits,&stdout_signp))
+ outpanel_stdout_off();
+ else
+ stdout_started=1;
+ }
- switch(outbytes){
- case 3:
- {
- int32_t val=rint(dval*8388608.);
- if(val>8388607)val=8388607;
- if(val<-8388608)val=-8388608;
-
- if(bigendianp){
- audiobuf[k++]=val>>16;
- audiobuf[k++]=val>>8;
- audiobuf[k++]=val;
- }else{
- audiobuf[k++]=val;
- audiobuf[k++]=val>>8;
- audiobuf[k++]=val>>16;
- }
+ if(stdout_started){
+ int outbytes=outpack(link,audiobuf,stdout_ch,
+ stdout_bits,stdout_endian,stdout_signp,
+ outset.stdout.source);
+
+ output_bytecount+=fwrite(audiobuf,1,outbytes,stdout);
+ }
+ }else{
+ if(stdout_started){
+ /* if stdout is a device, halt playback. Otherwise, write nothing */
+ if(output_stdout_device){
+ /* halt playback */
+ output_halt(stdout,output_stdout_device,0,input_rate,stdout_ch,stdout_endian,
+ stdout_bits,stdout_signp,-1);
+ stdout_started=0;
}
- break;
- case 2:
- {
- int32_t val=rint(dval*32768.);
- if(val>32767)val=32767;
- if(val<-32768)val=-32768;
- if(bigendianp){
- audiobuf[k++]=val>>8;
- audiobuf[k++]=val;
- }else{
- audiobuf[k++]=val;
- audiobuf[k++]=val>>8;
- }
- }
- break;
- }
-
- if(fabs(dval)>peak[j])peak[j]=fabs(dval);
- rms[j]+= dval*dval;
- mean+=dval;
-
+ }
}
-
- /* mean */
- mean/=j;
- if(fabs(mean)>peak[input_ch])peak[input_ch]=fabs(mean);
- rms[input_ch]+= mean*mean;
-
- /* div */
- for(j=0;j<ch;j++){
- float dval=mean-link->data[j][i];
- if(fabs(dval)>peak[input_ch+1])peak[input_ch+1]=fabs(dval);
- divrms+=dval*dval;
- }
- rms[input_ch+1]+=divrms/ch;
-
}
- for(j=0;j<input_ch+2;j++){
+ /* feedback */
+ memset(rms,0,sizeof(*rms)*OUTPUT_CHANNELS);
+ memset(peak,0,sizeof(*peak)*OUTPUT_CHANNELS);
+
+ for(j=0;j<OUTPUT_CHANNELS;j++){
+ if(!mute_channel_muted(link->active,j))
+ for(i=0;i<link->samples;i++){
+ float dval=link->data[j][i];
+ dval*=dval;
+ if(dval>peak[j])peak[j]=dval;
+ rms[j]+= dval;
+ }
+ }
+
+ for(j=0;j<OUTPUT_CHANNELS;j++)
rms[j]/=link->samples;
- rms[j]=sqrt(rms[j]);
- }
-
- count+=fwrite(audiobuf,1,ch*link->samples*outbytes,playback_fd);
-
+
/* inform Lord Vader his shuttle is ready */
push_output_feedback(peak,rms);
-
+
write(eventpipe[1],"",1);
-
}
+ }
+ /* shut down monitor */
+ if(monitor_fd){
+ if(monitor_started)
+ output_halt(monitor_fd,monitor_list[monitor_devicenum].type,0,input_rate,monitor_ch,
+ monitor_endian,monitor_bits,monitor_signp,-1);
+ fclose(monitor_fd);
}
- if(playback_fd){
- if(isachr(playback_fd)){
- int fd=fileno(playback_fd);
- ioctl(fd,SNDCTL_DSP_RESET);
- }else{
- if(ch>-1)
- WriteWav(playback_fd,ch,rate,24,count);
- }
- fclose(playback_fd);
- }
+ /* shut down stdout playback or write final header */
+ if(stdout_started)
+ output_halt(stdout,output_stdout_device,stdout_format,input_rate,stdout_ch,stdout_endian,
+ stdout_bits,stdout_signp,output_bytecount);
+
pipeline_reset();
playback_active=0;
playback_exit=0;
if(audiobuf)free(audiobuf);
+
write(eventpipe[1],"",1);
return(NULL);
}
+/* for access from UI */
void output_halt_playback(void){
if(playback_active){
playback_exit=1;
Modified: trunk/postfish/output.h
===================================================================
--- trunk/postfish/output.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/output.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -21,9 +21,47 @@
*
*/
+typedef struct {
+ sig_atomic_t device;
+ sig_atomic_t source[OUTPUT_CHANNELS];
+ sig_atomic_t bytes;
+ sig_atomic_t ch;
+ sig_atomic_t format; /* WAV, AIFC, LE, BE */
+} output_subsetting;
+
+typedef struct {
+ sig_atomic_t panel_active[2];
+ sig_atomic_t panel_visible;
+
+ output_subsetting stdout;
+ output_subsetting monitor;
+} output_settings;
+
+typedef struct {
+ int type;
+ char *name;
+ char *file;
+} output_monitor_entry;
+
+extern int output_stdout_available;
+extern int output_stdout_device;
+extern int output_monitor_available;
+extern output_monitor_entry *monitor_list;
+extern int monitor_entries;
+
+extern sig_atomic_t master_att;
+
extern int pull_output_feedback(float *peak,float *rms);
extern void *playback_thread(void *dummy);
extern void output_halt_playback(void);
extern void output_reset(void);
extern void playback_request_seek(off_t cursor);
extern int output_feedback_deep(void);
+
+extern int output_probe_stdout(int outfileno);
+extern int output_probe_monitor(void );
+
+extern void outpanel_monitor_off();
+extern void outpanel_stdout_off();
+
+extern output_settings outset;
Modified: trunk/postfish/postfish-gtkrc
===================================================================
--- trunk/postfish/postfish-gtkrc 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/postfish-gtkrc 2004-05-29 01:17:47 UTC (rev 6774)
@@ -3,6 +3,14 @@
bg[ACTIVE]="#c0f0ff"
bg[PRELIGHT]="#c0f0ff"
+ text[NORMAL]="#000000"
+ text[ACTIVE]="#000000"
+ text[PRELIGHT]="#000000"
+
+ fg[NORMAL]="#000000"
+ fg[ACTIVE]="#000000"
+ fg[PRELIGHT]="#000000"
+
font_name = "sans 8"
GtkButton::relief = none
@@ -173,6 +181,8 @@
widget "*.smallreadout" style "small-readout"
widget "*.GtkEntry" style "readout"
widget "*.GtkHScale" style "slider"
+widget "*.GtkMenu*" style "button-poppy"
+widget "*.GtkOptionMenu*" style "button-poppy"
widget "*.GtkToggleButton*" style "button-poppy"
widget "*.GtkButton*" style "button-poppy"
widget "*.GtkCheckButton" style "check-poppy"
Modified: trunk/postfish/postfish.h
===================================================================
--- trunk/postfish/postfish.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/postfish.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -50,7 +50,8 @@
#include <signal.h>
#include <fcntl.h>
-#define OUTPUT_CHANNELS 6
+#define OUTPUT_CHANNELS 8 // UI code assumes this is <=8
+#define MAX_INPUT_CHANNELS 32 // engine code requires <= 32
static inline float todB(float x){
return logf((x)*(x)+1e-30f)*4.34294480f;
@@ -67,7 +68,7 @@
}
static inline float fromdB_a(float x){
- int y=1.39331762961e+06f*((x<-400?-400:x)+764.6161886f);
+ int y=(x < -300 ? 0 : 1.39331762961e+06f*(x+764.6161886f));
return *(float *)&y;
}
@@ -100,20 +101,19 @@
u_int32_t active; /* active channel bitmask */
} time_linkage;
-extern pthread_mutex_t master_mutex;
-
extern sig_atomic_t loop_active;
extern sig_atomic_t playback_active;
extern sig_atomic_t playback_exit;
extern sig_atomic_t playback_seeking;
extern sig_atomic_t master_att;
extern int outfileno;
-extern int seekable;
+extern int input_seekable;
extern int eventpipe[2];
extern int input_ch;
+extern int input_size;
+extern int input_rate;
-extern void mainpanel_go(int n,char *list[],int ch);
extern int mute_channel_muted(u_int32_t bitmap,int i);
-
+extern void clean_exit(int sig);
#endif
Modified: trunk/postfish/readout.c
===================================================================
--- trunk/postfish/readout.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/readout.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -153,7 +153,6 @@
GtkWidget *ret= GTK_WIDGET (g_object_new (readout_get_type (), NULL));
Readout *r=READOUT(ret);
- r->layout=calloc(1,sizeof(r->layout));
r->layout=gtk_widget_create_pango_layout(ret,markup);
return ret;
Modified: trunk/postfish/reverb.c
===================================================================
--- trunk/postfish/reverb.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/reverb.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -52,7 +52,10 @@
int size;
float *buffer[2];
int ptr;
+ int dptr;
+ int dptr_pending;
int delay;
+ int delay_pending;
float fc;
float lp[2];
float a1a;
@@ -63,6 +66,8 @@
typedef struct {
float *outbuffer;
waveguide_nl w[8];
+ int prevwet;
+ int initstate;
} plate;
typedef struct {
@@ -90,10 +95,13 @@
static void waveguide_init(waveguide_nl *wg,
int size, float fc, float da, float db){
wg->size = size;
- wg->delay = size;
+ wg->delay_pending = size;
+ wg->delay = -1;
wg->buffer[0] = calloc(size, sizeof(float));
wg->buffer[1] = calloc(size, sizeof(float));
wg->ptr = 0;
+ wg->dptr = 0;
+ wg->dptr_pending = 0;
wg->fc = fc;
wg->lp[0] = 0.0f;
wg->lp[1] = 0.0f;
@@ -101,25 +109,33 @@
wg->zm1[1] = 0.0f;
wg->a1a = (1.0f - da) / (1.0f + da);
wg->a1b = (1.0f - db) / (1.0f + db);
+
}
static void waveguide_nl_reset(waveguide_nl *wg){
- memset(wg->buffer[0], 0, wg->size * sizeof(float));
- memset(wg->buffer[1], 0, wg->size * sizeof(float));
+ memset(wg->buffer[0], 0, wg->size * sizeof(**wg->buffer));
+ memset(wg->buffer[1], 0, wg->size * sizeof(**wg->buffer));
wg->lp[0] = 0.0f;
wg->lp[1] = 0.0f;
wg->zm1[0] = 0.0f;
wg->zm1[1] = 0.0f;
+
+ wg->ptr=0;
+ wg->dptr = wg->delay;
+ wg->dptr_pending = wg->delay_pending;
}
static void waveguide_nl_set_delay(waveguide_nl *wg, int delay){
if (delay > wg->size) {
- wg->delay = wg->size;
+ wg->delay_pending = wg->size;
} else if (delay < 1) {
- wg->delay = 1;
+ wg->delay_pending = 1;
} else {
- wg->delay = delay;
+ wg->delay_pending = delay;
}
+
+ wg->dptr_pending = wg->ptr + wg->delay_pending;
+ if(wg->dptr_pending >= wg->size) wg->dptr_pending -= wg->size;
}
static void waveguide_nl_set_fc(waveguide_nl *wg, float fc){
@@ -127,17 +143,45 @@
}
static void waveguide_nl_process_lin(waveguide_nl *wg, float in0, float in1,
- float *out0, float *out1){
+ float *out0, float *out1, int i){
float tmp;
+
+ *out0 = wg->buffer[0][wg->dptr];
+ *out0 = wg->lp[0] * (wg->fc - 1.0f) + wg->fc * *out0;
+ wg->lp[0] = *out0;
+ tmp = *out0 * -(wg->a1a) + wg->zm1[0];
+ wg->zm1[0] = tmp * wg->a1a + *out0;
+ *out0 = tmp;
- *out0 = wg->buffer[0][(wg->ptr + wg->delay) % wg->size];
+ *out1 = wg->buffer[1][wg->dptr];
+ *out1 = wg->lp[1] * (wg->fc - 1.0f) + wg->fc * *out1;
+ wg->lp[1] = *out1;
+ tmp = *out1 * -(wg->a1a) + wg->zm1[1];
+ wg->zm1[1] = tmp * wg->a1a + *out1;
+ *out1 = tmp;
+
+ wg->buffer[0][wg->ptr] = in0;
+ wg->buffer[1][wg->ptr] = in1;
+ wg->ptr--;
+ wg->dptr--;
+ if (wg->ptr < 0) wg->ptr += wg->size;
+ if (wg->dptr < 0) wg->dptr += wg->size;
+}
+
+static void waveguide_nl_process_trans(waveguide_nl *wg, float in0, float in1,
+ float *out0, float *out1, int i){
+ float tmp;
+
+ *out0 = wg->buffer[0][wg->dptr]*(1.-frame_window[i]) +
+ wg->buffer[0][wg->dptr_pending]*frame_window[i];
*out0 = wg->lp[0] * (wg->fc - 1.0f) + wg->fc * *out0;
wg->lp[0] = *out0;
tmp = *out0 * -(wg->a1a) + wg->zm1[0];
wg->zm1[0] = tmp * wg->a1a + *out0;
*out0 = tmp;
- *out1 = wg->buffer[1][(wg->ptr + wg->delay) % wg->size];
+ *out1 = wg->buffer[1][wg->dptr]*(1.-frame_window[i]) +
+ wg->buffer[1][wg->dptr_pending]*frame_window[i];
*out1 = wg->lp[1] * (wg->fc - 1.0f) + wg->fc * *out1;
wg->lp[1] = *out1;
tmp = *out1 * -(wg->a1a) + wg->zm1[1];
@@ -147,7 +191,11 @@
wg->buffer[0][wg->ptr] = in0;
wg->buffer[1][wg->ptr] = in1;
wg->ptr--;
+ wg->dptr--;
+ wg->dptr_pending--;
if (wg->ptr < 0) wg->ptr += wg->size;
+ if (wg->dptr < 0) wg->dptr += wg->size;
+ if (wg->dptr_pending < 0) wg->dptr_pending += wg->size;
}
/* model the plate reverb as a set of eight linear waveguides */
@@ -155,17 +203,9 @@
#define LP_INNER 0.96f
#define LP_OUTER 0.983f
-#define RUN_WG(n, junct_a, junct_b) waveguide_nl_process_lin(&w[n], junct_a - out[n*2+1], junct_b - out[n*2], out+n*2, out+n*2+1)
+#define RUN_WG(n, junct_a, junct_b, i) process(&w[n], junct_a - out[n*2+1], junct_b - out[n*2], out+n*2, out+n*2+1, i)
static void plate_reset_helper(plate_state *ps){
- int i,j;
-
- for(i=0;i<ps->out.channels;i++){
- for (j = 0; j < 8; j++)
- waveguide_nl_reset(&ps->plates[i].w[j]);
- memset(ps->plates[i].outbuffer,0,
- 32*sizeof(*ps->plates[i].outbuffer));
- }
ps->fillstate=0;
}
@@ -236,10 +276,24 @@
waveguide_nl *w = ps->w;
float *out=ps->outbuffer;
+ void (*process)(waveguide_nl *, float, float, float*, float*, int)=
+ waveguide_nl_process_lin;
+
int pos;
const float scale = powf(p->time*.0009999f, 1.34f);
const float lpscale = 1.0f - p->damping*.001f * 0.93f;
- const float wet = p->wet*.001f;
+ int curwet=p->wet;
+ float wet;
+ float wet_e;
+
+ if(ps->initstate==0){
+ wet = fromdB(curwet*.1f);
+ wet_e = 1.;
+ ps->initstate=1;
+ }else{
+ wet = fromdB(ps->prevwet*.1f);
+ wet_e = fromdB((curwet-ps->prevwet)*.1f/count);
+ }
/* waveguide reconfig */
for (pos=0; pos<8; pos++)
@@ -248,31 +302,44 @@
waveguide_nl_set_fc(&w[pos], LP_INNER * lpscale);
for (; pos<8; pos++)
waveguide_nl_set_fc(&w[pos], LP_OUTER * lpscale);
-
+
+ if(w[0].delay!=w[0].delay_pending)
+ process=waveguide_nl_process_trans;
+
for (pos = 0; pos < count; pos++) {
- const float alpha = (out[0] + out[2] + out[4] + out[6]) * 0.5f + in[pos];
+ const float alpha = (out[0] + out[2] + out[4] + out[6]) * 0.5f +
+ (in?in[pos]:0.f);
const float beta = (out[1] + out[9] + out[14]) * 0.666666666f;
const float gamma = (out[3] + out[8] + out[11]) * 0.666666666f;
const float delta = (out[5] + out[10] + out[13]) * 0.666666666f;
const float epsilon = (out[7] + out[12] + out[15]) * 0.666666666f;
- RUN_WG(0, beta, alpha);
- RUN_WG(1, gamma, alpha);
- RUN_WG(2, delta, alpha);
- RUN_WG(3, epsilon, alpha);
- RUN_WG(4, beta, gamma);
- RUN_WG(5, gamma, delta);
- RUN_WG(6, delta, epsilon);
- RUN_WG(7, epsilon, beta);
+ RUN_WG(0, beta, alpha, pos);
+ RUN_WG(1, gamma, alpha, pos);
+ RUN_WG(2, delta, alpha, pos);
+ RUN_WG(3, epsilon, alpha, pos);
+ RUN_WG(4, beta, gamma, pos);
+ RUN_WG(5, gamma, delta, pos);
+ RUN_WG(6, delta, epsilon, pos);
+ RUN_WG(7, epsilon, beta, pos);
if(!outB || !outC){
- outA[pos]=in[pos] * (1.0f - wet) + beta * wet;
+ outA[pos]= beta * wet;
}else{
- outA[pos]=in[pos] * (1.0f - wet);
outB[pos]= beta * wet;
outC[pos]= gamma * wet;
}
+ wet*=wet_e;
}
+ ps->prevwet=curwet;
+
+ if(w[0].delay!=w[0].delay_pending){
+ int i;
+ for(i=0;i<8;i++){
+ w[i].delay=w[i].delay_pending;
+ w[i].dptr=w[i].dptr_pending;
+ }
+ }
}
time_linkage *plate_read_channel(time_linkage *in,
@@ -280,6 +347,7 @@
time_linkage **revB){
int i,j,ch=in->channels;
plate_state *ps=&channel;
+ int active[ch];
*revA=&ps->outA;
*revB=&ps->outB;
@@ -288,52 +356,78 @@
ps->out.samples=0;
ps->outA.samples=0;
ps->outB.samples=0;
+ return &ps->out;
}
+ for(i=0;i<ch;i++)
+ active[i]=plate_channel_set[i].panel_active;
+
ps->outA.active=0;
ps->outB.active=0;
if(ps->fillstate==0){
for(i=0;i<ch;i++)
- ps->prevactive[i]=plate_channel_set[i].panel_active;
- ps->fillstate=1;
+ ps->prevactive[i]=active[i];
}
for(i=0;i<ch;i++){
- if(plate_channel_set[i].panel_active || ps->prevactive[i]){
+ if(active[i] || ps->prevactive[i]){
float *x=in->data[i];
float *y=ps->out.data[i];
float *yA=ps->outA.data[i];
float *yB=ps->outB.data[i];
/* clear the waveguides of old state if they were inactive */
- if (!ps->prevactive[i]){
+ if (!ps->prevactive[i] || !ps->fillstate){
for (j = 0; j < 8; j++)
waveguide_nl_reset(&ps->plates[i].w[j]);
+ ps->plates[i].initstate=0;
memset(ps->plates[i].outbuffer,0,
32*sizeof(*ps->plates[i].outbuffer));
}
/* process this plate */
- plate_compute(&plate_channel_set[i], &ps->plates[i],
- x,y,yA,yB,input_size);
-
- if(!plate_channel_set[i].panel_active){
+ if(mute_channel_muted(in->active,i)){
+ plate_compute(&plate_channel_set[i], &ps->plates[i],
+ 0,0,yA,yB,input_size);
+ }else{
+
+ /* state transition? If so, the input needs to be smoothed to
+ avoid a step transition ringing through the plate */
+ if(!ps->fillstate ||
+ !active[i] ||
+ !ps->prevactive[i]){
+
+ memcpy(y,x,sizeof(*x)*input_size);
+ if(!active[i]){
+ /* transition to inactive */
+ for(j=0;j<input_size;j++)
+ x[j] *= (1.f - frame_window[j]);
+
+ }else if (!ps->prevactive[i] || !ps->fillstate){
+ /* transition to active */
+ for(j=0;j<input_size;j++)
+ x[j]*= frame_window[j];
+ }
+ }else{
+ ps->out.data[i]=x;
+ in->data[i]=y;
+ }
+
+ plate_compute(&plate_channel_set[i], &ps->plates[i],
+ x,0,yA,yB,input_size);
+
+
+ }
+
+ if(!active[i]){
/* transition to inactive */
- for(j=0;j<input_ch;j++){
- y[j]= y[j]*(1.f - frame_window[j]) + x[j] * frame_window[j];
- yA[j]= yA[j]*(1.f - frame_window[j]);
- yB[j]= yB[j]*(1.f - frame_window[j]);
+ for(j=0;j<input_size;j++){
+ yA[j] *= (1.f - frame_window[j]);
+ yB[j] *= (1.f - frame_window[j]);
}
+ }
- }else if (!ps->prevactive[i]){
- /* transition to active */
- for(j=0;j<input_ch;j++){
- y[j]= y[j]* frame_window[j] + x[j] * (1. - frame_window[j]);
- yA[j]= yA[j]* frame_window[j];
- yB[j]= yB[j]* frame_window[j];
- }
- }
ps->outA.active |= 1<<i;
ps->outB.active |= 1<<i;
@@ -343,67 +437,92 @@
ps->out.data[i]=in->data[i];
in->data[i]=temp;
}
- ps->prevactive[i]=plate_channel_set[i].panel_active;
+ ps->prevactive[i]=active[i];
}
ps->out.active=in->active;
ps->out.samples=in->samples;
ps->outA.samples=in->samples;
ps->outB.samples=in->samples;
+ ps->fillstate=1;
return &ps->out;
}
time_linkage *plate_read_master(time_linkage *in){
int i,j,ch=in->channels;
plate_state *ps=&master;
-
+ int active=plate_master_set.panel_active;
+
if(in->samples==0){
ps->out.samples=0;
+ return &ps->out;
}
if(ps->fillstate==0){
- ps->prevactive[0]=plate_master_set.panel_active;
- ps->fillstate=1;
+ ps->prevactive[0]=active;
}
for(i=0;i<ch;i++){
- if(plate_master_set.panel_active || ps->prevactive[0]){
+ if(active || ps->prevactive[0]){
float *x=in->data[i];
float *y=ps->out.data[i];
/* clear the waveguides of old state if they were inactive */
- if (!ps->prevactive[0]){
+ if (!ps->prevactive[0] || !ps->fillstate){
for (j = 0; j < 8; j++)
waveguide_nl_reset(&ps->plates[i].w[j]);
memset(ps->plates[i].outbuffer,0,
32*sizeof(*ps->plates[i].outbuffer));
}
-
+
/* process this plate */
- plate_compute(&plate_master_set, &ps->plates[i],
- x,y,0,0,input_size);
-
- if(!plate_master_set.panel_active){
+ if(mute_channel_muted(in->active,i)){
+ plate_compute(&plate_master_set, &ps->plates[i],
+ 0,y,0,0,input_size);
+ }else{
+
+ memcpy(y,x,sizeof(*x)*input_size);
+
+ /* must be done to the input, else the transition impulse
+ will ring through the plate */
+ if(!active){
+ /* transition to inactive */
+ for(j=0;j<input_size;j++)
+ y[j] *= (1.f - frame_window[j]);
+
+ }else if (!ps->prevactive[0] || !ps->fillstate){
+ /* transition to active */
+ for(j=0;j<input_size;j++)
+ y[j]*= frame_window[j];
+ }
+
+ plate_compute(&plate_master_set, &ps->plates[i],
+ y,y,0,0,input_size);
+ }
+
+ if(!active){
/* transition to inactive */
- for(j=0;j<input_ch;j++)
- y[j]= y[j]*(1.f - frame_window[j]) + x[j] * frame_window[j];
+ for(j=0;j<input_size;j++)
+ y[j]*= 1.f - frame_window[j];
+
+ }
+ if(!mute_channel_muted(in->active,i))
+ for(j=0;j<input_size;j++)
+ y[j]+=x[j];
- }else if (!ps->prevactive[0]){
- /* transition to active */
- for(j=0;j<input_ch;j++)
- y[j]= y[j]* frame_window[j] + x[j] * (1. - frame_window[j]);
+ ps->out.active |= 1<<i;
- }
}else{
/* fully inactive */
float *temp=ps->out.data[i];
ps->out.data[i]=in->data[i];
in->data[i]=temp;
+ ps->out.active |= in->active & (1<<i);
}
}
- ps->prevactive[0]=plate_master_set.panel_active;
+ ps->prevactive[0]=active;
- ps->out.active=in->active;
ps->out.samples=in->samples;
+ ps->fillstate=1;
return &ps->out;
}
Modified: trunk/postfish/reverb.h
===================================================================
--- trunk/postfish/reverb.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/reverb.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -36,3 +36,7 @@
time_linkage **revA,
time_linkage **revB);
extern time_linkage *plate_read_master(time_linkage *in);
+
+extern plate_set *plate_channel_set;
+extern plate_set plate_master_set;
+
Added: trunk/postfish/reverbpanel.c
===================================================================
--- trunk/postfish/reverbpanel.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/reverbpanel.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -0,0 +1,228 @@
+/*
+ *
+ * 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 "reverb.h"
+#include "reverbpanel.h"
+#include "config.h"
+
+typedef struct {
+ GtkWidget *s;
+ GtkWidget *r;
+ sig_atomic_t *val;
+} slider_readout_pair;
+
+typedef struct{
+ subpanel_generic *panel;
+ slider_readout_pair *time;
+ slider_readout_pair *damp;
+ slider_readout_pair *wet;
+} reverb_panel_state;
+
+reverb_panel_state *master_panel;
+reverb_panel_state **channel_panel;
+
+static void reverbpanel_state_to_config_helper(int bank,plate_set *s,int A){
+ config_set_integer("reverb_active",bank,A,0,0,0,s->panel_active);
+
+ config_set_integer("reverb_set",bank,A,0,0,0,s->time);
+ config_set_integer("reverb_set",bank,A,0,0,1,s->damping);
+ config_set_integer("reverb_set",bank,A,0,0,2,s->wet);
+}
+
+void reverbpanel_state_to_config(int bank){
+ int i;
+ reverbpanel_state_to_config_helper(bank,&plate_master_set,0);
+ for(i=0;i<input_ch;i++)
+ reverbpanel_state_to_config_helper(bank,plate_channel_set+i,i+1);
+}
+
+static void reverbpanel_state_from_config_helper(int bank,plate_set *s,
+ reverb_panel_state *p,int A){
+
+ config_get_sigat("reverb_active",bank,A,0,0,0,&s->panel_active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->panel->subpanel_activebutton[0]),s->panel_active);
+
+
+ config_get_sigat("reverb_set",bank,A,0,0,0,&s->time);
+ multibar_thumb_set(MULTIBAR(p->time->s),s->time,0);
+
+ config_get_sigat("reverb_set",bank,A,0,0,1,&s->damping);
+ multibar_thumb_set(MULTIBAR(p->damp->s),s->damping,0);
+
+ config_get_sigat("reverb_set",bank,A,0,0,2,&s->wet);
+ multibar_thumb_set(MULTIBAR(p->wet->s),s->wet,0);
+
+}
+
+void reverbpanel_state_from_config(int bank){
+ int i;
+ reverbpanel_state_from_config_helper(bank,&plate_master_set,master_panel,0);
+ for(i=0;i<input_ch;i++)
+ reverbpanel_state_from_config_helper(bank,plate_channel_set+i,channel_panel[i],i+1);
+}
+
+static void slider_change(GtkWidget *w,gpointer in){
+ char buffer[80];
+ slider_readout_pair *p=(slider_readout_pair *)in;
+ float val=multibar_get_value(MULTIBAR(p->s),0);
+
+ sprintf(buffer," %5.2f",val*.01);
+ readout_set(READOUT(p->r),buffer);
+
+ *p->val=rint(val);
+}
+
+static void slider_change_dB(GtkWidget *w,gpointer in){
+ char buffer[80];
+ slider_readout_pair *p=(slider_readout_pair *)in;
+ float val=multibar_get_value(MULTIBAR(p->s),0);
+
+ sprintf(buffer,"%+4.1fdB",val*.1);
+ readout_set(READOUT(p->r),buffer);
+
+ *p->val=rint(val);
+}
+
+static reverb_panel_state *reverbpanel_create_helper (postfish_mainpanel *mp,
+ subpanel_generic *panel,
+ plate_set *ps){
+
+ char *labels[11]={"","1","2","3","4","5","6","7","8","9"," 10"};
+ float levels[11]={0,100,200,300,400,500,600,700,800,900,1000};
+
+ char *labelsdB[11]={"","-40","-20","-10","-3","0","+3","+10","+20","+40"," +80"};
+ float levelsdB[11]={-800,-400,-200,-100,-30,0,30,100,200,400,800};
+
+ GtkWidget *table=gtk_table_new(3,3,0);
+ slider_readout_pair *p1=malloc(sizeof(*p1));
+ slider_readout_pair *p2=malloc(sizeof(*p2));
+ slider_readout_pair *p3=malloc(sizeof(*p3));
+
+ GtkWidget *l1=gtk_label_new("Plate size ");
+ GtkWidget *l2=gtk_label_new("Damping ");
+ GtkWidget *l3=gtk_label_new("Wet level ");
+
+ reverb_panel_state *p=calloc(1,sizeof(*p));
+ p->panel=panel;
+
+ gtk_misc_set_alignment(GTK_MISC(l1),1,.5);
+ gtk_misc_set_alignment(GTK_MISC(l2),1,.5);
+ gtk_misc_set_alignment(GTK_MISC(l3),1,.5);
+
+ p->time=p1;
+ p1->s=multibar_slider_new(11,labels,levels,1);
+ p1->r=readout_new("10.00");
+ p1->val=&ps->time;
+
+ p->damp=p2;
+ p2->s=multibar_slider_new(11,labels,levels,1);
+ p2->r=readout_new("10.00");
+ p2->val=&ps->damping;
+
+ p->wet=p3;
+ p3->s=multibar_slider_new(11,labelsdB,levelsdB,1);
+ p3->r=readout_new("10.00");
+ p3->val=&ps->wet;
+
+ gtk_table_attach(GTK_TABLE(table),l1,0,1,0,1,
+ GTK_FILL,GTK_FILL|GTK_EXPAND,2,0);
+ gtk_table_attach(GTK_TABLE(table),p1->s,1,2,0,1,
+ GTK_FILL,GTK_FILL|GTK_EXPAND,2,0);
+ gtk_table_attach(GTK_TABLE(table),p1->r,2,3,0,1,
+ GTK_FILL,GTK_FILL|GTK_EXPAND,2,0);
+
+ gtk_table_attach(GTK_TABLE(table),l2,0,1,1,2,
+ GTK_FILL,GTK_FILL|GTK_EXPAND,2,0);
+ gtk_table_attach(GTK_TABLE(table),p2->s,1,2,1,2,
+ GTK_FILL,GTK_FILL|GTK_EXPAND,2,0);
+ gtk_table_attach(GTK_TABLE(table),p2->r,2,3,1,2,
+ GTK_FILL,GTK_FILL|GTK_EXPAND,2,0);
+
+ gtk_table_attach(GTK_TABLE(table),l3,0,1,2,3,
+ GTK_FILL,GTK_FILL|GTK_EXPAND,2,0);
+ gtk_table_attach(GTK_TABLE(table),p3->s,1,2,2,3,
+ GTK_FILL,GTK_FILL|GTK_EXPAND,2,0);
+ gtk_table_attach(GTK_TABLE(table),p3->r,2,3,2,3,
+ GTK_FILL,GTK_FILL|GTK_EXPAND,2,0);
+
+ gtk_container_add(GTK_CONTAINER(panel->subpanel_box),table);
+
+ multibar_callback(MULTIBAR(p1->s),slider_change,p1);
+ multibar_callback(MULTIBAR(p2->s),slider_change,p2);
+ multibar_callback(MULTIBAR(p3->s),slider_change_dB,p3);
+
+ multibar_thumb_set(MULTIBAR(p1->s),200,0);
+ multibar_thumb_set(MULTIBAR(p2->s),200,0);
+ multibar_thumb_set(MULTIBAR(p3->s),0,0);
+
+ multibar_thumb_increment(MULTIBAR(p1->s),1,10);
+ multibar_thumb_increment(MULTIBAR(p2->s),1,10);
+ multibar_thumb_increment(MULTIBAR(p3->s),1,10);
+
+ subpanel_show_all_but_toplevel(panel);
+ return p;
+}
+
+void reverbpanel_create_master(postfish_mainpanel *mp,
+ GtkWidget *windowbutton,
+ GtkWidget *activebutton){
+
+ char *shortcut[]={" r "};
+ subpanel_generic *panel=subpanel_create(mp,windowbutton,&activebutton,
+ &plate_master_set.panel_active,
+ &plate_master_set.panel_visible,
+ "_Plate Reverb (master)",shortcut,
+ 0,1);
+ master_panel=reverbpanel_create_helper(mp,panel,&plate_master_set);
+}
+
+void reverbpanel_create_channel(postfish_mainpanel *mp,
+ GtkWidget **windowbutton,
+ GtkWidget **activebutton){
+ int i;
+ /* a panel for each channel */
+ channel_panel=calloc(input_ch,sizeof(*channel_panel));
+
+ for(i=0;i<input_ch;i++){
+ subpanel_generic *panel;
+ char buffer[80];
+
+ sprintf(buffer,"_Plate Reverb (channel %d)",i+1);
+ panel=subpanel_create(mp,windowbutton[i],activebutton+i,
+ &plate_channel_set[i].panel_active,
+ &plate_channel_set[i].panel_visible,
+ buffer,NULL,
+ i,1);
+
+ channel_panel[i]=reverbpanel_create_helper(mp,panel,plate_channel_set+i);
+ }
+}
+
+
Added: trunk/postfish/reverbpanel.h
===================================================================
--- trunk/postfish/reverbpanel.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/reverbpanel.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -0,0 +1,34 @@
+/*
+ *
+ * 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 reverbpanel_create_master(postfish_mainpanel *mp,
+ GtkWidget *windowbutton,
+ GtkWidget *activebutton);
+extern void reverbpanel_create_channel(postfish_mainpanel *mp,
+ GtkWidget **windowbutton,
+ GtkWidget **activebutton);
+
+
+
+extern void reverbpanel_state_to_config(int bank);
+extern void reverbpanel_state_from_config(int bank);
Modified: trunk/postfish/singlecomp.c
===================================================================
--- trunk/postfish/singlecomp.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/singlecomp.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -35,6 +35,16 @@
float val;
} peak_state;
+typedef struct {
+ sig_atomic_t u_thresh;
+ sig_atomic_t u_ratio;
+
+ sig_atomic_t o_thresh;
+ sig_atomic_t o_ratio;
+
+ sig_atomic_t b_ratio;
+} atten_cache;
+
typedef struct{
time_linkage out;
feedback_generic_pool feedpool;
@@ -64,6 +74,9 @@
int mutemaskP;
int mutemask0;
int ch;
+
+ atten_cache *prevset;
+ atten_cache *currset;
} singlecomp_state;
static float *window;
@@ -112,7 +125,7 @@
static void singlecomp_load_helper(singlecomp_state *scs,int ch){
int i;
- memset(scs,0,sizeof(scs));
+ memset(scs,0,sizeof(*scs));
scs->ch=ch;
scs->activeP=calloc(scs->ch,sizeof(*scs->activeP));
@@ -143,6 +156,8 @@
for(i=0;i<scs->ch;i++)
scs->cache[i]=malloc(input_size*sizeof(**scs->cache));
+ scs->prevset=malloc(ch*sizeof(*scs->prevset));
+ scs->currset=malloc(ch*sizeof(*scs->currset));
}
/* called only by initial setup */
@@ -187,12 +202,12 @@
}
static void reset_filter(singlecomp_state *scs){
- memset(scs->o_peak,0,scs->ch*sizeof(&scs->o_peak));
- memset(scs->u_peak,0,scs->ch*sizeof(&scs->u_peak));
- memset(scs->b_peak,0,scs->ch*sizeof(&scs->b_peak));
- memset(scs->o_iir,0,scs->ch*sizeof(&scs->o_iir));
- memset(scs->u_iir,0,scs->ch*sizeof(&scs->u_iir));
- memset(scs->b_iir,0,scs->ch*sizeof(&scs->b_iir));
+ memset(scs->o_peak,0,scs->ch*sizeof(*scs->o_peak));
+ memset(scs->u_peak,0,scs->ch*sizeof(*scs->u_peak));
+ memset(scs->b_peak,0,scs->ch*sizeof(*scs->b_peak));
+ memset(scs->o_iir,0,scs->ch*sizeof(*scs->o_iir));
+ memset(scs->u_iir,0,scs->ch*sizeof(*scs->u_iir));
+ memset(scs->b_iir,0,scs->ch*sizeof(*scs->b_iir));
}
/* called only in playback thread */
@@ -291,7 +306,10 @@
}
static void over_compand(float *A,float *B,float *adj,
- float zerocorner,float multiplier,
+ float zerocorner,
+ float currcorner,
+ float multiplier,
+ float currmultiplier,
float lookahead,int mode,int softknee,
iir_filter *attack, iir_filter *decay,
iir_state *iir, peak_state *ps,
@@ -306,18 +324,39 @@
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;
+ if(multiplier!=currmultiplier || zerocorner!=currcorner){
+ float multiplier_add=(currmultiplier-multiplier)/input_size;
+ float zerocorner_add=(currcorner-zerocorner)/input_size;
+
+ if(softknee){
+ for(k=0;k<input_size;k++){
+ adj[k]+=soft_knee(work[k]-zerocorner)*multiplier;
+ multiplier+=multiplier_add;
+ zerocorner+=zerocorner_add;
+ }
+ }else{
+ for(k=0;k<input_size;k++){
+ adj[k]+=hard_knee(work[k]-zerocorner)*multiplier;
+ multiplier+=multiplier_add;
+ zerocorner+=zerocorner_add;
+ }
+ }
+
}else{
- for(k=0;k<input_size;k++)
- adj[k]+=hard_knee(work[k]-zerocorner)*multiplier;
+ 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 zerocorner,float currcorner,
+ float multiplier,float currmultiplier,
float lookahead,int mode,int softknee,
iir_filter *attack, iir_filter *decay,
iir_state *iir, peak_state *ps,
@@ -331,20 +370,41 @@
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;
+ if(multiplier!=currmultiplier || zerocorner!=currcorner){
+ float multiplier_add=(currmultiplier-multiplier)/input_size;
+ float zerocorner_add=(currcorner-zerocorner)/input_size;
+
+ if(softknee){
+ for(k=0;k<input_size;k++){
+ adj[k]= -soft_knee(zerocorner-work[k])*multiplier;
+ multiplier+=multiplier_add;
+ zerocorner+=zerocorner_add;
+ }
+ }else{
+ for(k=0;k<input_size;k++){
+ adj[k]= -hard_knee(zerocorner-work[k])*multiplier;
+ multiplier+=multiplier_add;
+ zerocorner+=zerocorner_add;
+ }
+ }
+
}else{
- for(k=0;k<input_size;k++)
- adj[k]= -hard_knee(zerocorner-work[k])*multiplier;
+ 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,
+ float multiplier,float currmultiplier,
+ int mode,
iir_filter *attack, iir_filter *decay,
iir_state *iir, peak_state *ps,
int active){
@@ -355,11 +415,20 @@
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;
-
+
+ if(active){
+ if(multiplier!=currmultiplier){
+ float multiplier_add=(currmultiplier-multiplier)/input_size;
+
+ for(k=0;k<input_size;k++){
+ adj[k]-=(work[k]+adj[k])*multiplier;
+ multiplier+=multiplier_add;
+ }
+ }else{
+ for(k=0;k<input_size;k++)
+ adj[k]-=(work[k]+adj[k])*multiplier;
+ }
+ }
}
static void work_and_lapping(singlecomp_state *scs,
@@ -401,9 +470,9 @@
if(u_decayms!=scs->u_decay[i].ms)filter_set(u_decayms,&scs->u_decay[i],0);
if(b_attackms!=scs->b_attack[i].ms)filter_set(b_attackms,&scs->b_attack[i],1);
if(b_decayms!=scs->b_decay[i].ms)filter_set(b_decayms,&scs->b_decay[i],0);
-
+
if(!active0 && !activeC){
-
+
if(activeP) reset_filter(scs); /* just became inactive; reset all filters */
/* feedabck */
@@ -435,13 +504,26 @@
}else if(active0 || activeC){
+ float adj[input_size]; // under will set it
+ scs->currset[i].u_thresh=scset[i]->u_thresh;
+ scs->currset[i].o_thresh=scset[i]->o_thresh;
+ scs->currset[i].u_ratio=scset[i]->u_ratio;
+ scs->currset[i].o_ratio=scset[i]->o_ratio;
+ scs->currset[i].b_ratio=scset[i]->b_ratio;
+
+ /* don't slew from an unknown value */
+
+ if(!activeP || !scs->fillstate)
+ memcpy(scs->prevset+i,scs->currset+i,sizeof(*scs->currset));
+
/* run the filters */
- float adj[input_size]; // under will set it
under_compand(scs->cache[i],in->data[i],adj,
- (float)(scset[i]->u_thresh),
- 1.-1000./scset[i]->u_ratio,
+ scs->prevset[i].u_thresh,
+ scs->currset[i].u_thresh,
+ 1.-1000./scs->prevset[i].u_ratio,
+ 1.-1000./scs->currset[i].u_ratio,
scset[i]->u_lookahead/1000.,
scset[i]->u_mode,
scset[i]->u_softknee,
@@ -450,8 +532,10 @@
active0);
over_compand(scs->cache[i],in->data[i],adj,
- (float)(scset[i]->o_thresh),
- 1.-1000./scset[i]->o_ratio,
+ scs->prevset[i].o_thresh,
+ scs->currset[i].o_thresh,
+ 1.-1000./scs->prevset[i].o_ratio,
+ 1.-1000./scs->currset[i].o_ratio,
scset[i]->o_lookahead/1000.,
scset[i]->o_mode,
scset[i]->o_softknee,
@@ -484,7 +568,8 @@
}
base_compand(scs->cache[i],in->data[i],adj,
- 1.-1000./scset[i]->b_ratio,
+ 1.-1000./scs->prevset[i].b_ratio,
+ 1.-1000./scs->currset[i].b_ratio,
scset[i]->b_mode,
scs->b_attack+i,scs->b_decay+i,
scs->b_iir+i,scs->b_peak+i,
@@ -563,6 +648,12 @@
out->active=mutemask0;
out->samples=scs->cache_samples;
}
+
+ {
+ atten_cache *temp=scs->prevset;
+ scs->prevset=scs->currset;
+ scs->currset=temp;
+ }
scs->cache_samples=in->samples;
scs->mutemaskP=mutemask0;
Modified: trunk/postfish/singlecomp.h
===================================================================
--- trunk/postfish/singlecomp.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/singlecomp.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -56,3 +56,7 @@
extern int singlecomp_reset(void);
extern time_linkage *singlecomp_read_master(time_linkage *in);
extern time_linkage *singlecomp_read_channel(time_linkage *in);
+
+extern singlecomp_settings singlecomp_master_set;
+extern singlecomp_settings *singlecomp_channel_set;
+
Modified: trunk/postfish/singlepanel.c
===================================================================
--- trunk/postfish/singlepanel.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/singlepanel.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -31,14 +31,8 @@
#include "feedback.h"
#include "singlecomp.h"
#include "singlepanel.h"
+#include "config.h"
-extern singlecomp_settings singlecomp_master_set;
-extern singlecomp_settings *singlecomp_channel_set;
-
-extern int input_ch;
-extern int input_size;
-extern int input_rate;
-
typedef struct {
GtkWidget *slider;
GtkWidget *readouto;
@@ -48,11 +42,13 @@
} cbar;
typedef struct{
+ Multibar *s;
Readout *r;
sig_atomic_t *v;
} callback_arg_rv;
typedef struct{
+ Multibar *s;
Readout *r0;
Readout *r1;
sig_atomic_t *v0;
@@ -60,6 +56,17 @@
} callback_arg_rv2;
typedef struct singlecomp_panel_state{
+ subpanel_generic *panel;
+
+ GtkWidget *o_peak;
+ GtkWidget *o_rms;
+ GtkWidget *o_knee;
+ GtkWidget *u_peak;
+ GtkWidget *u_rms;
+ GtkWidget *u_knee;
+ GtkWidget *b_peak;
+ GtkWidget *b_rms;
+
callback_arg_rv over_compand;
callback_arg_rv under_compand;
callback_arg_rv base_compand;
@@ -79,6 +86,106 @@
static singlecomp_panel_state *master_panel;
static singlecomp_panel_state **channel_panel;
+static void singlepanel_state_to_config_helper(int bank,singlecomp_settings *s,int A){
+ int i;
+ config_set_integer("singlecompand_active",bank,A,0,0,0,s->panel_active);
+ config_set_integer("singlecompand_thresh",bank,A,i,0,0,s->u_thresh);
+ config_set_integer("singlecompand_thresh",bank,A,i,0,1,s->o_thresh);
+
+ config_set_integer("singlecompand_over_set",bank,A,0,0,0,s->o_mode);
+ config_set_integer("singlecompand_over_set",bank,A,0,0,1,s->o_softknee);
+ config_set_integer("singlecompand_over_set",bank,A,0,0,2,s->o_ratio);
+ config_set_integer("singlecompand_over_set",bank,A,0,0,3,s->o_attack);
+ config_set_integer("singlecompand_over_set",bank,A,0,0,4,s->o_decay);
+ config_set_integer("singlecompand_over_set",bank,A,0,0,5,s->o_lookahead);
+
+ config_set_integer("singlecompand_under_set",bank,A,0,0,0,s->u_mode);
+ config_set_integer("singlecompand_under_set",bank,A,0,0,1,s->u_softknee);
+ config_set_integer("singlecompand_under_set",bank,A,0,0,2,s->u_ratio);
+ config_set_integer("singlecompand_under_set",bank,A,0,0,3,s->u_attack);
+ config_set_integer("singlecompand_under_set",bank,A,0,0,4,s->u_decay);
+ config_set_integer("singlecompand_under_set",bank,A,0,0,5,s->u_lookahead);
+
+ config_set_integer("singlecompand_base_set",bank,A,0,0,0,s->b_mode);
+ config_set_integer("singlecompand_base_set",bank,A,0,0,2,s->b_ratio);
+ config_set_integer("singlecompand_base_set",bank,A,0,0,3,s->b_attack);
+ config_set_integer("singlecompand_base_set",bank,A,0,0,4,s->b_decay);
+}
+
+void singlepanel_state_to_config(int bank){
+ int i;
+ singlepanel_state_to_config_helper(bank,&singlecomp_master_set,0);
+ for(i=0;i<input_ch;i++)
+ singlepanel_state_to_config_helper(bank,singlecomp_channel_set+i,i+1);
+}
+
+static void singlepanel_state_from_config_helper(int bank,singlecomp_settings *s,
+ singlecomp_panel_state *p,int A){
+
+ int i;
+ config_get_sigat("singlecompand_active",bank,A,0,0,0,&s->panel_active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->panel->subpanel_activebutton[0]),s->panel_active);
+
+ config_get_sigat("singlecompand_thresh",bank,A,i,0,0,&s->u_thresh);
+ multibar_thumb_set(MULTIBAR(p->bar.slider),s->u_thresh,0);
+ config_get_sigat("singlecompand_thresh",bank,A,i,0,1,&s->o_thresh);
+ multibar_thumb_set(MULTIBAR(p->bar.slider),s->o_thresh,1);
+
+ config_get_sigat("singlecompand_over_set",bank,A,0,0,0,&s->o_mode);
+ if(s->o_mode)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->o_peak),1);
+ else
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->o_rms),1);
+
+ config_get_sigat("singlecompand_over_set",bank,A,0,0,1,&s->o_softknee);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->o_knee),s->o_softknee);
+ config_get_sigat("singlecompand_over_set",bank,A,0,0,2,&s->o_ratio);
+ multibar_thumb_set(p->over_compand.s,1000./s->o_ratio,0);
+ config_get_sigat("singlecompand_over_set",bank,A,0,0,3,&s->o_attack);
+ multibar_thumb_set(p->over_timing.s,s->o_attack*.1,0);
+ config_get_sigat("singlecompand_over_set",bank,A,0,0,4,&s->o_decay);
+ multibar_thumb_set(p->over_timing.s,s->o_decay*.1,1);
+ config_get_sigat("singlecompand_over_set",bank,A,0,0,5,&s->o_lookahead);
+ multibar_thumb_set(p->over_lookahead.s,s->o_lookahead*.1,0);
+
+ config_get_sigat("singlecompand_under_set",bank,A,0,0,0,&s->u_mode);
+ if(s->u_mode)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->u_peak),1);
+ else
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->u_rms),1);
+
+ config_get_sigat("singlecompand_under_set",bank,A,0,0,1,&s->u_softknee);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->u_knee),s->u_softknee);
+ config_get_sigat("singlecompand_under_set",bank,A,0,0,2,&s->u_ratio);
+ multibar_thumb_set(p->under_compand.s,1000./s->u_ratio,0);
+ config_get_sigat("singlecompand_under_set",bank,A,0,0,3,&s->u_attack);
+ multibar_thumb_set(p->under_timing.s,s->u_attack*.1,0);
+ config_get_sigat("singlecompand_under_set",bank,A,0,0,4,&s->u_decay);
+ multibar_thumb_set(p->under_timing.s,s->u_decay*.1,1);
+ config_get_sigat("singlecompand_under_set",bank,A,0,0,5,&s->u_lookahead);
+ multibar_thumb_set(p->under_lookahead.s,s->u_lookahead*.1,0);
+
+ config_get_sigat("singlecompand_base_set",bank,A,0,0,0,&s->b_mode);
+ if(s->b_mode)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->b_peak),1);
+ else
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->b_rms),1);
+ config_get_sigat("singlecompand_base_set",bank,A,0,0,2,&s->b_ratio);
+ multibar_thumb_set(p->base_compand.s,1000./s->b_ratio,0);
+ config_get_sigat("singlecompand_base_set",bank,A,0,0,3,&s->b_attack);
+ multibar_thumb_set(p->base_timing.s,s->b_attack*.1,0);
+ config_get_sigat("singlecompand_base_set",bank,A,0,0,4,&s->b_decay);
+ multibar_thumb_set(p->base_timing.s,s->b_decay*.1,1);
+
+}
+
+void singlepanel_state_from_config(int bank){
+ int i;
+ singlepanel_state_from_config_helper(bank,&singlecomp_master_set,master_panel,0);
+ for(i=0;i<input_ch;i++)
+ singlepanel_state_from_config_helper(bank,singlecomp_channel_set+i,channel_panel[i],i+1);
+}
+
static void compand_change(GtkWidget *w,gpointer in){
callback_arg_rv *ca=(callback_arg_rv *)in;
char buffer[80];
@@ -202,6 +309,7 @@
singlecomp_panel_state *ps=calloc(1,sizeof(singlecomp_panel_state));
ps->ms=scset;
+ ps->panel=panel;
GtkWidget *sliderframe=gtk_frame_new(NULL);
GtkWidget *allbox=gtk_vbox_new(0,0);
@@ -293,6 +401,10 @@
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);
+
+ ps->u_rms=rms_button;
+ ps->u_peak=peak_button;
+ ps->u_knee=knee_button;
}
/* under compand: ratio */
@@ -302,6 +414,7 @@
GtkWidget *readout=readout_new("1.55:1");
GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1);
+ ps->under_compand.s=MULTIBAR(slider);
ps->under_compand.r=READOUT(readout);
ps->under_compand.v=&ps->ms->u_ratio;
@@ -325,6 +438,7 @@
GtkWidget *readout1=readout_new(" 100ms");
GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2);
+ ps->under_timing.s=MULTIBAR(slider);
ps->under_timing.r0=READOUT(readout0);
ps->under_timing.r1=READOUT(readout1);
ps->under_timing.v0=&ps->ms->u_attack;
@@ -351,6 +465,7 @@
GtkWidget *readout=readout_new("100%");
GtkWidget *slider=multibar_slider_new(9,per_labels,per_levels,1);
+ ps->under_lookahead.s=MULTIBAR(slider);
ps->under_lookahead.r=READOUT(readout);
ps->under_lookahead.v=&ps->ms->u_lookahead;
@@ -390,6 +505,9 @@
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);
+ ps->o_rms=rms_button;
+ ps->o_peak=peak_button;
+ ps->o_knee=knee_button;
}
/* over compand: ratio */
@@ -399,6 +517,7 @@
GtkWidget *readout=readout_new("1.55:1");
GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1);
+ ps->over_compand.s=MULTIBAR(slider);
ps->over_compand.r=READOUT(readout);
ps->over_compand.v=&ps->ms->o_ratio;
@@ -422,6 +541,7 @@
GtkWidget *readout1=readout_new(" 100ms");
GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2);
+ ps->over_timing.s=MULTIBAR(slider);
ps->over_timing.r0=READOUT(readout0);
ps->over_timing.r1=READOUT(readout1);
ps->over_timing.v0=&ps->ms->o_attack;
@@ -448,6 +568,7 @@
GtkWidget *readout=readout_new("100%");
GtkWidget *slider=multibar_slider_new(9,per_labels,per_levels,1);
+ ps->over_lookahead.s=MULTIBAR(slider);
ps->over_lookahead.r=READOUT(readout);
ps->over_lookahead.v=&ps->ms->o_lookahead;
@@ -483,6 +604,8 @@
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);
+ ps->b_rms=rms_button;
+ ps->b_peak=peak_button;
}
/* base compand: ratio */
@@ -492,6 +615,7 @@
GtkWidget *readout=readout_new("1.55:1");
GtkWidget *slider=multibar_slider_new(9,compand_labels,compand_levels,1);
+ ps->base_compand.s=MULTIBAR(slider);
ps->base_compand.r=READOUT(readout);
ps->base_compand.v=&ps->ms->b_ratio;
@@ -515,6 +639,7 @@
GtkWidget *readout1=readout_new(" 100ms");
GtkWidget *slider=multibar_slider_new(6,timing_labels,timing_levels,2);
+ ps->base_timing.s=MULTIBAR(slider);
ps->base_timing.r0=READOUT(readout0);
ps->base_timing.r1=READOUT(readout1);
ps->base_timing.v0=&ps->ms->b_attack;
Modified: trunk/postfish/singlepanel.h
===================================================================
--- trunk/postfish/singlepanel.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/singlepanel.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -31,3 +31,5 @@
extern void singlepanel_reset(void);
+extern void singlepanel_state_to_config(int bank);
+extern void singlepanel_state_from_config(int bank);
Modified: trunk/postfish/subband.c
===================================================================
--- trunk/postfish/subband.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/subband.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -525,10 +525,9 @@
would have been in the previous frame */
for(i=0;i<ch;i++){
int set=(visible[i]||active[i]) && !mute_channel_muted(in->active,i);
- memset(f->lap_activeP,set,sizeof(*f->lap_activeP)*ch);
- memset(f->lap_active1,set,sizeof(*f->lap_active1)*ch);
- memset(f->lap_active0,set,sizeof(*f->lap_active0)*ch);
- //memset(f->lap_activeC,1,sizeof(*f->lap_activeC)*ch);
+ f->lap_activeP[i]=set;
+ f->lap_active1[i]=set;
+ f->lap_active0[i]=set;
f->wP[i]=w[i];
f->w1[i]=w[i];
Modified: trunk/postfish/subpanel.c
===================================================================
--- trunk/postfish/subpanel.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/subpanel.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -167,7 +167,7 @@
GtkWidget *toplabelwb=windowbutton_new(prompt);
GtkWidget *toplabelab[num];
int i;
-
+
for(i=0;i<num;i++){
if(shortcut && shortcut[i]){
toplabelab[i]=gtk_toggle_button_new_with_label(shortcut[i]);
@@ -207,6 +207,9 @@
panel->subpanel_toplevel=gtk_window_new (GTK_WINDOW_TOPLEVEL);
panel->mainpanel=mp;
+ panel->group = gtk_accel_group_new ();
+ gtk_window_add_accel_group (GTK_WINDOW(panel->subpanel_toplevel), panel->group);
+
gtk_container_add (GTK_CONTAINER (panel->subpanel_toplevel), panel->subpanel_topframe);
gtk_container_add (GTK_CONTAINER (panel->subpanel_topframe), panel->subpanel_box);
gtk_container_set_border_width (GTK_CONTAINER (panel->subpanel_topframe), 3);
@@ -229,6 +232,9 @@
G_CALLBACK (subpanel_hide),
panel);
+ gtk_widget_add_accelerator(windowbutton, "clicked", panel->group, GDK_W, GDK_MOD1_MASK, 0);
+
+
/* link the mainpanel and subpanel buttons */
g_signal_connect_after (G_OBJECT (panel->mainpanel_windowbutton), "clicked",
G_CALLBACK (windowbutton_action), panel);
Modified: trunk/postfish/subpanel.h
===================================================================
--- trunk/postfish/subpanel.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/subpanel.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -30,6 +30,7 @@
GtkWidget *subpanel_topframe;
GtkWidget *subpanel_box;
sig_atomic_t *activevar;
+ GtkAccelGroup *group;
int active_button_count; /* silliness around the rotating non-alt-shortcut */
int active_button_start; /* silliness around the rotating non-alt-shortcut */
Modified: trunk/postfish/suppress.c
===================================================================
--- trunk/postfish/suppress.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/suppress.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -56,6 +56,8 @@
iir_state *iirT[suppress_freqs];
iir_state *iirR[suppress_freqs];
+ float prevratio[suppress_freqs];
+
} suppress_state;
suppress_settings suppress_channel_set;
@@ -182,8 +184,23 @@
//_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);
+
+ if(multiplier==sss->prevratio[i]){
+
+ for(k=0;k<input_size;k++)
+ fast[k]=fromdB_a((todB_a(slow+k)-todB_a(fast+k))*.5*multiplier);
+
+ }else{
+ float multiplier_add=(multiplier-sss->prevratio[i])/input_size;
+ multiplier=sss->prevratio[i];
+
+ for(k=0;k<input_size;k++){
+ fast[k]=fromdB_a((todB_a(slow+k)-todB_a(fast+k))*.5*multiplier);
+ multiplier+=multiplier_add;
+ }
+
+ }
+
//_analysis("adj",i,fast,input_size,1,offset);
if(sset->linkp && firstlink==1){
@@ -214,6 +231,9 @@
memset(&sss->iirR[i][j],0,sizeof(iir_state));
}
}
+
+ sss->prevratio[i]=multiplier;
+
}
}
Modified: trunk/postfish/suppress.h
===================================================================
--- trunk/postfish/suppress.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/suppress.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -47,3 +47,5 @@
extern int suppress_load(void);
extern time_linkage *suppress_read_channel(time_linkage *in);
+extern suppress_settings suppress_channel_set;
+
Modified: trunk/postfish/suppresspanel.c
===================================================================
--- trunk/postfish/suppresspanel.c 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/suppresspanel.c 2004-05-29 01:17:47 UTC (rev 6774)
@@ -31,13 +31,8 @@
#include "feedback.h"
#include "suppress.h"
#include "suppresspanel.h"
+#include "config.h"
-extern int input_ch;
-extern int input_size;
-extern int input_rate;
-
-extern suppress_settings suppress_channel_set;
-
typedef struct {
GtkWidget *cslider;
Readout *readoutc;
@@ -47,6 +42,7 @@
} tbar;
typedef struct{
+ Multibar *s;
Readout *r0;
Readout *r1;
Readout *r2;
@@ -56,12 +52,50 @@
} callback_arg_rv3;
typedef struct suppress_panel_state{
- callback_arg_rv3 timing;
- tbar bars[suppress_freqs+1];
+ subpanel_generic *panel;
+
+ GtkWidget *link;
+ callback_arg_rv3 timing;
+ tbar bars[suppress_freqs];
} suppress_panel_state;
static suppress_panel_state *channel_panel;
+void suppresspanel_state_to_config(int bank){
+ config_set_vector("suppresspanel_active",bank,0,0,0,input_ch,suppress_channel_set.active);
+ config_set_vector("suppresspanel_ratio",bank,0,0,0,suppress_freqs,suppress_channel_set.ratio);
+ config_set_integer("suppresspanel_set",bank,0,0,0,0,suppress_channel_set.linkp);
+ config_set_integer("suppresspanel_set",bank,0,0,0,1,suppress_channel_set.smooth);
+ config_set_integer("suppresspanel_set",bank,0,0,0,2,suppress_channel_set.trigger);
+ config_set_integer("suppresspanel_set",bank,0,0,0,3,suppress_channel_set.release);
+}
+
+void suppresspanel_state_from_config(int bank){
+ int i;
+
+ config_get_vector("suppresspanel_active",bank,0,0,0,input_ch,suppress_channel_set.active);
+ for(i=0;i<input_ch;i++)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(channel_panel->panel->subpanel_activebutton[i]),
+ suppress_channel_set.active[i]);
+
+ config_get_vector("suppresspanel_ratio",bank,0,0,0,suppress_freqs,suppress_channel_set.ratio);
+ for(i=0;i<suppress_freqs;i++)
+ multibar_thumb_set(MULTIBAR(channel_panel->bars[i].cslider),
+ 1000./suppress_channel_set.ratio[i],0);
+
+ config_get_sigat("suppresspanel_set",bank,0,0,0,0,&suppress_channel_set.linkp);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(channel_panel->link),suppress_channel_set.linkp);
+
+ config_get_sigat("suppresspanel_set",bank,0,0,0,1,&suppress_channel_set.smooth);
+ multibar_thumb_set(MULTIBAR(channel_panel->timing.s),suppress_channel_set.smooth*.1,0);
+
+ config_get_sigat("suppresspanel_set",bank,0,0,0,2,&suppress_channel_set.trigger);
+ multibar_thumb_set(MULTIBAR(channel_panel->timing.s),suppress_channel_set.trigger*.1,1);
+
+ config_get_sigat("suppresspanel_set",bank,0,0,0,3,&suppress_channel_set.release);
+ multibar_thumb_set(MULTIBAR(channel_panel->timing.s),suppress_channel_set.release*.1,2);
+}
+
static void compand_change(GtkWidget *w,gpointer in){
char buffer[80];
tbar *bar=(tbar *)in;
@@ -149,6 +183,7 @@
GtkWidget *linkbox=gtk_hbox_new(0,0);
suppress_panel_state *ps=calloc(1,sizeof(suppress_panel_state));
+ ps->panel=panel;
gtk_container_add(GTK_CONTAINER(panel->subpanel_box),table);
@@ -194,11 +229,14 @@
g_signal_connect (G_OBJECT (linkbutton), "clicked",
G_CALLBACK (suppress_link), &sset->linkp);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linkbutton),1);
+ ps->link=linkbutton;
/* timing controls */
{
GtkWidget *slider=multibar_slider_new(5,timing_labels,timing_levels,3);
+ ps->timing.s=MULTIBAR(slider);
+
ps->timing.r0=READOUT(readout_new("10.0ms"));
ps->timing.r1=READOUT(readout_new("10.0ms"));
ps->timing.r2=READOUT(readout_new("10.0ms"));
@@ -209,9 +247,9 @@
multibar_callback(MULTIBAR(slider),timing_change,&ps->timing);
- multibar_thumb_set(MULTIBAR(slider),20,0);
+ multibar_thumb_set(MULTIBAR(slider),80,0);
multibar_thumb_set(MULTIBAR(slider),100,1);
- multibar_thumb_set(MULTIBAR(slider),1000,2);
+ multibar_thumb_set(MULTIBAR(slider),2000,2);
gtk_table_attach(GTK_TABLE(table),slider,1,2,1,2,
GTK_FILL|GTK_EXPAND,GTK_EXPAND,5,0);
Modified: trunk/postfish/suppresspanel.h
===================================================================
--- trunk/postfish/suppresspanel.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/suppresspanel.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -24,3 +24,6 @@
extern void suppresspanel_create_channel(postfish_mainpanel *mp,
GtkWidget **windowbutton,
GtkWidget **activebutton);
+
+extern void suppresspanel_state_to_config(int bank);
+extern void suppresspanel_state_from_config(int bank);
Modified: trunk/postfish/version.h
===================================================================
--- trunk/postfish/version.h 2004-05-28 21:46:02 UTC (rev 6773)
+++ trunk/postfish/version.h 2004-05-29 01:17:47 UTC (rev 6774)
@@ -1,2 +1,2 @@
#define VERSION "$Id$ "
-/* DO NOT EDIT: Automated versioning hack [Mon May 17 17:49:56 EDT 2004] */
+/* DO NOT EDIT: Automated versioning hack [Fri May 28 21:14:38 EDT 2004] */
--- >8 ----
List archives: http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body. No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.
More information about the commits
mailing list