Commit 0b169a93 authored by Monty Montgomery's avatar Monty Montgomery

Basic declipper functionality and UI in place.

Monty


git-svn-id: https://svn.xiph.org/trunk/postfish@5716 0101bb08-14d6-0310-b084-bc0e0c8e3800
parent d091181a
......@@ -4,6 +4,11 @@
CC=gcc
LD=gcc
INSTALL=install
PREFIX=/usr/local
BINDIR=$PREFIX/bin
ETCDIR=/etc
MANDIR=$PREFIX/man
SRC = main.c mainpanel.c multibar.c readout.c input.c output.c clippanel.c declip.c \
reconstruct.c smallft.c windowbutton.c subpanel.c feedback.c
......@@ -32,3 +37,11 @@ target: $(OBJ)
./touch-version
$(LD) $(OBJ) $(CFLAGS) -o postfish `pkg-config --libs gtk+-2.0` -lpthread -lm
install:
$(INSTALL) -d -m 0755 $(BINDIR)
$(INSTALL) -m 0755 postfish $(BINDIR)
$(INSTALL) -d -m 0755 $(ETCDIR)
$(INSTALL) -m 0644 postfish-gtkrc $(ETCDIR)
# $(INSTALL) -d -m 0755 $(MANDIR)
# $(INSTALL) -d -m 0755 $(MANDIR)/man1
# $(INSTALL) -m 0644 postfish.1 $(MANDIR)/man1
......@@ -44,6 +44,8 @@ GtkWidget *hzreadout;
GtkWidget *creadout;
GtkWidget *ireadout;
GtkWidget *mainpanel_inbar;
typedef struct {
GtkWidget *slider;
GtkWidget *readout;
......@@ -87,7 +89,7 @@ static void converge_slider_change(GtkWidget *w,gpointer in){
char buffer[80];
double percent=gtk_range_get_value(GTK_RANGE(w));
double sigfigs=percent*.05+2.8;
double epsilon=pow(1.,-sigfigs);
double epsilon=pow(10.,-sigfigs);
sprintf(buffer,"%3.1f",sigfigs);
readout_set(READOUT(creadout),buffer);
......@@ -96,15 +98,15 @@ static void converge_slider_change(GtkWidget *w,gpointer in){
readout_set(READOUT(ireadout),buffer);
declip_setconvergence(epsilon);
declip_setiterations(percent);
declip_setiterations(percent*.01);
}
void clippanel_create(postfish_mainpanel *mp,
GtkWidget *windowbutton,
GtkWidget *activebutton){
int i;
char *labels[3]={"1%","10%","100%"};
double levels[4]={0.,1.,10.,100.};
char *labels[2]={"10%","100%"};
double levels[3]={0.,10.,100.};
int block_choices=0;
subpanel_generic *panel=subpanel_create(mp,windowbutton,activebutton,
......@@ -113,7 +115,7 @@ void clippanel_create(postfish_mainpanel *mp,
GtkWidget *framebox=gtk_hbox_new(1,0);
GtkWidget *blocksize_box=gtk_vbox_new(0,0);
GtkWidget *blocksize_frame=gtk_frame_new (" filter width / approx. lowest response ");
GtkWidget *blocksize_frame=gtk_frame_new (" filter width ");
GtkWidget *converge_frame=gtk_frame_new (" filter convergence ");
GtkWidget *converge_box=gtk_vbox_new(0,0);
GtkWidget *channel_table=gtk_table_new(input_ch,4,0);
......@@ -135,7 +137,7 @@ void clippanel_create(postfish_mainpanel *mp,
GtkWidget *slider=gtk_hscale_new_with_range(0,block_choices-1,1);
GtkWidget *samplelabel=gtk_label_new("window sample width");
GtkWidget *mslabel=gtk_label_new("window time width");
GtkWidget *hzlabel=gtk_label_new("approx. lowest response");
GtkWidget *hzlabel=gtk_label_new("approximate lowest response");
samplereadout=readout_new("00000 ");
msreadout=readout_new("00000 ms");
hzreadout=readout_new("00000 Hz");
......@@ -175,8 +177,8 @@ void clippanel_create(postfish_mainpanel *mp,
GtkWidget *fastlabel=gtk_label_new("fastest");
GtkWidget *qualitylabel=gtk_label_new("best");
GtkWidget *slider=gtk_hscale_new_with_range(10,200,1);
GtkWidget *clabel=gtk_label_new("significant figure target");
GtkWidget *ilabel=gtk_label_new("iteration bound");
GtkWidget *clabel=gtk_label_new("significant figures target");
GtkWidget *ilabel=gtk_label_new("limit predicted iterations");
creadout=readout_new("000 ");
ireadout=readout_new("000%");
......@@ -217,7 +219,7 @@ void clippanel_create(postfish_mainpanel *mp,
GtkWidget *readout=readout_new("0.00");
GtkWidget *readoutdB=readout_new("-40 dB");
GtkWidget *barframe=gtk_frame_new(NULL);
GtkWidget *bar=multibar_new(3,labels,levels,0);
GtkWidget *bar=multibar_new(2,labels,levels,HI_DECAY|ZERO_DAMP);
cs->slider=slider;
cs->readout=readout;
......@@ -266,7 +268,9 @@ void clippanel_create(postfish_mainpanel *mp,
trigger_slider_change(NULL,cs);
}
mainpanel_inbar=mp->inbar;
}
void clippanel_feedback(void){
......@@ -274,8 +278,15 @@ void clippanel_feedback(void){
if(pull_declip_feedback(clip,&count)){
int i;
for(i=0;i<input_ch;i++){
double val=clip[i]*100./count,zero=0;
multibar_set(MULTIBAR(feedback_bars[i]),&zero,&val,1);
double val[2],zero[2];
val[0]=-1.,zero[0]=-1.;
val[1]=(count?clip[i]*100./count-.1:-1);
zero[1]=-1.;
multibar_set(MULTIBAR(feedback_bars[i]),zero,val,2);
if(clip[i]){
multibar_setwarn(MULTIBAR(mainpanel_inbar));
multibar_setwarn(MULTIBAR(feedback_bars[i]));
}
}
}
}
......
......@@ -27,43 +27,11 @@
#include "smallft.h"
#include "reconstruct.h"
#include "feedback.h"
#include <stdio.h>
extern int input_rate;
extern int input_ch;
extern int input_size;
void _analysis(char *base,int i,double *v,int n,int bark,int dB){
int j;
FILE *of;
char buffer[80];
sprintf(buffer,"%s_%d.m",base,i);
of=fopen(buffer,"w");
if(!of)perror("failed to open data dump file");
for(j=0;j<n;j++){
if(bark){
float b=toBark((4000.f*j/n)+.25);
fprintf(of,"%f ",b);
}else
fprintf(of,"%f ",(double)j);
if(dB){
if(j==0||j==n-1)
fprintf(of,"%f\n",todB(v[j]));
else{
fprintf(of,"%f\n",todB(hypot(v[j],v[j+1])));
j++;
}
}else{
fprintf(of,"%f\n",v[j]);
}
}
fclose(of);
}
/* accessed only in playback thread/setup */
static drft_lookup fft;
static int blocksize=0;
......@@ -258,11 +226,11 @@ static void declip(double *data,double *lap,double *out,
if(data[i]>=trigger || data[i]<=-trigger){
flag[i]=1;
count++;
*runningcount++;
}
}
*runningtotal+=blocksize*3/4;
*runningcount+=count;
if(declip_active){
......@@ -279,14 +247,14 @@ static void declip(double *data,double *lap,double *out,
}
if(iterbound<20)iterbound=20;
reconstruct(&fft,data,freq,flag,epsilon*count,iterbound,blocksize);
if(count)reconstruct(&fft,data,freq,flag,epsilon*count,iterbound,blocksize);
if(out)
for(i=0;i<blocksize/2;i++)
out[i]=lap[i]+data[i]*window[i];
for(i=blocksize/2,j=0;i<blocksize;i++)
lap[j]=data[i]*window[i];
lap[j++]=data[i]*window[i];
}else{
......@@ -295,15 +263,15 @@ static void declip(double *data,double *lap,double *out,
out[i]=data[i];
for(i=blocksize/2,j=0;i<blocksize;i++)
lap[j]=data[i]*window[i]*window[i];
lap[j++]=data[i]*window[i]*window[i];
}
for(i=blocksize/2;i<input_size;i++)
lap[i]=0.;
}
/* called only by playback thread */
time_linkage *declip_read(time_linkage *in){
int i;
double work[blocksize];
double local_trigger[input_ch];
int total=0;
int count[input_ch];
......@@ -328,83 +296,95 @@ time_linkage *declip_read(time_linkage *in){
}
blocksize=pending_blocksize;
widthlookup=malloc((blocksize>>1)*sizeof(*widthlookup));
lopad=1-rint(fromBark(toBark(0.)-width)*blocksize/input_rate);
hipad=rint(fromBark(toBark(input_rate*.5)+width)*blocksize/input_rate)+lopad;
widthlookup=malloc((hipad+1)*sizeof(*widthlookup));
for(i=0;i<blocksize/2;i++){
double bark=toBark(input_rate*i/blocksize);
int hi=rint(fromBark(bark-width)*blocksize/input_rate)-1+lopad;
int lo=rint(fromBark(bark+width)*blocksize/input_rate)+1+lopad;
if(hi<0 || lo<0 || hi>65535 || lo<65535) return 0;
widthlookup[i]=(hi<<16)+lo;
}
lopad=1-rint(fromBark(toBark(0.)-width)*blocksize/input_rate);
hipad=rint(fromBark(toBark(input_rate*.5)+width)*blocksize/input_rate)+lopad;
drft_init(&fft,blocksize);
window=malloc(blocksize*sizeof(*window));
for(i=0;i<blocksize/8;i++) window[i]=0.;
for(;i<blocksize*3/8;i++) window[i]=sin( (double)(i-blocksize/8)/blocksize*M_PIl );
for(;i<blocksize*3/8;i++) window[i]=sin( (double)(i-blocksize/8)/blocksize*M_PIl*2. );
for(;i<blocksize*5/8;i++) window[i]=1.;
for(;i<blocksize*7/8;i++) window[i]=sin( (double)(blocksize*7/8-i)/blocksize*M_PIl );
for(;i<blocksize*7/8;i++) window[i]=sin( (double)(blocksize*7/8-i)/blocksize*M_PIl*2. );
for(;i<blocksize;i++) window[i]=0.;
for(i=0;i<blocksize;i++) window[i]*=window[i];
for(i=0;i<blocksize;i++) window[i]=sin(window[i]*M_PIl);
for(i=0;i<blocksize;i++) window[i]=sin(window[i]*M_PIl*.5);
}
switch(fillstate){
case 0: /* prime the lapping and cache */
for(i=0;i<input_ch;i++){
int j;
double *temp=in->data[i];
total=0;
memset(work,0,sizeof(*work)*blocksize/2);
memcpy(work+blocksize/2,temp,sizeof(*work)*blocksize/2);
declip(work,lap[i],0,blocksize,
local_trigger[i],local_convergence,local_iterations,
&total,count+i);
memset(cache[i],0,sizeof(**cache)*input_size);
in->data[i]=cache[i];
cache[i]=temp;
}
cache_samples=in->samples;
fillstate=1;
if(in->samples==in->size)return 0;
in->samples=0;
/* fall through */
case 1: /* nominal processing */
for(i=0;i<input_ch;i++){
double *temp=cache[i];
int j;
total=0;
for(j=0;j+blocksize<out.size;j+=blocksize/2){
memcpy(work,temp+j,sizeof(*work)*blocksize);
{
double work[blocksize];
switch(fillstate){
case 0: /* prime the lapping and cache */
for(i=0;i<input_ch;i++){
int j;
double *temp=in->data[i];
total=0;
memset(work,0,sizeof(*work)*blocksize/2);
memcpy(work+blocksize/2,temp,sizeof(*work)*blocksize/2);
declip(work,lap[i],0,blocksize,
local_trigger[i],local_convergence,local_iterations,
&total,count+i);
memset(cache[i],0,sizeof(**cache)*input_size);
in->data[i]=cache[i];
cache[i]=temp;
}
cache_samples=in->samples;
fillstate=1;
out.samples=0;
if(in->samples==in->size)goto tidy_up;
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 */
for(i=0;i<input_ch;i++){
double *temp=cache[i];
int j;
total=0;
for(j=0;j+blocksize<=out.size;j+=blocksize/2){
memcpy(work,temp+j,sizeof(*work)*blocksize);
declip(work,lap[i],out.data[i]+j,blocksize,
local_trigger[i],local_convergence,local_iterations,
&total,count+i);
}
memcpy(work,temp+j,sizeof(*work)*blocksize/2);
memcpy(work+blocksize/2,in->data[i],sizeof(*work)*blocksize/2);
declip(work,lap[i],out.data[i]+j,blocksize,
local_trigger[i],local_convergence,local_iterations,
&total,count+i);
cache[i]=in->data[i];
in->data[i]=temp;
}
memcpy(work,temp+j,sizeof(*work)*blocksize/2);
memcpy(work+blocksize/2,in->data[i],sizeof(*work)*blocksize/2);
declip(work,lap[i],out.data[i]+j,blocksize,
local_trigger[i],local_convergence,local_iterations,
&total,count+i);
in->data[i]=cache[i];
cache[i]=temp;
out.samples=cache_samples;
cache_samples=in->samples;
if(out.samples<out.size)fillstate=2;
break;
case 2: /* we've pushed out EOF already */
out.samples=0;
}
out.samples=cache_samples;
cache_samples=in->samples;
if(out.samples<out.size)fillstate=2;
break;
case 2: /* we've pushed out EOF already */
return 0;
}
/* we're returning data, push feedback */
push_declip_feedback(count,total);
tidy_up:
{
int tozero=out.size-out.samples;
if(tozero)
for(i=0;i<out.channels;i++)
memset(out.data[i]+out.samples,0,sizeof(**out.data)*tozero);
}
return &out;
}
......@@ -439,14 +439,14 @@ time_linkage *input_read(void){
cursor>=current_file_entry->end &&
current_file_entry->end!=-1){
pthread_mutex_unlock(&master_mutex);
return &out; /* EOF */
goto tidy_up;
}
/* the streaming case */
if(feof(current_file_entry->f) &&
current_file_entry_number+1>=file_entries){
pthread_mutex_unlock(&master_mutex);
return &out;
goto tidy_up;
}
pthread_mutex_unlock(&master_mutex);
......@@ -550,6 +550,14 @@ time_linkage *input_read(void){
push_input_feedback(peak,rms,cursor);
tidy_up:
{
int tozero=out.size-out.samples;
if(tozero)
for(j=0;j<out.channels;j++)
memset(out.data[j]+out.samples,0,sizeof(**out.data)*tozero);
}
return &out;
}
......
......@@ -581,43 +581,6 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){
gtk_widget_set_name(panel->leftback,"winpanel");
/* left side of main panel */
//gtk_container_set_border_width (GTK_CONTAINER (panel->leftframe), 3);
gtk_container_set_border_width (GTK_CONTAINER (panel->wintable), 3);
gtk_frame_set_shadow_type(GTK_FRAME(panel->leftframe),GTK_SHADOW_ETCHED_IN);
gtk_container_add(GTK_CONTAINER(panel->leftframe),panel->wintable);
gtk_table_set_row_spacings(GTK_TABLE(panel->wintable),1);
{
GtkWidget *temp=gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(temp),"<span size=\"x-small\">visible</span>");
gtk_misc_set_alignment(GTK_MISC(temp),0,.5);
gtk_table_attach_defaults(GTK_TABLE(panel->wintable),temp,0,1,0,1);
temp=gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(temp),"<span size=\"x-small\">active</span>");
gtk_misc_set_alignment(GTK_MISC(temp),1,.5);
gtk_table_attach_defaults(GTK_TABLE(panel->wintable),temp,1,2,0,1);
}
mainpanel_panelentry(panel,"_Declip ","[d]",0,clippanel_create);
mainpanel_panelentry(panel,"Cross_Talk ","[t]",1,0);
mainpanel_panelentry(panel,"_Noise Filter ","[n]",2,0);
mainpanel_panelentry(panel,"_Equalizer ","[e]",3,0);
mainpanel_panelentry(panel,"_Compander ","[c]",4,0);
mainpanel_panelentry(panel,"_Limiter ","[l]",5,0);
mainpanel_panelentry(panel,"_Output Cal. ","[o]",6,0);
g_signal_connect (G_OBJECT (panel->toplevel), "delete_event",
G_CALLBACK (shutdown), NULL);
g_signal_connect (G_OBJECT (panel->toplevel), "delete_event",
G_CALLBACK (shutdown), NULL);
/* right side of main panel */
{
char *labels[12]={"-96","-72","-60","-48","-36","-24",
"-16","-8","-3","0","+3","+6"};
......@@ -844,6 +807,43 @@ void mainpanel_create(postfish_mainpanel *panel,char **chlabels){
}
/* right side of main panel */
//gtk_container_set_border_width (GTK_CONTAINER (panel->leftframe), 3);
gtk_container_set_border_width (GTK_CONTAINER (panel->wintable), 3);
gtk_frame_set_shadow_type(GTK_FRAME(panel->leftframe),GTK_SHADOW_ETCHED_IN);
gtk_container_add(GTK_CONTAINER(panel->leftframe),panel->wintable);
gtk_table_set_row_spacings(GTK_TABLE(panel->wintable),1);
{
GtkWidget *temp=gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(temp),"<span size=\"x-small\">visible</span>");
gtk_misc_set_alignment(GTK_MISC(temp),0,.5);
gtk_table_attach_defaults(GTK_TABLE(panel->wintable),temp,0,1,0,1);
temp=gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(temp),"<span size=\"x-small\">active</span>");
gtk_misc_set_alignment(GTK_MISC(temp),1,.5);
gtk_table_attach_defaults(GTK_TABLE(panel->wintable),temp,1,2,0,1);
}
mainpanel_panelentry(panel,"_Declip ","[d]",0,clippanel_create);
mainpanel_panelentry(panel,"Cross_Talk ","[t]",1,0);
mainpanel_panelentry(panel,"_Noise Filter ","[n]",2,0);
mainpanel_panelentry(panel,"_Equalizer ","[e]",3,0);
mainpanel_panelentry(panel,"_Compander ","[c]",4,0);
mainpanel_panelentry(panel,"_Limiter ","[l]",5,0);
mainpanel_panelentry(panel,"_Output Cal. ","[o]",6,0);
g_signal_connect (G_OBJECT (panel->toplevel), "delete_event",
G_CALLBACK (shutdown), NULL);
g_signal_connect (G_OBJECT (panel->toplevel), "delete_event",
G_CALLBACK (shutdown), NULL);
gtk_widget_show_all(panel->toplevel);
gtk_window_set_resizable(GTK_WINDOW(panel->toplevel),0);
......@@ -865,9 +865,11 @@ static gboolean feedback_process(postfish_mainpanel *panel){
int n=input_ch+2;
double *rms=alloca(sizeof(*rms)*(input_ch+2));
double *peak=alloca(sizeof(*peak)*(input_ch+2));
if(pull_input_feedback(peak,rms,&time_cursor)){
if(pull_output_feedback(peak,rms)){
char buffer[14];
int i;
for(i=0;i<n;i++){
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(panel->channelshow[i]))){
peak[i]=todB(peak[i]);
......@@ -876,15 +878,13 @@ static gboolean feedback_process(postfish_mainpanel *panel){
peak[i]=-400;
rms[i]=-400;
}
if(i<input_ch && peak[i]>=0.)multibar_setwarn(MULTIBAR(panel->outbar));
}
multibar_set(MULTIBAR(panel->inbar),rms,peak,n);
input_cursor_to_time(time_cursor,buffer);
readout_set(READOUT(panel->cue),buffer);
clippanel_feedback();
multibar_set(MULTIBAR(panel->outbar),rms,peak,n);
if(pull_output_feedback(peak,rms)){
if(pull_input_feedback(peak,rms,&time_cursor)){
for(i=0;i<n;i++){
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(panel->channelshow[i]))){
peak[i]=todB(peak[i]);
......@@ -895,13 +895,16 @@ static gboolean feedback_process(postfish_mainpanel *panel){
}
}
multibar_set(MULTIBAR(panel->outbar),rms,peak,n);
multibar_set(MULTIBAR(panel->inbar),rms,peak,n);
input_cursor_to_time(time_cursor,buffer);
readout_set(READOUT(panel->cue),buffer);
}
clippanel_feedback();
}
}
}
static gboolean async_event_handle(GIOChannel *channel,
......@@ -933,6 +936,8 @@ void mainpanel_go(int argc,char *argv[], int ch){
strcat(homerc,rcfile);
gtk_rc_add_default_file(homerc);
}
gtk_rc_add_default_file(".postfish-gtkrc");
gtk_rc_add_default_file("postfish-gtkrc");
gtk_init (&argc, &argv);
memset(labels,0,sizeof(labels));
......
This diff is collapsed.
......@@ -31,6 +31,7 @@ typedef struct bartack {
#define LO_ATTACK (1<<1)
#define HI_DECAY (1<<2)
#define LO_DECAY (1<<3)
#define ZERO_DAMP (1<<4)
struct _Multibar{
......@@ -65,6 +66,7 @@ GtkWidget* multibar_new (int n, char **labels, double *levels,
int flags);
void multibar_clear (Multibar *m);
void multibar_set (Multibar *m,double *lo,double *hi, int n);
void multibar_setwarn (Multibar *m);
void multibar_reset (Multibar *m);
G_END_DECLS
......
......@@ -124,7 +124,7 @@ static int isachr(FILE *f){
return 0;
}
static FILE *playback_startup(int outfileno, int ch, int r){
static FILE *playback_startup(int outfileno, int ch, int r, int *bep){
FILE *playback_fd=NULL;
int format=AFMT_S16_NE;
int rate=r,channels=ch,ret;
......@@ -168,6 +168,7 @@ static FILE *playback_startup(int outfileno, int ch, int r){
}
}else{
WriteWav(playback_fd,ch,r,16,-1);
*bep=0;
}
return playback_fd;
......@@ -180,7 +181,8 @@ void *playback_thread(void *dummy){
int bigendianp=(AFMT_S16_NE==AFMT_S16_BE?1:0);
FILE *playback_fd=NULL;
int setupp=0;
time_linkage *ret;
time_linkage *link;
int result;
off_t count=0;
long last=-1;
......@@ -200,34 +202,37 @@ void *playback_thread(void *dummy){
if(playback_exit)break;
/* get data */
if(!(ret=input_read()))break;
//!(ret=declip_read()))break;
link=input_read();
result=link->samples;
link=declip_read(link);
result|=link->samples;
if(!result)break;
/************/
/* temporary; this would be frequency domain in the finished postfish */
if(ret && ret->samples>0){
if(link->samples>0){
double scale=fromdB(master_att/10.);
for(i=0;i<ret->samples;i++)
for(j=0;j<ret->channels;j++)
ret->data[j][i]*=scale;
for(i=0;i<link->samples;i++)
for(j=0;j<link->channels;j++)
link->data[j][i]*=scale;
}
/************/
if(ret && ret->samples>0){
if(link->samples>0){
memset(rms,0,sizeof(*rms)*(input_ch+2));
memset(peak,0,sizeof(*peak)*(input_ch+2));
ch=ret->channels;
rate=ret->rate;
ch=link->channels;
rate=link->rate;
/* 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);
playback_fd=playback_startup(outfileno,ch,rate,&bigendianp);
if(!playback_fd){
playback_active=0;
playback_exit=0;
......@@ -235,21 +240,21 @@ void *playback_thread(void *dummy){
}
setupp=1;
}
if(audiobufsize<ret->channels*ret->samples*2){
audiobufsize=ret->channels*ret->samples*2;
if(audiobufsize<link->channels*link->samples*2){
audiobufsize=link->channels*link->samples*2;
audiobuf=realloc(audiobuf,sizeof(*audiobuf)*audiobufsize);
}
/* final limiting and conversion */
for(k=0,i=0;i<ret->samples;i++){
for(k=0,i=0;i<link->samples;i++){
double mean=0.;
double div=0.;
double divrms=0.;
for(j=0;j<ret->channels;j++){
double dval=ret->data[j][i];
for(j=0;j<link->channels;j++){
double dval=link->data[j][i];
int val=rint(dval*32767.);
if(val>32767)val=32767;
if(val<-32768)val=-32768;
......@@ -260,41 +265,40 @@ void *playback_thread(void *dummy){
audiobuf[k++]=val;
audiobuf[k++]=val>>8;
}
if(fabs(dval)>peak[j])peak[j]=fabs(dval);
rms[j]+= dval*dval;
mean+=dval;