Commit 9ee0d754 authored by Monty Montgomery's avatar Monty Montgomery

Avoid losing work in progress


git-svn-id: https://svn.xiph.org/trunk/postfish@5872 0101bb08-14d6-0310-b084-bc0e0c8e3800
parent 8d0f905c
......@@ -11,21 +11,21 @@ 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 freq.c eq.c eqpanel.c compand.c compandpanel.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
OBJ = main.o mainpanel.o multibar.o readout.o input.o output.o clippanel.o \
declip.o reconstruct.o smallft.o windowbutton.o subpanel.o \
feedback.o freq.o eq.o eqpanel.o compand.o compandpanel.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
GCF = `pkg-config --cflags gtk+-2.0` -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED
all:
$(MAKE) target CFLAGS="-W -O2 $(GCF)"
$(MAKE) target CFLAGS="-W -O3 -ffast-math $(GCF)"
debug:
$(MAKE) target CFLAGS="-g -W -D__NO_MATH_INLINES $(GCF)"
profile:
$(MAKE) target CFLAGS="-W -pg -g -O2 $(GCF)"
$(MAKE) target CFLAGS="-W -pg -g -O3 $(GCF)"
clean:
rm -f $(OBJ) *.d
......@@ -37,7 +37,7 @@ include $(SRC:.c=.d)
target: $(OBJ)
./touch-version
$(LD) $(OBJ) $(CFLAGS) -o postfish `pkg-config --libs gtk+-2.0` -lpthread -lm
$(LD) $(OBJ) $(CFLAGS) -o postfish `pkg-config --libs gtk+-2.0` -lpthread -lfftw3f -lm
install:
$(INSTALL) -d -m 0755 $(BINDIR)
......
......@@ -58,7 +58,7 @@ typedef struct {
static void trigger_slider_change(GtkWidget *w,gpointer in){
char buffer[80];
clipslider *p=(clipslider *)in;
gdouble linear=multibar_get_value(MULTIBAR(p->slider),0);
float linear=multibar_get_value(MULTIBAR(p->slider),0);
sprintf(buffer,"%1.2f",linear);
readout_set(READOUT(p->readout),buffer);
......@@ -72,7 +72,7 @@ static void trigger_slider_change(GtkWidget *w,gpointer in){
static void blocksize_slider_change(GtkWidget *w,gpointer in){
char buffer[80];
int choice=rint(gtk_range_get_value(GTK_RANGE(w)));
int choice=rint(multibar_get_value(MULTIBAR(w),0));
int blocksize=64<<choice;
sprintf(buffer,"%5d ",blocksize);
......@@ -89,8 +89,8 @@ static void blocksize_slider_change(GtkWidget *w,gpointer in){
static void depth_slider_change(GtkWidget *w,gpointer in){
char buffer[80];
double dB=gtk_range_get_value(GTK_RANGE(w));
float dB=multibar_get_value(MULTIBAR(w),0);
sprintf(buffer,"%3ddB",(int)dB);
readout_set(READOUT(depth_readout),buffer);
......@@ -99,7 +99,7 @@ static void depth_slider_change(GtkWidget *w,gpointer in){
static void limit_slider_change(GtkWidget *w,gpointer in){
char buffer[80];
double percent=gtk_range_get_value(GTK_RANGE(w));
float percent=multibar_get_value(MULTIBAR(w),0);
sprintf(buffer,"%3d%%",(int)percent);
readout_set(READOUT(limit_readout),buffer);
......@@ -112,7 +112,7 @@ void clippanel_create(postfish_mainpanel *mp,
GtkWidget *activebutton){
int i;
char *labels[2]={"10%","100%"};
double levels[3]={0.,10.,100.};
float levels[3]={0.,10.,100.};
int block_choices=0;
subpanel_generic *panel=subpanel_create(mp,windowbutton,activebutton,
......@@ -142,11 +142,14 @@ void clippanel_create(postfish_mainpanel *mp,
/* set up blocksize config */
for(i=64;i<=input_size*2;i*=2)block_choices++;
{
float levels[9]={0,1,2,3,4,5,6,7,8};
char *labels[8]={"128","256","512","1024","2048","4096","8192","16384"};
GtkWidget *table=gtk_table_new(4,2,0);
GtkWidget *sliderbox=gtk_hbox_new(0,0);
GtkWidget *fastlabel=gtk_label_new("fastest");
GtkWidget *qualitylabel=gtk_label_new("best");
GtkWidget *slider=gtk_hscale_new_with_range(0,block_choices-1,1);
GtkWidget *slider=multibar_slider_new(block_choices-1,labels,levels,1);
GtkWidget *samplelabel=gtk_label_new("window sample width");
GtkWidget *mslabel=gtk_label_new("window time width");
GtkWidget *hzlabel=gtk_label_new("approximate lowest response");
......@@ -154,7 +157,6 @@ void clippanel_create(postfish_mainpanel *mp,
msreadout=readout_new("00000ms");
hzreadout=readout_new("00000Hz");
gtk_scale_set_draw_value(GTK_SCALE(slider),FALSE);
gtk_misc_set_alignment(GTK_MISC(samplelabel),1,.5);
gtk_misc_set_alignment(GTK_MISC(mslabel),1,.5);
gtk_misc_set_alignment(GTK_MISC(hzlabel),1,.5);
......@@ -172,27 +174,26 @@ 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);
multibar_thumb_increment(MULTIBAR(slider),1.,1.);
multibar_callback(MULTIBAR(slider),blocksize_slider_change,0);
g_signal_connect (G_OBJECT (slider), "key-press-event",
G_CALLBACK (slider_keymodify), NULL);
g_signal_connect_after (G_OBJECT(slider), "value-changed",
G_CALLBACK(blocksize_slider_change), 0);
gtk_range_set_value(GTK_RANGE(slider),2.);
multibar_thumb_set(MULTIBAR(slider),2.,0);
}
gtk_container_add(GTK_CONTAINER(blocksize_frame),blocksize_box);
/* set up convergence config */
{
float levels[7]={20,40,60,80,100,120,140};
char *labels[6]={"40","60","80","100","120","140"};
GtkWidget *table=gtk_table_new(2,2,0);
GtkWidget *sliderbox=gtk_hbox_new(0,0);
GtkWidget *fastlabel=gtk_label_new("fastest");
GtkWidget *qualitylabel=gtk_label_new("best");
GtkWidget *slider=gtk_hscale_new_with_range(1,140,1);
GtkWidget *slider=multibar_slider_new(6,labels,levels,1);
GtkWidget *label=gtk_label_new("solution depth");
depth_readout=readout_new("000dB");
gtk_scale_set_draw_value(GTK_SCALE(slider),FALSE);
gtk_misc_set_alignment(GTK_MISC(label),1,.5);
gtk_box_pack_start(GTK_BOX(sliderbox),fastlabel,0,0,4);
......@@ -205,25 +206,24 @@ void clippanel_create(postfish_mainpanel *mp,
gtk_container_add(GTK_CONTAINER(converge_box),table);
g_signal_connect (G_OBJECT (slider), "key-press-event",
G_CALLBACK (slider_keymodify), NULL);
g_signal_connect_after (G_OBJECT(slider), "value-changed",
G_CALLBACK(depth_slider_change), 0);
gtk_range_set_value(GTK_RANGE(slider),60.);
multibar_thumb_increment(MULTIBAR(slider),1.,10.);
multibar_callback(MULTIBAR(slider),depth_slider_change,0);
multibar_thumb_set(MULTIBAR(slider),60.,0);
}
/* set up limit config */
{
float levels[7]={1,5,10,20,40,60,100};
char *labels[6]={"5","10","20","40","60","100"};
GtkWidget *table=gtk_table_new(2,2,0);
GtkWidget *sliderbox=gtk_hbox_new(0,0);
GtkWidget *fastlabel=gtk_label_new("fastest");
GtkWidget *qualitylabel=gtk_label_new("best");
GtkWidget *slider=gtk_hscale_new_with_range(1,100,1);
GtkWidget *slider=multibar_slider_new(6,labels,levels,1);
GtkWidget *label=gtk_label_new("hard iteration limit");
limit_readout=readout_new("000%");
gtk_scale_set_draw_value(GTK_SCALE(slider),FALSE);
gtk_misc_set_alignment(GTK_MISC(label),1,.5);
gtk_box_pack_start(GTK_BOX(sliderbox),fastlabel,0,0,4);
......@@ -236,17 +236,15 @@ void clippanel_create(postfish_mainpanel *mp,
gtk_container_add(GTK_CONTAINER(limit_box),table);
g_signal_connect (G_OBJECT (slider), "key-press-event",
G_CALLBACK (slider_keymodify), NULL);
g_signal_connect_after (G_OBJECT(slider), "value-changed",
G_CALLBACK(limit_slider_change), 0);
gtk_range_set_value(GTK_RANGE(slider),100.);
multibar_thumb_increment(MULTIBAR(slider),1.,10.);
multibar_callback(MULTIBAR(slider),limit_slider_change,0);
multibar_thumb_set(MULTIBAR(slider),100.,0);
}
for(i=0;i<input_ch;i++){
char *slabels[8]={".05",".1",".2",".3",".4",
".6",".8","1."};
double slevels[9]={.01,.05,.1,.2,.3,.4,.6,
float slevels[9]={.01,.05,.1,.2,.3,.4,.6,
.8,1.};
char buffer[80];
......@@ -320,26 +318,29 @@ void clippanel_create(postfish_mainpanel *mp,
void clippanel_feedback(int displayit){
int clip[input_ch],count;
double peak[input_ch];
float peak[input_ch];
if(pull_declip_feedback(clip,peak,&count)){
int i;
for(i=0;i<input_ch;i++){
double val[2],zero[2];
float val[2],zero[2];
val[0]=-1.,zero[0]=-1.;
val[1]=(count?clip[i]*100./count-.1:-1);
zero[1]=-1.;
if(displayit && declip_visible){
multibar_set(MULTIBAR(feedback_bars[i]),zero,val,2);
val[0]=(count?peak[i]:-1);
multibar_set(MULTIBAR(trigger_bars[i]),zero,val,1);
}
multibar_set(MULTIBAR(feedback_bars[i]),zero,val,2,
(displayit && declip_visible));
val[0]=(count?peak[i]:-1);
multibar_set(MULTIBAR(trigger_bars[i]),zero,val,1,
(displayit && declip_visible));
if(clip[i]){
multibar_setwarn(MULTIBAR(mainpanel_inbar));
multibar_setwarn(MULTIBAR(feedback_bars[i]));
multibar_setwarn(MULTIBAR(trigger_bars[i]));
multibar_setwarn(MULTIBAR(mainpanel_inbar),
(displayit && declip_visible));
multibar_setwarn(MULTIBAR(feedback_bars[i]),
(displayit && declip_visible));
multibar_setwarn(MULTIBAR(trigger_bars[i]),
(displayit && declip_visible));
}
}
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -23,9 +23,9 @@
extern int declip_load(void);
extern int declip_setblock(int n);
extern int declip_settrigger(double trigger,int ch);
extern int declip_setiterations(double x);
extern int declip_setconvergence(double x);
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,double *peak,int *total);
extern int pull_declip_feedback(int *clip,float *peak,int *total);
......@@ -32,15 +32,18 @@ extern int input_size;
sig_atomic_t eq_active;
sig_atomic_t eq_visible;
sig_atomic_t curve_dirty=1;
freq_state eq;
int pull_eq_feedback(double **peak,double **rms){
/* accessed only in playback thread/setup */
int pull_eq_feedback(float **peak,float **rms){
return pull_freq_feedback(&eq,peak,rms);
}
/* called only by initial setup */
int eq_load(void){
return freq_load(&eq,input_size*2);
return freq_load(&eq,eq_freq_list,eq_freqs,input_size);
}
/* called only in playback thread */
......@@ -48,39 +51,45 @@ int eq_reset(){
return freq_reset(&eq);
}
static sig_atomic_t settings[freqs];
static sig_atomic_t settings[eq_freqs];
void eq_set(int freq, double value){
void eq_set(int freq, float value){
settings[freq]=rint(value*10.);
curve_dirty=1;
}
static float *curve_cache=0;
static void workfunc(freq_state *f,float **data,float **peak, float **rms){
int h,i,j,k;
float sq_mags[f->qblocksize*2+1];
static void workfunc(double *data,freq_state *f,
double *peak, double *rms){
int i,j,k;
double work[f->blocksize+1];
double sq_mags[f->blocksize+1];
if(eq_active){
memset(work,0,sizeof(work));
if(curve_dirty || !curve_cache){
curve_dirty=0;
for(i=0;i<freqs;i++){
double set=fromdB(settings[i]*.1);
for(k=0,j=f->ho_bin_lo[i];j<f->ho_bin_hi[i];j++,k++)
work[j]+=f->ho_window[i][k]*set;
peak[i]*=set;
rms[i]*=set;
if(!curve_cache)curve_cache=malloc((f->qblocksize*2+1)*sizeof(*curve_cache));
memset(curve_cache,0,(f->qblocksize*2+1)*sizeof(*curve_cache));
for(i=0;i<eq_freqs;i++){
float set=fromdB(settings[i]*.1);
for(j=0;j<f->qblocksize*2+1;j++)
curve_cache[j]+=f->ho_window[i][j]*set;
}
}
for(h=0;h<input_ch;h++){
data[0]*=work[0];
data[f->blocksize*2-1]*=work[f->blocksize];
for(i=1;i<f->blocksize;i++){
data[i*2]*=work[i];
data[i*2-1]*=work[i];
if(eq_active){
for(i=0;i<f->qblocksize*2+1;i++){
data[h][i*2]*=curve_cache[i];
data[h][i*2+1]*=curve_cache[i];
}
}
freq_metric_work(data[h],f,sq_mags,peak[h],rms[h]);
}
freq_metric_work(data,f,sq_mags,peak,rms);
return;
}
......
......@@ -23,8 +23,26 @@
#include "postfish.h"
extern int pull_eq_feedback(double **peak,double **rms);
#define eq_freqs 30
static float eq_freq_list[eq_freqs+1]={
25,31.5,40,50,63,80,
100,125,160,200,250,315,
400,500,630,800,1000,1250,1600,
2000,2500,3150,4000,5000,6300,
8000,10000,12500,16000,20000,9e10};
static char *eq_freq_labels[eq_freqs]={
"25","31.5","40","50","63","80",
"100","125","160","200","250","315",
"400","500","630","800","1k","1.2k","1.6k",
"2k","2.5k","3.1k","4k","5k","6.3k",
"8k","10k","12.5k","16k","20k"
};
extern int pull_eq_feedback(float **peak,float **rms);
extern int eq_load(void);
extern int eq_reset();
extern void eq_set(int freq, double value);
extern void eq_set(int freq, float value);
extern time_linkage *eq_read(time_linkage *in);
......@@ -44,12 +44,12 @@ typedef struct {
int number;
} bar;
static bar bars[freqs];
static bar bars[eq_freqs];
static void slider_change(GtkWidget *w,gpointer in){
char buffer[80];
bar *b=(bar *)in;
gdouble val=multibar_get_value(MULTIBAR(b->slider),0);
float val=multibar_get_value(MULTIBAR(b->slider),0);
sprintf(buffer,"%+3.0fdB",val);
readout_set(READOUT(b->readout),buffer);
......@@ -62,9 +62,9 @@ void eqpanel_create(postfish_mainpanel *mp,
GtkWidget *windowbutton,
GtkWidget *activebutton){
int i;
char *labels[15]={"-110","-100","-90","-80","-70","-60","-50","-40",
"-30","-20","-10","0","+10","+20","+30"};
double levels[16]={-120,-110,-100,-90,-80,-70,-60,-50,-40,
char *labels[15]={"110","100","90","80","70","60","50","40",
"30","20","10","0","+10","+20","+30"};
float levels[16]={-120,-110,-100,-90,-80,-70,-60,-50,-40,
-30,-20,-10,0,10,20,30};
subpanel_generic *panel=subpanel_create(mp,windowbutton,activebutton,
......@@ -72,10 +72,10 @@ void eqpanel_create(postfish_mainpanel *mp,
&eq_visible,
"_Equalization filter"," [e] ");
GtkWidget *slidertable=gtk_table_new(freqs,3,0);
GtkWidget *slidertable=gtk_table_new(eq_freqs,3,0);
for(i=0;i<freqs;i++){
const char *labeltext=freq_frequency_label(i);
for(i=0;i<eq_freqs;i++){
const char *labeltext=eq_freq_labels[i];
GtkWidget *label=gtk_label_new(labeltext);
gtk_widget_set_name(label,"smallmarker");
......@@ -87,7 +87,7 @@ void eqpanel_create(postfish_mainpanel *mp,
multibar_callback(MULTIBAR(bars[i].slider),slider_change,bars+i);
multibar_thumb_set(MULTIBAR(bars[i].slider),0.,0);
multibar_thumb_bounds(MULTIBAR(bars[i].slider),-40,30);
multibar_thumb_bounds(MULTIBAR(bars[i].slider),-60,30);
multibar_thumb_increment(MULTIBAR(bars[i].slider),1,10);
gtk_misc_set_alignment(GTK_MISC(label),1,.5);
......@@ -104,35 +104,31 @@ void eqpanel_create(postfish_mainpanel *mp,
}
static double **peakfeed=0;
static double **rmsfeed=0;
static float **peakfeed=0;
static float **rmsfeed=0;
void eqpanel_feedback(int displayit){
int i;
if(!peakfeed){
peakfeed=malloc(sizeof(*peakfeed)*freqs);
rmsfeed=malloc(sizeof(*rmsfeed)*freqs);
peakfeed=malloc(sizeof(*peakfeed)*eq_freqs);
rmsfeed=malloc(sizeof(*rmsfeed)*eq_freqs);
for(i=0;i<freqs;i++){
for(i=0;i<eq_freqs;i++){
peakfeed[i]=malloc(sizeof(**peakfeed)*input_ch);
rmsfeed[i]=malloc(sizeof(**rmsfeed)*input_ch);
}
}
if(pull_eq_feedback(peakfeed,rmsfeed)==1)
if(displayit && eq_visible)
for(i=0;i<freqs;i++)
multibar_set(MULTIBAR(bars[i].slider),rmsfeed[i],peakfeed[i],input_ch);
for(i=0;i<eq_freqs;i++)
multibar_set(MULTIBAR(bars[i].slider),rmsfeed[i],peakfeed[i],
input_ch,(displayit && eq_visible));
}
void eqpanel_reset(void){
int i;
for(i=0;i<freqs;i++)
for(i=0;i<eq_freqs;i++)
multibar_reset(MULTIBAR(bars[i].slider));
}
This diff is collapsed.
......@@ -22,38 +22,42 @@
*/
#include "postfish.h"
#include "smallft.h"
#define freqs 30
#include <fftw3.h>
typedef struct {
drft_lookup fft;
time_linkage out;
feedback_generic_pool feedpool;
float **fftwf_buffer; // need one for each channel
fftwf_plan *fftwf_forward; // need one for each channel
fftwf_plan *fftwf_backward; // need one for each channel
int blocksize;
double **ho_window;
double ho_area[freqs];
int ho_bin_lo[freqs];
int ho_bin_hi[freqs];
int qblocksize;
int bands;
float *frequencies;
float **ho_window;
float *ho_area;
double *window;
double **lap;
double **cache;
float *window;
float **lap;
float **cache;
int cache_samples;
int fillstate; /* 0: uninitialized
1: normal
2: eof processed */
} freq_state;
extern int pull_freq_feedback(freq_state *ff,double **peak,double **rms);
extern int freq_load(freq_state *f,int blocksize);
extern void freq_transform_work(float *work,freq_state *f);
extern int pull_freq_feedback(freq_state *ff,float **peak,float **rms);
extern int freq_load(freq_state *f,float *frequencies, int bands,
int blocksize);
extern int freq_reset(freq_state *f);
extern const char *freq_frequency_label(int n);
extern time_linkage *freq_read(time_linkage *in, freq_state *f,
void (*func)(double *data,freq_state *f,
double *peak, double *rms),
void (*func)(freq_state *f,
float **data,
float **peak, float **rms),
int bypassp);
extern void freq_metric_work(double *work,freq_state *f,
double *sq_mags,double *peak,double *rms);
extern void freq_metric_work(float *work,freq_state *f,
float *sq_mags,float *peak,float *rms);
......@@ -50,8 +50,8 @@ typedef struct {
typedef struct input_feedback{
feedback_generic parent_class;
off_t cursor;
double *rms;
double *peak;
float *rms;
float *peak;
} input_feedback;
static feedback_generic_pool feedpool;
......@@ -385,7 +385,7 @@ off_t input_seek(off_t pos){
return cursor;
}
off_t input_time_seek_rel(double s){
off_t input_time_seek_rel(float s){
off_t ret;
pthread_mutex_lock(&master_mutex);
ret=input_seek(cursor+input_rate*inbytes*input_ch*s);
......@@ -400,7 +400,7 @@ static feedback_generic *new_input_feedback(void){
return (feedback_generic *)ret;
}
static void push_input_feedback(double *peak,double *rms, off_t cursor){
static void push_input_feedback(float *peak,float *rms, off_t cursor){
int i,n=input_ch+2;
input_feedback *f=(input_feedback *)
feedback_new(&feedpool,new_input_feedback);
......@@ -410,7 +410,7 @@ static void push_input_feedback(double *peak,double *rms, off_t cursor){
feedback_push(&feedpool,(feedback_generic *)f);
}
int pull_input_feedback(double *peak,double *rms,off_t *cursor){
int pull_input_feedback(float *peak,float *rms,off_t *cursor){
input_feedback *f=(input_feedback *)feedback_pull(&feedpool);
int i,j,n=input_ch+2;
if(!f)return 0;
......@@ -425,8 +425,8 @@ time_linkage *input_read(void){
int read_b=0,i,j,k;
int toread_b=out.size*out.channels*inbytes;
unsigned char *readbuf;
double *rms=alloca(sizeof(*rms)*(out.channels+2));
double *peak=alloca(sizeof(*peak)*(out.channels+2));
float *rms=alloca(sizeof(*rms)*(out.channels+2));
float *peak=alloca(sizeof(*peak)*(out.channels+2));
memset(rms,0,sizeof(*rms)*(out.channels+2));
memset(peak,0,sizeof(*peak)*(out.channels+2));
......@@ -495,12 +495,12 @@ time_linkage *input_read(void){
k=0;
for(i=0;i<out.samples;i++){
double mean=0.;
double div=0.;
double divrms=0.;
float mean=0.;
float div=0.;
float divrms=0.;
for(j=0;j<out.channels;j++){
double dval;
float dval;
long val=0;
switch(inbytes){
case 1:
......@@ -535,7 +535,7 @@ time_linkage *input_read(void){
/* div */
for(j=0;j<out.channels;j++){
double dval=mean-out.data[j][i];
float dval=mean-out.data[j][i];
if(fabs(dval)>peak[out.channels+1])peak[out.channels+1]=fabs(dval);
divrms+=dval*dval;
}
......
......@@ -6,6 +6,6 @@ extern void time_fix(char *buffer);
extern off_t input_seek(off_t pos);
extern time_linkage *input_read(void);
extern int input_load(int n,char *list[]);
extern int pull_input_feedback(double *peak,double *rms,off_t *cursor);
extern int pull_input_feedback(float *peak,float *rms,off_t *cursor);
extern void input_reset(void);
extern off_t input_time_seek_rel(double s);
extern off_t input_time_seek_rel(float s);
/*
*
* postfish.c
*
* 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.
*
*
*/
/* The LPC filters are used to extrapolate past the initial and final
PCM 'cliffs' to remove most of the frequency-domain pollution from the
abrupt edges */
/* lpc_from_data is derived from code written by Jutta Degener and
Carsten Bormann; thus we include their copyright below. */
/* Preserved Copyright: *********************************************/
/* Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,
Technische Universita"t Berlin
Any use of this software is permitted provided that this notice is not
removed and that neither the authors nor the Technische Universita"t
Berlin are deemed to have made any representations as to the
suitability of this software for any purpose nor are held responsible
for any defects of this software. THERE IS ABSOLUTELY NO WARRANTY FOR
THIS SOFTWARE.
As a matter of courtesy, the authors request to be informed about uses
this software has found, about bugs in this software, and about any
improvements that may be of general interest.
Berlin, 28.11.1994
Jutta Degener
Carsten Bormann
*********************************************************************/
#include "postfish.h"
#include "lpc.h"
/* this version is from the Vorbis source code */
static float lpc_from_data(float *data,float *coeff,int n,int m){
double *aut=alloca(sizeof(*aut)*(m+1));
double *lpc=alloca(sizeof(*lpc)*(m));
double error;
int i,j;
/* autocorrelation, p+1 lag coefficients */
j=m+1;
while(j--){
double d=0; /* double needed for accumulator depth */
for(i=j;i<n;i++)d+=(double)data[i]*data[i-j];
aut[j]=d;
}
/* Generate lpc coefficients from autocorr values */
error=aut[0];
for(i=0;i<m;i++){
double r= -aut[i+1];
if(error==0){
memset(coeff,0,m*sizeof(*coeff));
return 0;
}
/* Sum up this iteration's reflection coefficient; note that in
Vorbis we don't save it. If anyone wants to recycle this code
and needs reflection coefficients, save the results of 'r' from
each iteration. */
for(j=0;j<i;j++)r-=lpc[j]*aut[i-j];
r/=error;
/* Update LPC coefficients and total error */
lpc[i]=r;
for(j=0;j<i/2;j++){
double tmp=lpc[j];
lpc[j]+=r*lpc[i-1-j];
lpc[i-1-j]+=r*tmp;
}
if(i%2)lpc[j]+=lpc[j]*r;
error*=1.f-r*r;
}
for(j=0;j<m;j++)coeff[j]=(float)lpc[j];
/* we need the error value to know how big an impulse to hit the
filter with later */