Commit affc4a72 authored by Monty Montgomery's avatar Monty Montgomery

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.  



git-svn-id: https://svn.xiph.org/trunk/postfish@6774 0101bb08-14d6-0310-b084-bc0e0c8e3800
parent 637b80f1
......@@ -3,14 +3,19 @@
# and Fuck its little dog Libtool too
ADD_DEF= -DUGLY_IEEE754_FLOAT32_HACK=1 -maltivec
# use for PPC with altivec. IF YOU HAVE ALTIVEC, YOU MUST USE THIS
# LINE, otherwise FFTW3 will randomly crash whenever it uses Altivec
# and any math denormalizes.
# The PPC build *must* use -maltivec, even if the target is a non-altivec machine
#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 @@ SRC = main.c mainpanel.c multibar.c readout.c input.c output.c clippanel.c \
declip.c reconstruct.c multicompand.c windowbutton.c subpanel.c \
feedback.c freq.c eq.c eqpanel.c compandpanel.c subband.c lpc.c \
bessel.c suppresspanel.c suppress.c singlecomp.c singlepanel.c \
limit.c limitpanel.c mute.c 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:
......
......@@ -29,24 +29,24 @@
#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;
......@@ -55,6 +55,37 @@ typedef struct {
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 @@ static void trigger_slider_change(GtkWidget *w,gpointer in){
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 @@ static void blocksize_slider_change(GtkWidget *w,gpointer in){
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 @@ static void depth_slider_change(GtkWidget *w,gpointer in){
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 @@ static void limit_slider_change(GtkWidget *w,gpointer in){
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 @@ void clippanel_create(postfish_mainpanel *mp,
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 @@ void clippanel_create(postfish_mainpanel *mp,
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 @@ void clippanel_create(postfish_mainpanel *mp,
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 @@ void clippanel_create(postfish_mainpanel *mp,
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 @@ void clippanel_create(postfish_mainpanel *mp,
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);
......
......@@ -28,3 +28,6 @@ extern void clippanel_create(postfish_mainpanel *mp,
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);
This diff is collapsed.
......@@ -31,5 +31,7 @@ extern void compandpanel_create_channel(postfish_mainpanel *mp,
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);
/*
*
* 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");
}
/*
*
* 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);
......@@ -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 @@ int *declip_prev_active;
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 declip_load(void){
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 @@ int declip_load(void){
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 declip_load(void){
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 @@ int declip_load(void){
}
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 @@ time_linkage *declip_read(time_linkage *in){
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 @@ time_linkage *declip_read(time_linkage *in){
}
}
}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;
......
......@@ -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;
......@@ -27,8 +27,6 @@
#include "freq.h"
#include "eq.h"
extern int input_size;
typedef struct{
freq_state eq;
......
......@@ -56,3 +56,7 @@ extern int eq_reset();
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;
......@@ -31,13 +31,7 @@
#include "feedback.h"
#include "freq.h"
#include "eq.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;
#include "config.h"
typedef struct {
GtkWidget *slider;
......@@ -46,8 +40,45 @@ typedef struct {
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