Commit 563f94fa authored by Monty Montgomery's avatar Monty Montgomery

Implement mute-button infrastructure tie-in

Implement muted channel support/passthrough in declipper

Signal path 'cleanup' in declipper; eliminate any clicks/thumps
  during realtime parameter adjustment

Remaining: realtime burst-CPU demand elimination in FFTW blocksize changes



git-svn-id: https://svn.xiph.org/trunk/postfish@6531 0101bb08-14d6-0310-b084-bc0e0c8e3800
parent 6055550f
......@@ -15,12 +15,12 @@ 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
limit.c limitpanel.c mute.c mutedummy.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
limit.o limitpanel.o mute.o mutedummy.o
GCF = `pkg-config --cflags gtk+-2.0` -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED
all:
......
......@@ -326,20 +326,22 @@ void clippanel_create(postfish_mainpanel *mp,
}
void clippanel_feedback(int displayit){
int clip[input_ch],count;
int clip[input_ch],count[input_ch];
float peak[input_ch];
if(pull_declip_feedback(clip,peak,&count)){
if(pull_declip_feedback(clip,peak,count)){
int i;
for(i=0;i<input_ch;i++){
float val[2],zero[2];
val[0]=-1.,zero[0]=-1.;
val[1]=(count?clip[i]*100./count-.1:-1);
val[1]=(count[i]?clip[i]*100./count[i]-.1:-1);
zero[1]=-1.;
multibar_set(MULTIBAR(feedback_bars[i]),zero,val,2,
(displayit && declip_visible));
val[0]=(count?peak[i]:-1);
val[0]=peak[i];
multibar_set(MULTIBAR(trigger_bars[i]),zero,val,1,
(displayit && declip_visible));
......
......@@ -43,8 +43,9 @@ static int lopad=0,hipad=0;
static u_int32_t *widthlookup=0;
static float *window=0;
static float width=.5;
static float **lap=0;
static float **lap;
static float **cache;
static u_int32_t cache_active;
static int cache_samples;
static int fillstate=0; /* 0: uninitialized
1: normal
......@@ -53,21 +54,44 @@ static time_linkage out;
/* accessed across threads */
sig_atomic_t *declip_active;
int *declip_prev_active;
sig_atomic_t declip_visible=0;
sig_atomic_t declip_converge=2; /* 0=over, 1=full, 2=half, 3=partial, 4=approx */
static float *chtrigger=0;
static sig_atomic_t pending_blocksize=0;
static float convergence=0.;
static float iterations=0.;
#include <stdio.h>
static void _analysis(char *base,int i,float *v,int n,int dB,int offset){
int j;
FILE *of;
char buffer[80];
sprintf(buffer,"%s_%d.m",base,i);
of=fopen(buffer,"a");
if(!of)perror("failed to open data dump file");
for(j=0;j<n;j++){
fprintf(of,"%f ",(float)j+offset);
if(dB)
fprintf(of,"%f\n",todB(v[j]));
else
fprintf(of,"%f\n",(v[j]));
}
fprintf(of,"\n");
fclose(of);
}
/* feedback! */
typedef struct declip_feedback{
feedback_generic parent_class;
float *peak;
int *clipcount;
int total;
int *clipcount;
int *total;
} declip_feedback;
static feedback_generic_pool feedpool;
......@@ -76,16 +100,17 @@ static feedback_generic *new_declip_feedback(void){
declip_feedback *ret=malloc(sizeof(*ret));
ret->clipcount=malloc((input_ch)*sizeof(*ret->clipcount));
ret->peak=malloc((input_ch)*sizeof(*ret->peak));
ret->total=malloc((input_ch)*sizeof(*ret->total));
return (feedback_generic *)ret;
}
static void push_declip_feedback(int *clip,float *peak,int total){
static void push_declip_feedback(int *clip,float *peak,int *total){
int n=input_ch;
declip_feedback *f=(declip_feedback *)
feedback_new(&feedpool,new_declip_feedback);
memcpy(f->clipcount,clip,n*sizeof(*clip));
memcpy(f->peak,peak,n*sizeof(*peak));
f->total=total;
memcpy(f->total,total,n*sizeof(*total));
feedback_push(&feedpool,(feedback_generic *)f);
}
......@@ -96,16 +121,59 @@ int pull_declip_feedback(int *clip,float *peak,int *total){
if(clip)memcpy(clip,f->clipcount,sizeof(*clip)*input_ch);
if(peak)memcpy(peak,f->peak,sizeof(*peak)*input_ch);
if(total)*total=f->total;
if(total)memcpy(total,f->total,sizeof(*total)*input_ch);
feedback_old(&feedpool,(feedback_generic *)f);
return 1;
}
static void setup_window(int left,int right){
int max=(left<right?right:left);
int i,j;
for(i=0;i<max-left;i++)
window[i]=0;
for(j=0;j<left;i++,j++)
window[i]=sin( M_PIl*j/(left*2) );
for(j=right;j<right*2;i++,j++)
window[i]=sin( M_PIl*j/(right*2) );
for(;i<max*2;i++)
window[i]=0;
for(i=0;i<max*2;i++) window[i]*=window[i];
for(i=0;i<max*2;i++) window[i]=sin(window[i]*M_PIl*.5);
}
static void setup_blocksize(int newblocksize){
int i;
if(blocksize)fftwf_destroy_plan(fftwf_weight);
blocksize=newblocksize;
fftwf_weight=fftwf_plan_dft_r2c_1d(blocksize*2,
work,
(fftwf_complex *)freq,
FFTW_MEASURE);
lopad=1-rint(fromBark(toBark(0.)-width)*blocksize*2/input_rate);
hipad=rint(fromBark(toBark(input_rate*.5)+width)*blocksize*2/input_rate)+lopad;
for(i=0;i<blocksize;i++){
float bark=toBark(input_rate*i/(blocksize*2));
int hi=rint(fromBark(bark-width)*(blocksize*2)/input_rate)-1+lopad;
int lo=rint(fromBark(bark+width)*(blocksize*2)/input_rate)+1+lopad;
widthlookup[i]=(hi<<16)+lo;
}
reconstruct_reinit(blocksize*2);
}
/* called only by initial setup */
int declip_load(void){
int i;
declip_active=calloc(input_ch,sizeof(*declip_active));
declip_prev_active=calloc(input_ch,sizeof(*declip_prev_active));
chtrigger=malloc(input_ch*sizeof(*chtrigger));
for(i=0;i<input_ch;i++)
chtrigger[i]=1.;
......@@ -121,10 +189,24 @@ int declip_load(void){
cache=malloc(input_ch*sizeof(*cache));
for(i=0;i<input_ch;i++)
cache[i]=malloc(input_size*sizeof(**cache));
lap=malloc(input_ch*sizeof(*lap));
for(i=0;i<input_ch;i++)
lap[i]=malloc(input_size*sizeof(**lap));
window=malloc(input_size*2*sizeof(window));
{
/* alloc for largest possible blocksize */
int blocksize=input_size*2;
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));
}
pending_blocksize=input_size*2;
return(0);
}
......@@ -203,16 +285,13 @@ static void sliding_bark_average(float *f,int n,float width){
}
/* work,freq are passed through the static buffer fftwf requires */
static void declip(float *lap,float *out,
int blocksize,float trigger,
static void declip(int blocksize,float trigger,
float epsilon, float iteration,
int *runningtotal, int *runningcount,float *peak,
int active){
int *runningtotal, int *runningcount){
float flag[blocksize*2];
int iterbound,i,j,count=0;
int iterbound,i,count=0;
for(i=blocksize/2;i<blocksize*3/2;i++){
if(fabs(work[i])>*peak)*peak=fabs(work[i]);
flag[i]=0.;
if(work[i]>=trigger || work[i]<=-trigger){
flag[i]=1.;
......@@ -223,51 +302,35 @@ static void declip(float *lap,float *out,
*runningtotal+=blocksize;
*runningcount+=count;
if(active){
if(count){
for(i=0;i<blocksize/2;i++)flag[i]=0.;
for(i=blocksize*3/2;i<blocksize*2;i++)flag[i]=0.;
for(i=0;i<blocksize/2;i++)work[i]=0.;
for(i=0;i<blocksize;i++)work[i+blocksize/2]*=window[i];
for(i=blocksize*3/2;i<blocksize*2;i++)work[i]=0.;
fftwf_execute(fftwf_weight);
sliding_bark_average(freq,blocksize*2,width);
iterbound=blocksize*iteration;
if(iterbound<10)iterbound=10;
if(count)reconstruct(work,freq,flag,epsilon,iterbound);
if(out)
for(i=0;i<blocksize/2;i++)
out[i]=lap[i]+work[i+blocksize/2]*window[i];
for(i=blocksize/2,j=0;i<blocksize;i++)
lap[j++]=work[i+blocksize/2]*window[i];
}else{
if(out)
for(i=0;i<blocksize/2;i++)
out[i]=work[i+blocksize/2];
for(i=blocksize/2,j=0;i<blocksize;i++)
lap[j++]=work[i+blocksize/2]*window[i]*window[i];
}
for(i=blocksize/2;i<input_size;i++)
lap[i]=0.;
reconstruct(work,freq,flag,epsilon,iterbound);
for(i=0;i<blocksize;i++)work[i+blocksize/2]*=window[i];
}else
for(i=0;i<blocksize;i++)work[i+blocksize/2]*=window[i]*window[i];
}
/* called only by playback thread */
static int offset=0;
time_linkage *declip_read(time_linkage *in){
int i;
int i,j,k;
float local_trigger[input_ch];
int total=0;
int count[input_ch];
int total[input_ch];
float peak[input_ch];
time_linkage dummy;
u_int32_t active=0;
int next_blocksize=pending_blocksize;
int orig_blocksize;
float local_convergence;
float local_iterations;
......@@ -280,98 +343,299 @@ time_linkage *declip_read(time_linkage *in){
memset(count,0,sizeof(count));
memset(peak,0,sizeof(peak));
memset(total,0,sizeof(total));
if(pending_blocksize!=blocksize){
if(blocksize){
free(widthlookup);
free(window);
fftwf_destroy_plan(fftwf_weight);
fftwf_free(freq);
fftwf_free(work);
}
blocksize=pending_blocksize;
switch(fillstate){
case 0: /* prime the lapping and cache */
freq=fftwf_malloc((blocksize*2+2)*sizeof(freq));
work=fftwf_malloc((blocksize*2)*sizeof(freq));
fftwf_weight=fftwf_plan_dft_r2c_1d(blocksize*2,
work,
(fftwf_complex *)freq,
FFTW_MEASURE);
lopad=1-rint(fromBark(toBark(0.)-width)*blocksize*2/input_rate);
hipad=rint(fromBark(toBark(input_rate*.5)+width)*blocksize*2/input_rate)+lopad;
widthlookup=malloc((hipad+1)*sizeof(*widthlookup));
for(i=0;i<blocksize;i++){
float bark=toBark(input_rate*i/(blocksize*2));
int hi=rint(fromBark(bark-width)*(blocksize*2)/input_rate)-1+lopad;
int lo=rint(fromBark(bark+width)*(blocksize*2)/input_rate)+1+lopad;
widthlookup[i]=(hi<<16)+lo;
/* set up for the blocksize we're actually using for now */
{
setup_blocksize(next_blocksize);
setup_window(blocksize/2,blocksize/2);
}
window=malloc(blocksize*sizeof(*window));
for(i=0;i<blocksize;i++) window[i]=sin( M_PIl*i/blocksize );
for(i=0;i<blocksize;i++) window[i]*=window[i];
for(i=0;i<blocksize;i++) window[i]=sin(window[i]*M_PIl*.5);
reconstruct_reinit(blocksize*2);
}
switch(fillstate){
case 0: /* prime the lapping and cache */
for(i=0;i<input_ch;i++){
float *temp=in->data[i];
total=0;
memset(work+blocksize/2,0,sizeof(*work)*blocksize/2);
memcpy(work+blocksize,temp,sizeof(*work)*blocksize/2);
declip(lap[i],0,blocksize,
local_trigger[i],local_convergence,local_iterations,
&total,count+i,peak+i,declip_active[i]);
memset(cache[i],0,sizeof(**cache)*input_size);
in->data[i]=cache[i];
cache[i]=temp;
int channel_active=declip_active[i];
declip_prev_active[i]=channel_active;
/* peak feedback */
if(declip_visible){
float *l=in->data[i];
for(j=0;j<in->samples;j++)
if(fabs(l[j])>peak[i])peak[i]=fabs(l[j]);
}
if(channel_active){
/* fill work with the block spanning cache/in (first 1/4, last 1/4 are zeroed) */
memset(work,0,sizeof(*work)*blocksize);
memcpy(work+blocksize,in->data[i],sizeof(*work)*blocksize/2);
memset(work+blocksize+blocksize/2,0,sizeof(*work)*blocksize/2);
declip(blocksize,local_trigger[i],local_convergence,local_iterations,
total+i,count+i);
/* second half of work goes to lap */
memcpy(lap[i],work+blocksize,sizeof(*work)*blocksize/2);
/* now iterate the pieces purely within in */
for(j=0;j+blocksize<=in->size;j+=blocksize/2){
memset(work,0,sizeof(*work)*blocksize);
memcpy(work+blocksize/2,in->data[i]+j,sizeof(*work)*blocksize);
memset(work+blocksize+blocksize/2,0,sizeof(*work)*blocksize/2);
declip(blocksize,local_trigger[i],local_convergence,local_iterations,
total+i,count+i);
/* second half of work goes to lap */
{
float *llap=lap[i]+j;
float *lwork=work+blocksize/2;
for(k=0;k<blocksize/2;k++)
llap[k]+=lwork[k];
memcpy(llap+k,lwork+k,sizeof(*work)*blocksize/2);
}
}
}else{
/* no declipping to do, so direct cache/lap buffer rotation */
float *temp=cache[i];
cache[i]=in->data[i];
in->data[i]=temp;
memset(temp,0,sizeof(*temp)*input_size);
}
}
cache_samples=in->samples;
cache_active=in->active;
fillstate=1;
out.samples=0;
if(in->samples==in->size)goto tidy_up;
if(in->samples==in->size)break;
for(i=0;i<input_ch;i++)
memset(in->data[i],0,sizeof(**in->data)*in->size);
in->samples=0;
/* fall through */
case 1: /* nominal processing */
orig_blocksize=blocksize;
/* the 'gap' transition and finishing off the output block is done
first as it may need to handle a blocksize transition (and a
temporary transition window */
if(next_blocksize != orig_blocksize){
if(next_blocksize > orig_blocksize) setup_blocksize(next_blocksize);
setup_window(orig_blocksize/2,next_blocksize/2);
}
/* the gap piece is also special in that it may need to deal with
a transition to/from mute and/or a transition to/from bypass */
for(i=0;i<input_ch;i++){
float *temp=cache[i];
int j;
total=0;
for(j=0;j+blocksize<=out.size;j+=blocksize/2){
memcpy(work+blocksize/2,temp+j,sizeof(*work)*blocksize);
declip(lap[i],out.data[i]+j,blocksize,
local_trigger[i],local_convergence,local_iterations,
&total,count+i,peak+i,declip_active[i]);
int channel_active=declip_active[i];
/* peak feedback */
if(declip_visible){
float *l=in->data[i];
for(j=0;j<in->samples;j++)
if(fabs(l[j])>peak[i])peak[i]=fabs(l[j]);
}
memcpy(work+blocksize/2,temp+j,sizeof(*work)*blocksize/2);
memcpy(work+blocksize,in->data[i],sizeof(*work)*blocksize/2);
declip(lap[i],out.data[i]+j,blocksize,
local_trigger[i],local_convergence,local_iterations,
&total,count+i,peak+i,declip_active[i]);
cache[i]=in->data[i];
in->data[i]=temp;
if( mute_channel_muted(in->active,i) &&
mute_channel_muted(cache_active,i)){
/* Cache: Muted=True , Bypass=X
Input: Muted=True , Bypass=X */
/* we may need cache for a later transition, so keep it up to date */
float *temp=cache[i];
cache[i]=in->data[i];
in->data[i]=temp;
}else{
if(mute_channel_muted(cache_active,i)){
if(channel_active){
/* Cache: Muted=True , Bypass=X
Input: Muted=False, Bypass=False */
/* rotate cache */
float *temp=cache[i];
cache[i]=in->data[i];
in->data[i]=temp;
/* zero the lap */
memset(lap[i],0,sizeof(*lap[i])*blocksize/2);
}else{
/* Cache: Muted=True , Bypass=X
Input: Muted=False, Bypass=True */
/* silence->bypass; transition must happen in the current outblock */
active|=(1<<i); /* audible output in out.data[i] */
memset(out.data[i],0,sizeof(*out.data[i])*input_size);
for(j=input_size-blocksize/2,k=0;j<input_size;j++,k++)
out.data[i][j]=cache[i][j]*window[k]*window[k];
float *temp=cache[i];
cache[i]=in->data[i];
in->data[i]=temp;
}
}else{
active|=(1<<i); /* audible output in out.data[i] */
if(mute_channel_muted(in->active,i)){
if(declip_prev_active[i]){
/* Cache: Muted=False, Bypass=False
Input: Muted=True, Bypass=X */
/* transition to mute, so lap is finished output. Rotate all */
float *temp=cache[i];
cache[i]=in->data[i];
in->data[i]=temp;
temp=out.data[i];
out.data[i]=lap[i];
lap[i]=temp;
}else{
/* Cache: Muted=False, Bypass=True
Input: Muted=True, Bypass=X */
/* rotate in/cache/out, transition out */
float *temp=out.data[i];
out.data[i]=cache[i];
cache[i]=in->data[i];
in->data[i]=temp;
for(j=input_size-blocksize/2,k=0;j<input_size;j++,k++){
float w=(1.-window[k]);
out.data[i][j]*=w*w;
}
}
}else{
if(!declip_prev_active[i]){
if(!channel_active){
/* Cache: Muted=False, Bypass=True
Input: Muted=False, Bypass=True */
/* all bypass! rotate in/cache/out */
float *temp=out.data[i];
out.data[i]=cache[i];
cache[i]=in->data[i];
in->data[i]=temp;
}else{
/* Cache: Muted=False, Bypass=True
Input: Muted=False, Bypass=False */
/* transition the lap */
for(j=0,k=blocksize/2;j<blocksize/2;j++,k++)
lap[i][j]=in->data[i][j]*window[k]*window[k];
/* all rotate in/cache/out */
float *temp=out.data[i];
out.data[i]=cache[i];
cache[i]=in->data[i];
in->data[i]=temp;
}
}else{
if(!channel_active){
/* Cache: Muted=False, Bypass=False
Input: Muted=False, Bypass=True */
/* finish off lap, then rotate all */
for(j=input_size-blocksize/2,k=0;j<input_size;j++,k++)
lap[i][j]+=cache[i][j]*window[k]*window[k];
float *temp=cache[i];
cache[i]=in->data[i];
in->data[i]=temp;
temp=out.data[i];
out.data[i]=lap[i];
lap[i]=temp;
}else{
/* Cache: Muted=False, Bypass=False
Input: Muted=False, Bypass=False */
/* nominal case; the only one involving declipping the gap */
memset(work,0,sizeof(*work)*blocksize/2);
memcpy(work+blocksize/2,cache[i]+input_size-blocksize/2,sizeof(*work)*blocksize/2);
memcpy(work+blocksize,in->data[i],sizeof(*work)*blocksize/2);
memset(work+blocksize+blocksize/2,0,sizeof(*work)*blocksize/2);
declip(blocksize,local_trigger[i],local_convergence,local_iterations,
total+i,count+i);
/* finish lap from last frame */
{
float *llap=lap[i]+input_size-blocksize/2;
float *lwork=work+blocksize/2;
for(j=0;j<blocksize/2;j++)
llap[j]+=lwork[j];
}
/* rotate buffers */
float *temp=out.data[i];
out.data[i]=lap[i];
lap[i]=temp;
temp=in->data[i];
in->data[i]=cache[i];
cache[i]=temp;
/* begin lap for this frame */
memcpy(lap[i],work+blocksize,sizeof(*work)*blocksize/2);
}
}
}
}
}
declip_prev_active[i]=channel_active;
}
/* also rotate metadata */