Commit b9c4208c authored by Monty Montgomery's avatar Monty Montgomery
Browse files

Engine for multiband compander panels for individial channels now active



git-svn-id: https://svn.xiph.org/trunk/postfish@6585 0101bb08-14d6-0310-b084-bc0e0c8e3800
parent c14dabf8
...@@ -90,6 +90,7 @@ typedef struct multi_panel_state{ ...@@ -90,6 +90,7 @@ typedef struct multi_panel_state{
} multi_panel_state; } multi_panel_state;
multi_panel_state *master_panel; multi_panel_state *master_panel;
multi_panel_state **channel_panel;
static void compand_change(GtkWidget *w,gpointer in){ static void compand_change(GtkWidget *w,gpointer in){
callback_arg_rv *ca=(callback_arg_rv *)in; callback_arg_rv *ca=(callback_arg_rv *)in;
...@@ -490,9 +491,9 @@ static void mode_knee(GtkToggleButton *b,gpointer in){ ...@@ -490,9 +491,9 @@ static void mode_knee(GtkToggleButton *b,gpointer in){
*var=mode; *var=mode;
} }
static void compandpanel_create(postfish_mainpanel *mp, static multi_panel_state *compandpanel_create(postfish_mainpanel *mp,
subpanel_generic *panel, subpanel_generic *panel,
multicompand_settings *ms){ multicompand_settings *ms){
int i; int i;
char *labels[14]={"130","120","110","100","90","80","70", char *labels[14]={"130","120","110","100","90","80","70",
"60","50","40","30","20","10","0"}; "60","50","40","30","20","10","0"};
...@@ -508,7 +509,7 @@ static void compandpanel_create(postfish_mainpanel *mp, ...@@ -508,7 +509,7 @@ static void compandpanel_create(postfish_mainpanel *mp,
float per_levels[9]={0,12.5,25,37.5,50,62.5,75,87.5,100}; float per_levels[9]={0,12.5,25,37.5,50,62.5,75,87.5,100};
char *per_labels[8]={"","25%","","50%","","75%","","100%"}; char *per_labels[8]={"","25%","","50%","","75%","","100%"};
multi_panel_state *ps=master_panel=calloc(1,sizeof(multi_panel_state)); multi_panel_state *ps=calloc(1,sizeof(multi_panel_state));
ps->inactive_updatep=1; ps->inactive_updatep=1;
ps->bank_active=2; ps->bank_active=2;
ps->ms=ms; ps->ms=ms;
...@@ -912,8 +913,7 @@ static void compandpanel_create(postfish_mainpanel *mp, ...@@ -912,8 +913,7 @@ static void compandpanel_create(postfish_mainpanel *mp,
ps->bars[multicomp_freqs_max].slider=multibar_slider_new(14,labels,levels,2); ps->bars[multicomp_freqs_max].slider=multibar_slider_new(14,labels,levels,2);
multibar_callback(MULTIBAR(ps->bars[multicomp_freqs_max].slider),average_change, multibar_callback(MULTIBAR(ps->bars[multicomp_freqs_max].slider),average_change,ps);
master_panel);
multibar_thumb_set(MULTIBAR(ps->bars[multicomp_freqs_max].slider),-140.,0); multibar_thumb_set(MULTIBAR(ps->bars[multicomp_freqs_max].slider),-140.,0);
multibar_thumb_set(MULTIBAR(ps->bars[multicomp_freqs_max].slider),0.,1); multibar_thumb_set(MULTIBAR(ps->bars[multicomp_freqs_max].slider),0.,1);
...@@ -932,6 +932,7 @@ static void compandpanel_create(postfish_mainpanel *mp, ...@@ -932,6 +932,7 @@ static void compandpanel_create(postfish_mainpanel *mp,
/* Now unmap the sliders we don't want */ /* Now unmap the sliders we don't want */
static_octave(NULL,&ps->octave_full); static_octave(NULL,&ps->octave_full);
return ps;
} }
void compandpanel_create_master(postfish_mainpanel *mp, void compandpanel_create_master(postfish_mainpanel *mp,
...@@ -944,13 +945,15 @@ void compandpanel_create_master(postfish_mainpanel *mp, ...@@ -944,13 +945,15 @@ void compandpanel_create_master(postfish_mainpanel *mp,
"_Multiband Compand (master)",shortcut, "_Multiband Compand (master)",shortcut,
0,1); 0,1);
compandpanel_create(mp,panel,&multi_master_set); master_panel=compandpanel_create(mp,panel,&multi_master_set);
} }
void compandpanel_create_channel(postfish_mainpanel *mp, void compandpanel_create_channel(postfish_mainpanel *mp,
GtkWidget **windowbutton, GtkWidget **windowbutton,
GtkWidget **activebutton){ GtkWidget **activebutton){
int i; int i;
channel_panel=calloc(input_ch,sizeof(*channel_panel));
/* a panel for each channel */ /* a panel for each channel */
for(i=0;i<input_ch;i++){ for(i=0;i<input_ch;i++){
...@@ -964,7 +967,7 @@ void compandpanel_create_channel(postfish_mainpanel *mp, ...@@ -964,7 +967,7 @@ void compandpanel_create_channel(postfish_mainpanel *mp,
buffer,NULL, buffer,NULL,
i,1); i,1);
compandpanel_create(mp,panel,multi_channel_set+1); channel_panel[i]=compandpanel_create(mp,panel,multi_channel_set+i);
} }
} }
...@@ -973,7 +976,7 @@ static float **peakfeed=0; ...@@ -973,7 +976,7 @@ static float **peakfeed=0;
static float **rmsfeed=0; static float **rmsfeed=0;
void compandpanel_feedback(int displayit){ void compandpanel_feedback(int displayit){
int i,bands; int i,j,bands;
if(!peakfeed){ if(!peakfeed){
peakfeed=malloc(sizeof(*peakfeed)*multicomp_freqs_max); peakfeed=malloc(sizeof(*peakfeed)*multicomp_freqs_max);
rmsfeed=malloc(sizeof(*rmsfeed)*multicomp_freqs_max); rmsfeed=malloc(sizeof(*rmsfeed)*multicomp_freqs_max);
...@@ -988,12 +991,34 @@ void compandpanel_feedback(int displayit){ ...@@ -988,12 +991,34 @@ void compandpanel_feedback(int displayit){
for(i=0;i<bands;i++) for(i=0;i<bands;i++)
multibar_set(MULTIBAR(master_panel->bars[i].slider),rmsfeed[i],peakfeed[i], multibar_set(MULTIBAR(master_panel->bars[i].slider),rmsfeed[i],peakfeed[i],
input_ch,(displayit && multi_master_set.panel_visible)); input_ch,(displayit && multi_master_set.panel_visible));
/* channel panels are a bit different; we want each in its native color */
if(pull_multicompand_feedback_channel(peakfeed,rmsfeed,&bands)==1){
for(j=0;j<input_ch;j++){
for(i=0;i<bands;i++){
float rms[input_ch];
float peak[input_ch];
memset(rms,0,sizeof(rms));
memset(peak,0,sizeof(peak));
rms[j]=rmsfeed[i][j];
peak[j]=peakfeed[i][j];
multibar_set(MULTIBAR(channel_panel[j]->bars[i].slider),rms,peak,
input_ch,(displayit && multi_channel_set[j].panel_visible));
}
}
}
} }
void compandpanel_reset(void){ void compandpanel_reset(void){
int i; int i,j;
for(i=0;i<multicomp_freqs_max;i++) for(i=0;i<multicomp_freqs_max;i++)
multibar_reset(MULTIBAR(master_panel->bars[i].slider)); multibar_reset(MULTIBAR(master_panel->bars[i].slider));
for(i=0;i<multicomp_freqs_max;i++)
for(j=0;j<input_ch;j++)
multibar_reset(MULTIBAR(channel_panel[j]->bars[i].slider));
} }
...@@ -49,7 +49,6 @@ typedef struct { ...@@ -49,7 +49,6 @@ typedef struct {
typedef struct { typedef struct {
feedback_generic_pool feedpool; feedback_generic_pool feedpool;
subband_state ss; subband_state ss;
subband_window sw[multicomp_banks];
iir_filter *over_attack; iir_filter *over_attack;
iir_filter *over_decay; iir_filter *over_decay;
...@@ -76,7 +75,10 @@ typedef struct { ...@@ -76,7 +75,10 @@ typedef struct {
multicompand_settings multi_master_set; multicompand_settings multi_master_set;
multicompand_settings *multi_channel_set; multicompand_settings *multi_channel_set;
static multicompand_state ms; static multicompand_state master_state;
static multicompand_state channel_state;
static subband_window sw[multicomp_banks];
static feedback_generic *new_multicompand_feedback(void){ static feedback_generic *new_multicompand_feedback(void){
int i; int i;
...@@ -95,14 +97,14 @@ static feedback_generic *new_multicompand_feedback(void){ ...@@ -95,14 +97,14 @@ static feedback_generic *new_multicompand_feedback(void){
/* total, peak, rms are pulled in array[freqs][input_ch] order */ /* total, peak, rms are pulled in array[freqs][input_ch] order */
int pull_multicompand_feedback_master(float **peak,float **rms,int *b){ static int pull_multicompand_feedback(multicompand_state *ms,float **peak,float **rms,int *b){
multicompand_feedback *f=(multicompand_feedback *)feedback_pull(&ms.feedpool); multicompand_feedback *f=(multicompand_feedback *)feedback_pull(&ms->feedpool);
int i; int i;
if(!f)return 0; if(!f)return 0;
if(f->bypass){ if(f->bypass){
feedback_old(&ms.feedpool,(feedback_generic *)f); feedback_old(&ms->feedpool,(feedback_generic *)f);
return 2; return 2;
}else{ }else{
if(peak) if(peak)
...@@ -112,11 +114,19 @@ int pull_multicompand_feedback_master(float **peak,float **rms,int *b){ ...@@ -112,11 +114,19 @@ int pull_multicompand_feedback_master(float **peak,float **rms,int *b){
for(i=0;i<f->freq_bands;i++) for(i=0;i<f->freq_bands;i++)
memcpy(rms[i],f->rms[i],sizeof(**rms)*input_ch); memcpy(rms[i],f->rms[i],sizeof(**rms)*input_ch);
if(b)*b=f->freq_bands; if(b)*b=f->freq_bands;
feedback_old(&ms.feedpool,(feedback_generic *)f); feedback_old(&ms->feedpool,(feedback_generic *)f);
return 1; return 1;
} }
} }
int pull_multicompand_feedback_master(float **peak,float **rms,int *b){
return pull_multicompand_feedback(&master_state,peak,rms,b);
}
int pull_multicompand_feedback_channel(float **peak,float **rms,int *b){
return pull_multicompand_feedback(&channel_state,peak,rms,b);
}
static void reset_filters(multicompand_state *ms){ static void reset_filters(multicompand_state *ms){
int i,j; int i,j;
for(i=0;i<multicomp_freqs_max;i++) for(i=0;i<multicomp_freqs_max;i++)
...@@ -132,61 +142,72 @@ static void reset_filters(multicompand_state *ms){ ...@@ -132,61 +142,72 @@ static void reset_filters(multicompand_state *ms){
void multicompand_reset(){ void multicompand_reset(){
subband_reset(&ms.ss); subband_reset(&master_state.ss);
subband_reset(&channel_state.ss);
while(pull_multicompand_feedback_master(NULL,NULL,NULL)); while(pull_multicompand_feedback_master(NULL,NULL,NULL));
reset_filters(&ms); while(pull_multicompand_feedback_channel(NULL,NULL,NULL));
reset_filters(&master_state);
reset_filters(&channel_state);
} }
int multicompand_load(void){ static int multicompand_load_helper(multicompand_state *ms){
int h,i; int i;
int qblocksize=input_size/8; int qblocksize=input_size/8;
memset(&ms,0,sizeof(ms)); memset(ms,0,sizeof(ms));
multi_channel_set=calloc(input_ch,sizeof(*multi_channel_set)); subband_load(&ms->ss,multicomp_freqs_max,qblocksize);
subband_load(&ms.ss,multicomp_freqs_max,qblocksize); ms->over_attack=calloc(input_ch,sizeof(*ms->over_attack));
ms->over_decay=calloc(input_ch,sizeof(*ms->over_decay));
for(h=0;h<multicomp_banks;h++) ms->under_attack=calloc(input_ch,sizeof(*ms->under_attack));
subband_load_freqs(&ms.ss,&ms.sw[h],multicomp_freq_list[h], ms->under_decay=calloc(input_ch,sizeof(*ms->under_decay));
multicomp_freqs[h]);
ms.over_attack=calloc(input_ch,sizeof(*ms.over_attack));
ms.over_decay=calloc(input_ch,sizeof(*ms.over_decay));
ms.under_attack=calloc(input_ch,sizeof(*ms.under_attack)); ms->base_attack=calloc(input_ch,sizeof(*ms->base_attack));
ms.under_decay=calloc(input_ch,sizeof(*ms.under_decay)); ms->base_decay=calloc(input_ch,sizeof(*ms->base_decay));
ms.base_attack=calloc(input_ch,sizeof(*ms.base_attack));
ms.base_decay=calloc(input_ch,sizeof(*ms.base_decay));
for(i=0;i<multicomp_freqs_max;i++){ for(i=0;i<multicomp_freqs_max;i++){
ms.over_peak[i]=calloc(input_ch,sizeof(peak_state)); ms->over_peak[i]=calloc(input_ch,sizeof(peak_state));
ms.under_peak[i]=calloc(input_ch,sizeof(peak_state)); ms->under_peak[i]=calloc(input_ch,sizeof(peak_state));
ms.base_peak[i]=calloc(input_ch,sizeof(peak_state)); ms->base_peak[i]=calloc(input_ch,sizeof(peak_state));
ms.over_iir[i]=calloc(input_ch,sizeof(iir_state)); ms->over_iir[i]=calloc(input_ch,sizeof(iir_state));
ms.under_iir[i]=calloc(input_ch,sizeof(iir_state)); ms->under_iir[i]=calloc(input_ch,sizeof(iir_state));
ms.base_iir[i]=calloc(input_ch,sizeof(iir_state)); ms->base_iir[i]=calloc(input_ch,sizeof(iir_state));
} }
ms.peak=calloc(multicomp_freqs_max,sizeof(*ms.peak)); ms->peak=calloc(multicomp_freqs_max,sizeof(*ms->peak));
ms.rms=calloc(multicomp_freqs_max,sizeof(*ms.rms)); ms->rms=calloc(multicomp_freqs_max,sizeof(*ms->rms));
for(i=0;i<multicomp_freqs_max;i++)ms.peak[i]=malloc(input_ch*sizeof(**ms.peak)); for(i=0;i<multicomp_freqs_max;i++)ms->peak[i]=malloc(input_ch*sizeof(**ms->peak));
for(i=0;i<multicomp_freqs_max;i++)ms.rms[i]=malloc(input_ch*sizeof(**ms.rms)); for(i=0;i<multicomp_freqs_max;i++)ms->rms[i]=malloc(input_ch*sizeof(**ms->rms));
return 0; return 0;
} }
static void filter_set(float msec, int multicompand_load(void){
iir_filter *filter, int i;
int attackp){ multi_channel_set=calloc(input_ch,sizeof(*multi_channel_set));
multicompand_load_helper(&master_state);
multicompand_load_helper(&channel_state);
for(i=0;i<multicomp_banks;i++)
subband_load_freqs(&master_state.ss,&sw[i],multicomp_freq_list[i],
multicomp_freqs[i]);
return 0;
}
static void filter_set(multicompand_state *ms,
float msec,
iir_filter *filter,
int attackp){
float alpha; float alpha;
float corner_freq= 500./msec; float corner_freq= 500./msec;
/* make sure the chosen frequency doesn't require a lookahead /* make sure the chosen frequency doesn't require a lookahead
greater than what's available */ greater than what's available */
if(step_freq(input_size*2-ms.ss.qblocksize*3)*1.01>corner_freq && attackp) if(step_freq(input_size*2-ms->ss.qblocksize*3)*1.01>corner_freq && attackp)
corner_freq=step_freq(input_size*2-ms.ss.qblocksize*3); corner_freq=step_freq(input_size*2-ms->ss.qblocksize*3);
alpha=corner_freq/input_rate; alpha=corner_freq/input_rate;
filter->g=mkbessel(alpha,2,filter->c); filter->g=mkbessel(alpha,2,filter->c);
...@@ -195,12 +216,13 @@ static void filter_set(float msec, ...@@ -195,12 +216,13 @@ static void filter_set(float msec,
} }
static void filterbank_set(float msec, static void filterbank_set(multicompand_state *ms,
iir_filter *filter, float msec,
int attackp){ iir_filter *filter,
int attackp){
int i; int i;
for(i=0;i<input_ch;i++) for(i=0;i<input_ch;i++)
filter_set(msec,filter+i,attackp); filter_set(ms,msec,filter+i,attackp);
} }
...@@ -356,7 +378,7 @@ static int find_maxbands(subband_state *ss,int channel){ ...@@ -356,7 +378,7 @@ static int find_maxbands(subband_state *ss,int channel){
return maxbands; return maxbands;
} }
static int multicompand_work_channel(multicompand_state *ms, static int multicompand_work_perchannel(multicompand_state *ms,
float **peakfeed, float **peakfeed,
float **rmsfeed, float **rmsfeed,
int maxbands, int maxbands,
...@@ -373,9 +395,9 @@ static int multicompand_work_channel(multicompand_state *ms, ...@@ -373,9 +395,9 @@ static int multicompand_work_channel(multicompand_state *ms,
subband_window *wP=ss->wP[channel]; subband_window *wP=ss->wP[channel];
float adj[input_size]; float adj[input_size];
if(w==&ms->sw[0]){ if(w==&sw[0]){
bank=0; bank=0;
}else if(w==&ms->sw[1]){ }else if(w==&sw[1]){
bank=1; bank=1;
}else bank=2; }else bank=2;
...@@ -478,31 +500,10 @@ static int multicompand_work_channel(multicompand_state *ms, ...@@ -478,31 +500,10 @@ static int multicompand_work_channel(multicompand_state *ms,
return(feedback_p); return(feedback_p);
} }
static void multicompand_work(void *vs){ static void push_feedback(multicompand_state *ms,int bypass,int maxmaxbands){
multicompand_state *ms=(multicompand_state *)vs; int i;
subband_state *ss=&ms->ss;
int i,j,bypass_visible=1;
int maxmaxbands=0;
float **peakfeed=ms->peak;
float **rmsfeed=ms->rms;
for(i=0;i<multicomp_freqs_max;i++){
memset(peakfeed[i],0,input_ch*sizeof(**peakfeed));
memset(rmsfeed[i],0,input_ch*sizeof(**rmsfeed));
}
for(j=0;j<input_ch;j++){
int maxbands=find_maxbands(ss,j);
if(maxbands>maxmaxbands)maxmaxbands=maxbands;
if(multicompand_work_channel(ms, peakfeed, rmsfeed, maxbands, j, &multi_master_set))
bypass_visible=0;
}
/* finish up the state feedabck */ if(bypass){
if(bypass_visible){
multicompand_feedback *ff= multicompand_feedback *ff=
(multicompand_feedback *) (multicompand_feedback *)
feedback_new(&ms->feedpool,new_multicompand_feedback); feedback_new(&ms->feedpool,new_multicompand_feedback);
...@@ -523,16 +524,56 @@ static void multicompand_work(void *vs){ ...@@ -523,16 +524,56 @@ static void multicompand_work(void *vs){
} }
} }
static void multicompand_work_master(void *vs){
multicompand_state *ms=(multicompand_state *)vs;
int i,bypass_visible=1;
int maxmaxbands=0;
for(i=0;i<multicomp_freqs_max;i++){
memset(ms->peak[i],0,input_ch*sizeof(**ms->peak));
memset(ms->rms[i],0,input_ch*sizeof(**ms->rms));
}
for(i=0;i<input_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))
bypass_visible=0;
}
push_feedback(ms,bypass_visible,maxmaxbands);
}
static void multicompand_work_channel(void *vs){
multicompand_state *ms=(multicompand_state *)vs;
int i,bypass_visible=1;
int maxmaxbands=0;
for(i=0;i<multicomp_freqs_max;i++){
memset(ms->peak[i],0,input_ch*sizeof(**ms->peak));
memset(ms->rms[i],0,input_ch*sizeof(**ms->rms));
}
for(i=0;i<input_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))
bypass_visible=0;
}
push_feedback(ms,bypass_visible,maxmaxbands);
}
time_linkage *multicompand_read_master(time_linkage *in){ time_linkage *multicompand_read_master(time_linkage *in){
int visible[input_ch]; int visible[input_ch];
int active[input_ch]; int active[input_ch];
subband_window *w[input_ch]; subband_window *w[input_ch];
int i,ab=multi_master_set.active_bank; int i,ab=multi_master_set.active_bank;
for(i=0;i<input_ch;i++){ for(i=0;i<input_ch;i++){
visible[i]=multi_master_set.panel_visible; visible[i]=multi_master_set.panel_visible;
active[i]=multi_master_set.panel_active; active[i]=multi_master_set.panel_active;
w[i]=&ms.sw[ab]; w[i]=&sw[ab];
} }
/* do any filters need updated from UI changes? */ /* do any filters need updated from UI changes? */
...@@ -544,17 +585,61 @@ time_linkage *multicompand_read_master(time_linkage *in){ ...@@ -544,17 +585,61 @@ time_linkage *multicompand_read_master(time_linkage *in){
float b_attackms=multi_master_set.base_attack*.1; float b_attackms=multi_master_set.base_attack*.1;
float b_decayms=multi_master_set.base_decay*.1; float b_decayms=multi_master_set.base_decay*.1;
if(o_attackms!=ms.over_attack[0].ms) filterbank_set(o_attackms,ms.over_attack,1); if(o_attackms!=master_state.over_attack[0].ms)
if(o_decayms !=ms.over_decay[0].ms) filterbank_set(o_decayms,ms.over_decay,0); filterbank_set(&master_state,o_attackms,master_state.over_attack,1);
if(u_attackms!=ms.under_attack[0].ms)filterbank_set(u_attackms,ms.under_attack,1); if(o_decayms !=master_state.over_decay[0].ms)
if(u_decayms !=ms.under_decay[0].ms) filterbank_set(u_decayms,ms.under_decay,0); filterbank_set(&master_state,o_decayms,master_state.over_decay,0);
if(b_attackms!=ms.base_attack[0].ms) filterbank_set(b_attackms,ms.base_attack,1); if(u_attackms!=master_state.under_attack[0].ms)
if(b_decayms !=ms.base_decay[0].ms) filterbank_set(b_decayms,ms.base_decay,0); filterbank_set(&master_state,u_attackms,master_state.under_attack,1);
if(u_decayms !=master_state.under_decay[0].ms)
filterbank_set(&master_state,u_decayms,master_state.under_decay,0);
if(b_attackms!=master_state.base_attack[0].ms)
filterbank_set(&master_state,b_attackms,master_state.base_attack,1);
if(b_decayms !=master_state.base_decay[0].ms)
filterbank_set(&master_state,b_decayms,master_state.base_decay,0);
} }
return subband_read(in, &ms.ss, w, return subband_read(in, &master_state.ss, w, visible,active,
visible,active,multicompand_work,&ms); multicompand_work_master,&master_state);
}
time_linkage *multicompand_read_channel(time_linkage *in){
int visible[input_ch];
int active[input_ch];
subband_window *w[input_ch];
int i;
for(i=0;i<input_ch;i++){
/* do any filters need updated from UI changes? */
float o_attackms=multi_channel_set[i].over_attack*.1;
float o_decayms=multi_channel_set[i].over_decay*.1;
float u_attackms=multi_channel_set[i].under_attack*.1;
float u_decayms=multi_channel_set[i].under_decay*.1;
float b_attackms=multi_channel_set[i].base_attack*.1;
float b_decayms=multi_channel_set[i].base_decay*.1;
if(o_attackms!=channel_state.over_attack[i].ms)
filter_set(&master_state,o_attackms,channel_state.over_attack+i,1);
if(o_decayms !=channel_state.over_decay[i].ms)
filter_set(&master_state,o_decayms,channel_state.over_decay+i,0);
if(u_attackms!=channel_state.under_attack[i].ms)
filter_set(&master_state,u_attackms,channel_state.under_attack+i,1);
if(u_decayms !=channel_state.under_decay[i].ms)
filter_set(&master_state,u_decayms,channel_state.under_decay+i,0);
if(b_attackms!=channel_state.base_attack[i].ms)
filter_set(&master_state,b_attackms,channel_state.base_attack+i,1);
if(b_decayms !=channel_state.base_decay[i].ms)
filter_set(&master_state,b_decayms,channel_state.base_decay+i,0);
w[i]=&sw[multi_channel_set[i].active_bank];
visible[i]=multi_channel_set[i].panel_visible;
active[i]=multi_channel_set[i].panel_active;
}
return subband_read(in, &channel_state.ss, w, visible, active,
multicompand_work_channel,&channel_state);
}