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

Major signal path upgrade to subband.c:

  eliminate all clicks/thumps/dropouts on realtime interaction
  implement mute infrastructure
  active/visible by channel



git-svn-id: https://svn.xiph.org/trunk/postfish@6573 0101bb08-14d6-0310-b084-bc0e0c8e3800
parent 97a22680
......@@ -226,6 +226,7 @@ static void slider_change(GtkWidget *w,gpointer in){
cbar *b=(cbar *)in;
int o,u;
int i;
int adj;
u=multibar_get_value(MULTIBAR(b->slider),0);
sprintf(buffer,"%+4ddB",u);
......@@ -246,101 +247,98 @@ static void slider_change(GtkWidget *w,gpointer in){
bc[2].static_o[0]+=o-bc[2].static_o[1];
bc[2].static_u[0]+=u-bc[2].static_u[1];
}
if (b->number<9){
int adj;
/* convolutions for roundoff behavior */
if(b->number>0){
adj=(bc[1].static_o[b->number*2-1]*2 -
bc[1].static_o[b->number*2-2]-bc[1].static_o[b->number*2])/2;
bc[1].static_o[b->number*2-1]=
/* convolutions for roundoff behavior */
if(b->number>0){
adj=(bc[1].static_o[b->number*2-1]*2 -
bc[1].static_o[b->number*2-2]-bc[1].static_o[b->number*2])/2;
bc[1].static_o[b->number*2-1]=
(bc[1].static_o[b->number*2-2]+o)/2+adj;
adj=(bc[1].static_u[b->number*2-1]*2 -
bc[1].static_u[b->number*2-2]-bc[1].static_u[b->number*2])/2;
bc[1].static_u[b->number*2-1]=
(bc[1].static_u[b->number*2-2]+u)/2+adj;
adj=(bc[2].static_o[b->number*3-1]*3 -
bc[2].static_o[b->number*3-2] -
bc[2].static_o[b->number*3-2] -
bc[2].static_o[b->number*3+1])/3;
bc[2].static_o[b->number*3-1]=
(bc[2].static_o[b->number*3-2]+
bc[2].static_o[b->number*3-2]+
o)/3+adj;
adj=(bc[2].static_o[b->number*3]*3 -
bc[2].static_o[b->number*3-2] -
bc[2].static_o[b->number*3+1] -
bc[2].static_o[b->number*3+1])/3;
bc[2].static_o[b->number*3]=
(bc[2].static_o[b->number*3-2]+o+o)/3+adj;
adj=(bc[2].static_u[b->number*3-1]*3 -
bc[2].static_u[b->number*3-2] -
bc[2].static_u[b->number*3-2] -
bc[2].static_u[b->number*3+1])/3;
bc[2].static_u[b->number*3-1]=
(bc[2].static_u[b->number*3-2]+
bc[2].static_u[b->number*3-2]+
u)/3+adj;
adj=(bc[2].static_u[b->number*3]*3 -
bc[2].static_u[b->number*3-2] -
bc[2].static_u[b->number*3+1] -
bc[2].static_u[b->number*3+1])/3;
bc[2].static_u[b->number*3]=
(bc[2].static_u[b->number*3-2]+u+u)/3+adj;
}
if(b->number<9){
adj=(bc[1].static_o[b->number*2+1]*2-
bc[1].static_o[b->number*2+2]-bc[1].static_o[b->number*2])/2;
bc[1].static_o[b->number*2+1]=
(bc[1].static_o[b->number*2+2]+o)/2+adj;
adj=(bc[1].static_u[b->number*2+1]*2-
bc[1].static_u[b->number*2+2]-bc[1].static_u[b->number*2])/2;
bc[1].static_u[b->number*2+1]=
(bc[1].static_u[b->number*2+2]+u)/2+adj;
adj=(bc[2].static_o[b->number*3+3]*3 -
bc[2].static_o[b->number*3+4] -
bc[2].static_o[b->number*3+4] -
bc[2].static_o[b->number*3+1])/3;
bc[2].static_o[b->number*3+3]=
(bc[2].static_o[b->number*3+4]+
bc[2].static_o[b->number*3+4]+
o)/3+adj;
adj=(bc[2].static_o[b->number*3+2]*3 -
bc[2].static_o[b->number*3+4] -
bc[2].static_o[b->number*3+1] -
bc[2].static_o[b->number*3+1])/3;
bc[2].static_o[b->number*3+2]=
(bc[2].static_o[b->number*3+4]+o+o)/3+adj;
adj=(bc[2].static_u[b->number*3+3]*3 -
bc[2].static_u[b->number*3+4] -
bc[2].static_u[b->number*3+4] -
bc[2].static_u[b->number*3+1])/3;
bc[2].static_u[b->number*3+3]=
(bc[2].static_u[b->number*3+4]+
bc[2].static_u[b->number*3+4]+
u)/3+adj;
adj=(bc[2].static_u[b->number*3+2]*3 -
bc[2].static_u[b->number*3+4] -
bc[2].static_u[b->number*3+1] -
bc[2].static_u[b->number*3+1])/3;
bc[2].static_u[b->number*3+2]=
(bc[2].static_u[b->number*3+4]+u+u)/3+adj;
}
adj=(bc[1].static_u[b->number*2-1]*2 -
bc[1].static_u[b->number*2-2]-bc[1].static_u[b->number*2])/2;
bc[1].static_u[b->number*2-1]=
(bc[1].static_u[b->number*2-2]+u)/2+adj;
adj=(bc[2].static_o[b->number*3-1]*3 -
bc[2].static_o[b->number*3-2] -
bc[2].static_o[b->number*3-2] -
bc[2].static_o[b->number*3+1])/3;
bc[2].static_o[b->number*3-1]=
(bc[2].static_o[b->number*3-2]+
bc[2].static_o[b->number*3-2]+
o)/3+adj;
adj=(bc[2].static_o[b->number*3]*3 -
bc[2].static_o[b->number*3-2] -
bc[2].static_o[b->number*3+1] -
bc[2].static_o[b->number*3+1])/3;
bc[2].static_o[b->number*3]=
(bc[2].static_o[b->number*3-2]+o+o)/3+adj;
adj=(bc[2].static_u[b->number*3-1]*3 -
bc[2].static_u[b->number*3-2] -
bc[2].static_u[b->number*3-2] -
bc[2].static_u[b->number*3+1])/3;
bc[2].static_u[b->number*3-1]=
(bc[2].static_u[b->number*3-2]+
bc[2].static_u[b->number*3-2]+
u)/3+adj;
adj=(bc[2].static_u[b->number*3]*3 -
bc[2].static_u[b->number*3-2] -
bc[2].static_u[b->number*3+1] -
bc[2].static_u[b->number*3+1])/3;
bc[2].static_u[b->number*3]=
(bc[2].static_u[b->number*3-2]+u+u)/3+adj;
}
if(b->number<9){
adj=(bc[1].static_o[b->number*2+1]*2-
bc[1].static_o[b->number*2+2]-bc[1].static_o[b->number*2])/2;
bc[1].static_o[b->number*2+1]=
(bc[1].static_o[b->number*2+2]+o)/2+adj;
adj=(bc[1].static_u[b->number*2+1]*2-
bc[1].static_u[b->number*2+2]-bc[1].static_u[b->number*2])/2;
bc[1].static_u[b->number*2+1]=
(bc[1].static_u[b->number*2+2]+u)/2+adj;
adj=(bc[2].static_o[b->number*3+3]*3 -
bc[2].static_o[b->number*3+4] -
bc[2].static_o[b->number*3+4] -
bc[2].static_o[b->number*3+1])/3;
bc[2].static_o[b->number*3+3]=
(bc[2].static_o[b->number*3+4]+
bc[2].static_o[b->number*3+4]+
o)/3+adj;
adj=(bc[2].static_o[b->number*3+2]*3 -
bc[2].static_o[b->number*3+4] -
bc[2].static_o[b->number*3+1] -
bc[2].static_o[b->number*3+1])/3;
bc[2].static_o[b->number*3+2]=
(bc[2].static_o[b->number*3+4]+o+o)/3+adj;
adj=(bc[2].static_u[b->number*3+3]*3 -
bc[2].static_u[b->number*3+4] -
bc[2].static_u[b->number*3+4] -
bc[2].static_u[b->number*3+1])/3;
bc[2].static_u[b->number*3+3]=
(bc[2].static_u[b->number*3+4]+
bc[2].static_u[b->number*3+4]+
u)/3+adj;
adj=(bc[2].static_u[b->number*3+2]*3 -
bc[2].static_u[b->number*3+4] -
bc[2].static_u[b->number*3+1] -
bc[2].static_u[b->number*3+1])/3;
bc[2].static_u[b->number*3+2]=
(bc[2].static_u[b->number*3+4]+u+u)/3+adj;
}
if(b->number==9){
bc[1].static_o[19]+=o-bc[1].static_o[18];
bc[1].static_u[19]+=u-bc[1].static_u[18];
......@@ -461,7 +459,8 @@ static void static_octave(GtkWidget *w,gpointer in){
gtk_widget_hide(bars[i].readoutu);
}
}
multicompand_set_bank(bank_active);
c.active_bank=bank_active;
}
}
......
......@@ -476,6 +476,7 @@ time_linkage *freq_read(time_linkage *in, freq_state *f,
break;
case 3: /* we've pushed out EOF already */
f->out.samples=0;
return &f->out;
}
/* finish up the state feedabck */
......
......@@ -32,23 +32,33 @@ extern int input_size;
extern int input_rate;
extern int input_ch;
/* feedback! */
typedef struct multicompand_feedback{
feedback_generic parent_class;
float **peak;
float **rms;
int freq_bands;
int bypass;
} multicompand_feedback;
typedef struct {
int loc;
float val;
} peak_state;
typedef struct {
feedback_generic_pool feedpool;
subband_state ss;
subband_window sw[multicomp_banks];
iir_filter over_attack[multicomp_banks][multicomp_freqs_max];
iir_filter over_decay[multicomp_banks][multicomp_freqs_max];
iir_filter over_attack;
iir_filter over_decay;
iir_filter under_attack[multicomp_banks][multicomp_freqs_max];
iir_filter under_decay[multicomp_banks][multicomp_freqs_max];
iir_filter under_attack;
iir_filter under_decay;
iir_filter base_attack[multicomp_banks][multicomp_freqs_max];
iir_filter base_decay[multicomp_banks][multicomp_freqs_max];
iir_filter base_attack;
iir_filter base_decay;
iir_state *over_iir[multicomp_freqs_max];
iir_state *under_iir[multicomp_freqs_max];
......@@ -58,9 +68,8 @@ typedef struct {
peak_state *under_peak[multicomp_freqs_max];
peak_state *base_peak[multicomp_freqs_max];
sig_atomic_t pending_bank;
sig_atomic_t active_bank;
float **peak;
float **rms;
} multicompand_state;
sig_atomic_t compand_visible;
......@@ -71,26 +80,66 @@ other_compand_settings c;
static multicompand_state ms;
int pull_multicompand_feedback(float **peak,float **rms,int *bands){
return pull_subband_feedback(&ms.ss,peak,rms,bands);
static feedback_generic *new_multicompand_feedback(void){
int i;
multicompand_feedback *ret=calloc(1,sizeof(*ret));
ret->peak=malloc(multicomp_freqs_max*sizeof(*ret->peak));
for(i=0;i<multicomp_freqs_max;i++)
ret->peak[i]=malloc(input_ch*sizeof(**ret->peak));
ret->rms=malloc(multicomp_freqs_max*sizeof(*ret->rms));
for(i=0;i<multicomp_freqs_max;i++)
ret->rms[i]=malloc(input_ch*sizeof(**ret->rms));
return (feedback_generic *)ret;
}
void multicompand_reset(){
int i,j;
/* total, peak, rms are pulled in array[freqs][input_ch] order */
int pull_multicompand_feedback(float **peak,float **rms,int *b){
multicompand_feedback *f=(multicompand_feedback *)feedback_pull(&ms.feedpool);
int i;
subband_reset(&ms.ss);
if(!f)return 0;
if(f->bypass){
feedback_old(&ms.feedpool,(feedback_generic *)f);
return 2;
}else{
if(peak)
for(i=0;i<f->freq_bands;i++)
memcpy(peak[i],f->peak[i],sizeof(**peak)*input_ch);
if(rms)
for(i=0;i<f->freq_bands;i++)
memcpy(rms[i],f->rms[i],sizeof(**rms)*input_ch);
if(b)*b=f->freq_bands;
feedback_old(&ms.feedpool,(feedback_generic *)f);
return 1;
}
}
static void reset_filters(multicompand_state *ms){
int i,j;
for(i=0;i<multicomp_freqs_max;i++)
for(j=0;j<input_ch;j++){
memset(&ms.over_peak[i][j],0,sizeof(peak_state));
memset(&ms.under_peak[i][j],0,sizeof(peak_state));
memset(&ms.base_peak[i][j],0,sizeof(peak_state));
memset(&ms.over_iir[i][j],0,sizeof(iir_state));
memset(&ms.under_iir[i][j],0,sizeof(iir_state));
memset(&ms.base_iir[i][j],0,sizeof(iir_state));
memset(&ms->over_peak[i][j],0,sizeof(peak_state));
memset(&ms->under_peak[i][j],0,sizeof(peak_state));
memset(&ms->base_peak[i][j],0,sizeof(peak_state));
memset(&ms->over_iir[i][j],0,sizeof(iir_state));
memset(&ms->under_iir[i][j],0,sizeof(iir_state));
memset(&ms->base_iir[i][j],0,sizeof(iir_state));
}
}
void multicompand_reset(){
subband_reset(&ms.ss);
while(pull_multicompand_feedback(NULL,NULL,NULL));
reset_filters(&ms);
}
int multicompand_load(void){
int h,i;
int qblocksize=input_size/8;
......@@ -111,14 +160,17 @@ int multicompand_load(void){
ms.base_iir[i]=calloc(input_ch,sizeof(iir_state));
}
ms.active_bank=0;
ms.peak=calloc(multicomp_freqs_max,sizeof(*ms.peak));
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.rms[i]=malloc(input_ch*sizeof(**ms.rms));
return 0;
}
static void multicompand_filter_set(float msec,
iir_filter *filter,
int attackp){
static int multicompand_filter_set(float msec,
iir_filter *filter,
int attackp){
float alpha;
float corner_freq= 500./msec;
......@@ -131,47 +183,32 @@ static void multicompand_filter_set(float msec,
filter->g=mkbessel(alpha,2,filter->c);
filter->alpha=alpha;
filter->Hz=alpha*input_rate;
}
static int multicompand_filterbank_set(float msec,
iir_filter
filterbank[multicomp_banks]
[multicomp_freqs_max],
int attackp){
int i,j;
for(j=0;j<multicomp_banks;j++){
int bands=multicomp_freqs[j];
iir_filter *filters=filterbank[j];
for(i=0;i<bands;i++)
multicompand_filter_set(msec,filters+i,attackp);
}
return 0;
}
int multicompand_over_attack_set(float msec){
return multicompand_filterbank_set(msec,ms.over_attack,1);
return multicompand_filter_set(msec,&ms.over_attack,1);
}
int multicompand_over_decay_set(float msec){
return multicompand_filterbank_set(msec,ms.over_decay,0);
return multicompand_filter_set(msec,&ms.over_decay,0);
}
int multicompand_under_attack_set(float msec){
return multicompand_filterbank_set(msec,ms.under_attack,1);
return multicompand_filter_set(msec,&ms.under_attack,1);
}
int multicompand_under_decay_set(float msec){
return multicompand_filterbank_set(msec,ms.under_decay,0);
return multicompand_filter_set(msec,&ms.under_decay,0);
}
int multicompand_base_attack_set(float msec){
return multicompand_filterbank_set(msec,ms.base_attack,1);
return multicompand_filter_set(msec,&ms.base_attack,1);
}
int multicompand_base_decay_set(float msec){
return multicompand_filterbank_set(msec,ms.base_decay,0);
return multicompand_filter_set(msec,&ms.base_decay,0);
}
static void prepare_rms(float *rms, float *xx, int n, int ahead){
......@@ -192,8 +229,8 @@ static void prepare_peak(float *peak, float *x, int n, int ahead,int hold,
reset if the lookahead is exceptionally long */
if(loc==0 && val==0){
for(ii=0;ii<ahead;ii++)
if(fabs(x[ii])>val){
val=fabs(x[ii]);
if((x[ii]*x[ii])>val){
val=(x[ii]*x[ii]);
loc=ii+hold;
}
}
......@@ -201,18 +238,18 @@ static void prepare_peak(float *peak, float *x, int n, int ahead,int hold,
if(val>peak[0])peak[0]=val;
for(ii=1;ii<n;ii++){
if(fabs(x[ii+ahead])>val){
val=fabs(x[ii+ahead]);
if((x[ii+ahead]*x[ii+ahead])>val){
val=(x[ii+ahead]*x[ii+ahead]);
loc=ii+ahead+hold;
}
if(ii>=loc){
/* backfill */
val=0;
for(jj=ii+ahead-1;jj>=ii;jj--){
if(fabs(x[jj])>val)val=fabs(x[jj]);
if((x[jj]*x[jj])>val)val=(x[jj]*x[jj]);
if(jj<n && val>peak[jj])peak[jj]=val;
}
val=fabs(x[ii+ahead-1]);
val=(x[ii+ahead-1]*x[ii+ahead-1]);
loc=ii+ahead+hold;
}
if(val>peak[ii])peak[ii]=val;
......@@ -223,25 +260,11 @@ static void prepare_peak(float *peak, float *x, int n, int ahead,int hold,
}
static void run_filter_only(float *dB,int n,int mode,
iir_state *iir,iir_filter *attack,iir_filter *decay){
int i;
compute_iir2(dB, n, iir, attack, decay);
if(mode==0)
for(i=0;i<n;i++)
dB[i]=todB_a(dB+i)*.5f;
else
for(i=0;i<n;i++)
dB[i]=todB_a(dB+i);
}
static void run_filter(float *dB,float *x,int n,
float lookahead,int mode,
iir_state *iir,iir_filter *attack,iir_filter *decay,
peak_state *ps){
int i;
memset(dB,0,sizeof(*dB)*n);
if(mode)
......@@ -252,8 +275,11 @@ static void run_filter(float *dB,float *x,int n,
else
prepare_rms(dB, x, n, impulse_ahead2(attack->alpha)*lookahead);
compute_iir2(dB, n, iir, attack, decay);
run_filter_only(dB,n,mode,iir,attack,decay);
for(i=0;i<n;i++)
dB[i]=todB_a(dB+i)*.5f;
}
static float soft_knee(float x){
......@@ -267,16 +293,16 @@ static float hard_knee(float x){
static void over_compand(float *lx,float zerocorner,
iir_filter *attack, iir_filter *decay,
iir_state *iir, peak_state *ps,
float *peakfeed, float *rmsfeed,float *adj,int active){
float *adj){
int k;
float overdB[input_size];
float lookahead=c.over_lookahead/1000.;
int mode=c.over_mode;
float corner_multiplier=(1.-1./(c.over_ratio/1000.));
run_filter(overdB,lx,input_size,lookahead,mode,iir,attack, decay,ps);
run_filter(overdB,lx,input_size,lookahead,mode,iir,attack,decay,ps);
if(active){
if(adj){
float corner_multiplier=(1.-1./(c.over_ratio*.001));
if(c.over_softknee){
for(k=0;k<input_size;k++)
adj[k]+=soft_knee(overdB[k]-zerocorner)*corner_multiplier;
......@@ -285,126 +311,206 @@ static void over_compand(float *lx,float zerocorner,
adj[k]+=hard_knee(overdB[k]-zerocorner)*corner_multiplier;
}
}
{
/* determine rms and peak for feedback */
float max=-1.;
int maxpos=-1;
float rms=0.;
for(k=0;k<input_size;k++){
float val=lx[k]*lx[k];
if(val>max){
max=val;
maxpos=k;
}
rms+=val;
}
*peakfeed=todB(max)*.5+adj[maxpos];
*rmsfeed=todB(rms/input_size)*.5+adj[maxpos];
}
}
static void base_compand(float *x,
iir_filter *attack, iir_filter *decay,
iir_state *iir, peak_state *ps,
float *adj,int active){
float *adj){
int k;
float basedB[input_size];
int mode=c.base_mode;
float base_multiplier=(1.-1./(c.base_ratio/1000.));
run_filter(basedB,x,input_size,1.,mode,
iir,attack,decay,ps);
if(active)
if(adj){
float base_multiplier=(1.-1./(c.base_ratio*.001));
for(k=0;k<input_size;k++)
adj[k]-=(basedB[k]+adj[k])*base_multiplier;
}
}
static void under_compand(float *x,float zerocorner,
iir_filter *attack, iir_filter *decay,
iir_state *iir, peak_state *ps,
float *adj,int active){
float *adj){
int k;
float underdB[input_size];
float lookahead=c.under_lookahead/1000.;
int mode=c.under_mode;
float corner_multiplier=(1.-1./(c.under_ratio/1000.));
run_filter(underdB,x,input_size,lookahead,mode,
iir,attack,decay,ps);
if(active){
if(adj){
float corner_multiplier=(1./(c.under_ratio*.001)-1.);
if(c.under_softknee){
for(k=0;k<input_size;k++)
adj[k]-=soft_knee(zerocorner-underdB[k])*corner_multiplier;
adj[k]=soft_knee(zerocorner-underdB[k])*corner_multiplier;
}else{
for(k=0;k<input_size;k++)
adj[k]-=hard_knee(zerocorner-underdB[k])*corner_multiplier;