tg/interface.c
2015-10-04 11:56:54 +02:00

763 lines
21 KiB
C

/*
tg
Copyright (C) 2015 Marcello Mamino
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "tg.h"
int preset_bph[] = PRESET_BPH;
void print_debug(char *format,...)
{
va_list args;
va_start(args,format);
vfprintf(stderr,format,args);
va_end(args);
}
void error(char *format,...)
{
va_list args;
va_start(args,format);
vfprintf(stderr,format,args);
va_end(args);
}
struct main_window {
GtkWidget *window;
GtkWidget *bph_combo_box;
GtkWidget *la_spin_button;
GtkWidget *output_drawing_area;
GtkWidget *tic_drawing_area;
GtkWidget *toc_drawing_area;
GtkWidget *period_drawing_area;
GtkWidget *paperstrip_drawing_area;
#ifdef DEBUG
GtkWidget *debug_drawing_area;
#endif
struct processing_buffers *bfs;
struct processing_buffers *old;
int bph;
int guessed_bph;
int last_bph;
double la;
uint64_t *events;
int events_wp;
uint64_t events_from;
int signal;
};
void redraw(struct main_window *w)
{
gtk_widget_queue_draw_area(w->output_drawing_area,0,0,w->output_drawing_area->allocation.width,w->output_drawing_area->allocation.height);
gtk_widget_queue_draw_area(w->tic_drawing_area,0,0,w->tic_drawing_area->allocation.width,w->tic_drawing_area->allocation.height);
gtk_widget_queue_draw_area(w->toc_drawing_area,0,0,w->toc_drawing_area->allocation.width,w->toc_drawing_area->allocation.height);
gtk_widget_queue_draw_area(w->period_drawing_area,0,0,w->period_drawing_area->allocation.width,w->period_drawing_area->allocation.height);
gtk_widget_queue_draw_area(w->paperstrip_drawing_area,0,0,w->paperstrip_drawing_area->allocation.width,w->paperstrip_drawing_area->allocation.height);
#ifdef DEBUG
gtk_widget_queue_draw_area(w->debug_drawing_area,0,0,w->debug_drawing_area->allocation.width,w->debug_drawing_area->allocation.height);
#endif
}
int guess_bph(double period)
{
double bph = 7200 / period;
double min = bph;
int i,ret;
ret = 0;
for(i=0; preset_bph[i]; i++) {
double diff = fabs(bph - preset_bph[i]);
if(diff < min) {
min = diff;
ret = i;
}
}
return preset_bph[ret];
}
struct processing_buffers *get_data(struct main_window *w, int *old)
{
struct processing_buffers *p = w->bfs;
int i;
for(i=0; i<NSTEPS && p[i].ready; i++);
if(i && p[i-1].sigma < p[i-1].period / 10000) {
if(w->old) pb_destroy_clone(w->old);
w->old = pb_clone(&p[i-1]);
*old = 0;
return &p[i-1];
} else {
*old = 1;
return w->old;
}
}
void recompute(struct main_window *w)
{
w->signal = analyze_pa_data(w->bfs, w->bph, w->events_from);
int old;
struct processing_buffers *p = get_data(w,&old);
if(old) w->signal = -w->signal;
if(p)
w->guessed_bph = w->bph ? w->bph : guess_bph(p->period / p->sample_rate);
}
guint refresh(struct main_window *w)
{
recompute(w);
redraw(w);
return TRUE;
}
cairo_pattern_t *black,*white,*red,*green,*gray,*blue,*yellow,*yellowish,*magenta;
void define_color(cairo_pattern_t **gc,double r,double g,double b)
{
*gc = cairo_pattern_create_rgb(r,g,b);
}
void initialize_palette()
{
define_color(&black,0,0,0);
define_color(&white,1,1,1);
define_color(&red,1,0,0);
define_color(&green,0,0.8,0);
define_color(&gray,0.5,0.5,0.5);
define_color(&blue,0,0,1);
define_color(&yellow,1,1,0);
define_color(&yellowish,0.5,0.5,0);
define_color(&magenta,1,0,1);
}
gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
return FALSE;
}
void draw_graph(double a, double b, cairo_t *c, struct processing_buffers *p, GtkWidget *da)
{
int width = da->allocation.width;
int height = da->allocation.height;
int n;
int first = 1;
for(n=0; n<2*width; n++) {
int i = n < width ? n : 2*width - 1 - n;
double x = fmod(a + i * (b-a) / width, p->period);
if(x < 0) x += p->period;
int j = floor(x);
double y;
if(p->waveform[j] <= 0) y = 0;
else y = p->waveform[j] * 0.4 / p->waveform_max;
int k = round(y*height);
if(n < width) k = -k;
if(first) {
cairo_move_to(c,i+.5,height/2+k+.5);
first = 0;
} else
cairo_line_to(c,i+.5,height/2+k+.5);
}
}
#ifdef DEBUG
void draw_debug_graph(double a, double b, cairo_t *c, struct processing_buffers *p, GtkWidget *da)
{
int width = da->allocation.width;
int height = da->allocation.height;
int i;
float max = 0;
int ai = round(a);
int bi = 1+round(b);
if(ai < 0) ai = 0;
if(bi > p->sample_count) bi = p->sample_count;
for(i=ai; i<bi; i++)
if(p->debug[i] > max)
max = p->debug[i];
int first = 1;
for(i=0; i<width; i++) {
if( round(a + i*(b-a)/width) != round(a + (i+1)*(b-a)/width) ) {
int j = round(a + i*(b-a)/width);
if(j < 0) j = 0;
if(j >= p->sample_count) j = p->sample_count-1;
int k = round((0.1+p->debug[j]/max)*0.8*height);
if(first) {
cairo_move_to(c,i+.5,height-k-.5);
first = 0;
} else
cairo_line_to(c,i+.5,height-k-.5);
}
}
}
#endif
double amplitude_to_time(double lift_angle, double amp)
{
return asin(lift_angle / (2 * amp)) / M_PI;
}
double draw_watch_icon(cairo_t *c, int signal)
{
int happy = !!signal;
cairo_set_line_width(c,3);
cairo_set_source(c,happy?green:red);
cairo_move_to(c, OUTPUT_WINDOW_HEIGHT * 0.5, OUTPUT_WINDOW_HEIGHT * 0.5);
cairo_line_to(c, OUTPUT_WINDOW_HEIGHT * 0.75, OUTPUT_WINDOW_HEIGHT * (0.75 - 0.5*happy));
cairo_move_to(c, OUTPUT_WINDOW_HEIGHT * 0.5, OUTPUT_WINDOW_HEIGHT * 0.5);
cairo_line_to(c, OUTPUT_WINDOW_HEIGHT * 0.35, OUTPUT_WINDOW_HEIGHT * (0.65 - 0.3*happy));
cairo_stroke(c);
cairo_arc(c, OUTPUT_WINDOW_HEIGHT * 0.5, OUTPUT_WINDOW_HEIGHT * 0.5, OUTPUT_WINDOW_HEIGHT * 0.4, 0, 2*M_PI);
cairo_stroke(c);
const int l = OUTPUT_WINDOW_HEIGHT * 0.8 / (2*NSTEPS - 1);
int i;
cairo_set_line_width(c,1);
for(i = 0; i < signal; i++) {
cairo_move_to(c, OUTPUT_WINDOW_HEIGHT + 0.5*l, OUTPUT_WINDOW_HEIGHT * 0.9 - 2*i*l);
cairo_line_to(c, OUTPUT_WINDOW_HEIGHT + 1.5*l, OUTPUT_WINDOW_HEIGHT * 0.9 - 2*i*l);
cairo_line_to(c, OUTPUT_WINDOW_HEIGHT + 1.5*l, OUTPUT_WINDOW_HEIGHT * 0.9 - (2*i+1)*l);
cairo_line_to(c, OUTPUT_WINDOW_HEIGHT + 0.5*l, OUTPUT_WINDOW_HEIGHT * 0.9 - (2*i+1)*l);
cairo_line_to(c, OUTPUT_WINDOW_HEIGHT + 0.5*l, OUTPUT_WINDOW_HEIGHT * 0.9 - 2*i*l);
cairo_stroke_preserve(c);
cairo_fill(c);
}
return OUTPUT_WINDOW_HEIGHT + 3*l;
}
gboolean output_expose_event(GtkWidget *widget, GdkEvent *event, struct main_window *w)
{
cairo_t *c;
c = gdk_cairo_create(widget->window);
cairo_set_font_size(c,OUTPUT_FONT);
cairo_set_source(c,black);
cairo_paint(c);
int old;
struct processing_buffers *p = get_data(w,&old);
double x = draw_watch_icon(c,w->signal);
char rates[100];
char bphs[100];
if(p) {
int bph = w->guessed_bph;
double rate = (7200/(bph*p->period / p->sample_rate) - 1)*24*3600;
double be = fabs(p->be) * 1000 / p->sample_rate;
rate = round(rate);
if(rate == 0) rate = 0;
sprintf(rates,"%s%.0f s/d %.1f ms ",rate > 0 ? "+" : "",rate,be);
sprintf(bphs,"%d bph",bph);
} else {
strcpy(rates,"--- s/d --- ms ");
sprintf(bphs,"%d bph",w->guessed_bph);
}
if(p && old)
cairo_set_source(c,yellow);
else
cairo_set_source(c,white);
cairo_text_extents_t extents;
cairo_text_extents(c,"0",&extents);
double y = (double)OUTPUT_WINDOW_HEIGHT/2 - extents.y_bearing - extents.height/2;
cairo_move_to(c,x,y);
cairo_show_text(c,rates);
cairo_text_extents(c,rates,&extents);
x += extents.x_advance;
cairo_set_source(c,white);
cairo_move_to(c,x,y);
cairo_show_text(c,bphs);
cairo_text_extents(c,bphs,&extents);
x += extents.x_advance;
cairo_destroy(c);
return FALSE;
}
void expose_waveform(cairo_t *c, struct main_window *w, GtkWidget *da, int (*get_offset)(struct processing_buffers*))
{
int width = da->allocation.width;
int height = da->allocation.height;
int font = width / 90;
if(font < 12)
font = 12;
int i;
cairo_set_line_width(c,1);
cairo_set_font_size(c,font);
cairo_set_source(c,black);
cairo_paint(c);
for(i = 1-NEGATIVE_SPAN; i < POSITIVE_SPAN; i++) {
int x = (NEGATIVE_SPAN + i) * width / (POSITIVE_SPAN + NEGATIVE_SPAN);
cairo_move_to(c, x + .5, height / 2 + .5);
cairo_line_to(c, x + .5, height - .5);
if(i%5)
cairo_set_source(c,green);
else
cairo_set_source(c,red);
cairo_stroke(c);
}
cairo_set_source(c,white);
for(i = 1-NEGATIVE_SPAN; i < POSITIVE_SPAN; i++) {
int x = (NEGATIVE_SPAN + i) * width / (POSITIVE_SPAN + NEGATIVE_SPAN);
if(!(i%5)) {
char s[10];
sprintf(s,"%d",i);
cairo_move_to(c,x+font/4,height-font/2);
cairo_show_text(c,s);
}
}
int old;
struct processing_buffers *p = get_data(w,&old);
double period = p ? p->period / p->sample_rate : 7200. / w->guessed_bph;
for(i = 10; i < 360; i+=10) {
if(2*i < w->la) continue;
double t = period*amplitude_to_time(w->la,i);
if(t > .001 * NEGATIVE_SPAN) continue;
int x = round(width * (NEGATIVE_SPAN - 1000*t) / (NEGATIVE_SPAN + POSITIVE_SPAN));
cairo_move_to(c, x+.5, .5);
cairo_line_to(c, x+.5, height / 2 + .5);
if(i % 50)
cairo_set_source(c,green);
else
cairo_set_source(c,red);
cairo_stroke(c);
}
cairo_set_source(c,white);
for(i = 50; i < 360; i+=50) {
double t = period*amplitude_to_time(w->la,i);
if(t > .001 * NEGATIVE_SPAN) continue;
int x = round(width * (NEGATIVE_SPAN - 1000*t) / (NEGATIVE_SPAN + POSITIVE_SPAN));
char s[10];
sprintf(s,"%d",abs(i));
cairo_move_to(c,x+font/4,font * 3 / 2);
cairo_show_text(c,s);
}
if(p) {
double span = 0.001 * p->sample_rate;
int offset = get_offset(p);
double a = offset - span * NEGATIVE_SPAN;
double b = offset + span * POSITIVE_SPAN;
draw_graph(a,b,c,p,da);
cairo_set_source(c,old?yellow:white);
cairo_stroke_preserve(c);
cairo_fill(c);
} else {
cairo_move_to(c, .5, height / 2 + .5);
cairo_line_to(c, width - .5, height / 2 + .5);
cairo_set_source(c,yellow);
cairo_stroke(c);
}
cairo_destroy(c);
}
int get_tic(struct processing_buffers *p)
{
return p->tic;
}
int get_toc(struct processing_buffers *p)
{
return p->toc;
}
gboolean tic_expose_event(GtkWidget *widget, GdkEvent *event, struct main_window *w)
{
expose_waveform(gdk_cairo_create(widget->window), w, w->tic_drawing_area, get_tic);
return FALSE;
}
gboolean toc_expose_event(GtkWidget *widget, GdkEvent *event, struct main_window *w)
{
expose_waveform(gdk_cairo_create(widget->window), w, w->toc_drawing_area, get_toc);
return FALSE;
}
gboolean period_expose_event(GtkWidget *widget, GdkEvent *event, struct main_window *w)
{
int width = w->period_drawing_area->allocation.width;
int height = w->period_drawing_area->allocation.height;
cairo_t *c = gdk_cairo_create(widget->window);
cairo_set_line_width(c,1);
cairo_set_source(c,black);
cairo_paint(c);
int i;
for(i = 1; i < 16; i++) {
int x = i * width / 16;
cairo_move_to(c, x+.5, .5);
cairo_line_to(c, x+.5, height - .5);
if(i % 4)
cairo_set_source(c,green);
else
cairo_set_source(c,red);
cairo_stroke(c);
}
int old;
struct processing_buffers *p = get_data(w,&old);
if(p) {
double toc = p->tic < p->toc ? p->toc : p->toc + p->period;
double a = ((double)p->tic + toc)/2 - p->period/2;
double b = ((double)p->tic + toc)/2 + p->period/2;
draw_graph(a,b,c,p,w->period_drawing_area);
cairo_set_source(c,old?yellow:white);
cairo_stroke_preserve(c);
cairo_fill(c);
} else {
cairo_move_to(c, .5, height / 2 + .5);
cairo_line_to(c, width - .5, height / 2 + .5);
cairo_set_source(c,yellow);
cairo_stroke(c);
}
cairo_destroy(c);
return FALSE;
}
extern volatile uint64_t timestamp;
gboolean paperstrip_expose_event(GtkWidget *widget, GdkEvent *event, struct main_window *w)
{
int i,old;
struct processing_buffers *p = get_data(w,&old);
if(p && !old) {
uint64_t last = w->events[w->events_wp];
for(i=0; i<EVENTS_MAX && p->events[i]; i++)
if(p->events[i] > last + floor(p->period / 4)) {
if(++w->events_wp == EVENTS_COUNT) w->events_wp = 0;
w->events[w->events_wp] = p->events[i];
debug("event at %llu\n",w->events[w->events_wp]);
}
w->events_from = p->timestamp - ceil(p->period);
} else {
w->events_from = timestamp;
}
cairo_t *c;
int width = w->paperstrip_drawing_area->allocation.width;
int height = w->paperstrip_drawing_area->allocation.height;
c = gdk_cairo_create(widget->window);
cairo_set_source(c,black);
cairo_paint(c);
uint64_t time = timestamp;
int stopped = 0;
if(w->events[w->events_wp] && time > 5*PA_SAMPLE_RATE + w->events[w->events_wp]) {
time = 5*PA_SAMPLE_RATE + w->events[w->events_wp];
stopped = 1;
}
int strip_width = width * 9 / 10;
double sweep = PA_SAMPLE_RATE * 3600. / w->guessed_bph;
double now = sweep*ceil(time/sweep);
cairo_move_to(c, width/20 + .5, .5);
cairo_line_to(c, width/20 + .5, height - .5);
cairo_move_to(c, 19*width/20 + .5, .5);
cairo_line_to(c, 19*width/20 + .5, height - .5);
cairo_set_source(c, green);
cairo_stroke(c);
double ten_s = PA_SAMPLE_RATE * 10 / sweep;
double last_line = fmod(now/sweep, ten_s);
int last_tenth = floor(now/(sweep*ten_s));
for(i=0;;i++) {
double y = 0.5 + round(last_line + i*ten_s);
if(y > height) break;
cairo_move_to(c, .5, y);
cairo_line_to(c, width-.5, y);
cairo_set_source(c, (last_tenth-i)%6 ? green : red);
cairo_stroke(c);
}
cairo_set_source(c,stopped?yellow:white);
for(i = w->events_wp;;) {
if(!w->events[i]) break;
int column = floor(fmod(now - w->events[i], (sweep / PAPERSTRIP_ZOOM)) * strip_width / (sweep / PAPERSTRIP_ZOOM));
int row = floor((now - w->events[i]) / sweep);
if(row >= height) break;
cairo_move_to(c,column,row);
cairo_line_to(c,column+1,row);
cairo_line_to(c,column+1,row+1);
cairo_line_to(c,column,row+1);
cairo_line_to(c,column,row);
cairo_fill(c);
if(column < width - strip_width && row > 0) {
column += strip_width;
row -= 1;
cairo_move_to(c,column,row);
cairo_line_to(c,column+1,row);
cairo_line_to(c,column+1,row+1);
cairo_line_to(c,column,row+1);
cairo_line_to(c,column,row);
cairo_fill(c);
}
if(--i < 0) i = EVENTS_COUNT - 1;
if(i == w->events_wp) break;
}
cairo_destroy(c);
return FALSE;
}
#ifdef DEBUG
gboolean debug_expose_event(GtkWidget *widget, GdkEvent *event, struct main_window *w)
{
cairo_t *c;
c = gdk_cairo_create(widget->window);
cairo_set_line_width(c,1);
cairo_set_source(c,black);
cairo_paint(c);
int old = 0;
struct processing_buffers *p = get_data(w,&old);
//struct processing_buffers *p = ((struct interactive_w_data *)w->data)->bfs;
if(p) {
double a = p->period / 10;
double b = p->period * 2;
draw_debug_graph(a,b,c,p,w->debug_drawing_area);
cairo_set_source(c,old?yellow:white);
cairo_stroke(c);
}
cairo_destroy(c);
return FALSE;
}
#endif
void handle_bph_change(GtkComboBox *b, struct main_window *w)
{
char *s = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(b));
if(s) {
int n;
char *t;
n = strtol(s,&t,10);
if(*t || n < MIN_BPH || n > MAX_BPH) w->bph = 0;
else w->bph = w->guessed_bph = n;
g_free(s);
recompute(w);
redraw(w);
}
}
void handle_la_change(GtkSpinButton *b, struct main_window *w)
{
double la = gtk_spin_button_get_value(b);
if(la < MIN_LA || la > MAX_LA) la = DEFAULT_LA;
w->la = la;
redraw(w);
}
void quit()
{
gtk_main_quit();
}
void init_main_window(struct main_window *w)
{
w->signal = 0;
w->events = malloc(EVENTS_COUNT * sizeof(uint64_t));
memset(w->events,0,EVENTS_COUNT * sizeof(uint64_t));
w->events_wp = 0;
w->events_from = 0;
w->guessed_bph = w->last_bph = DEFAULT_BPH;
w->bph = 0;
w->la = DEFAULT_LA;
w->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_container_set_border_width(GTK_CONTAINER(w->window),10);
g_signal_connect(G_OBJECT(w->window),"delete_event",G_CALLBACK(delete_event),NULL);
g_signal_connect(G_OBJECT(w->window),"destroy",G_CALLBACK(quit),w);
GtkWidget *vbox = gtk_vbox_new(FALSE,10);
gtk_container_add(GTK_CONTAINER(w->window),vbox);
gtk_widget_show(vbox);
GtkWidget *hbox = gtk_hbox_new(FALSE,10);
gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,TRUE,0);
gtk_widget_show(hbox);
GtkWidget *label = gtk_label_new("bph");
GTK_WIDGET_SET_FLAGS(label,GTK_NO_WINDOW);
gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
gtk_widget_show(label);
w->bph_combo_box = gtk_combo_box_text_new_with_entry();
gtk_box_pack_start(GTK_BOX(hbox),w->bph_combo_box,FALSE,TRUE,0);
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w->bph_combo_box),"guess");
int *bph;
for(bph = preset_bph; *bph; bph++) {
char s[100];
sprintf(s,"%d",*bph);
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(w->bph_combo_box),s);
}
gtk_combo_box_set_active(GTK_COMBO_BOX(w->bph_combo_box),0);
gtk_signal_connect(GTK_OBJECT(w->bph_combo_box),"changed",(GtkSignalFunc)handle_bph_change,w);
gtk_widget_show(w->bph_combo_box);
label = gtk_label_new("lift angle");
GTK_WIDGET_SET_FLAGS(label,GTK_NO_WINDOW);
gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
gtk_widget_show(label);
w->la_spin_button = gtk_spin_button_new_with_range(MIN_LA,MAX_LA,1);
gtk_box_pack_start(GTK_BOX(hbox),w->la_spin_button,FALSE,TRUE,0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(w->la_spin_button),DEFAULT_LA);
gtk_signal_connect(GTK_OBJECT(w->la_spin_button),"value_changed",(GtkSignalFunc)handle_la_change,w);
gtk_widget_show(w->la_spin_button);
GtkWidget *hbox2 = gtk_hbox_new(FALSE,10);
gtk_box_pack_start(GTK_BOX(vbox),hbox2,TRUE,TRUE,0);
gtk_widget_show(hbox2);
w->paperstrip_drawing_area = gtk_drawing_area_new();
gtk_drawing_area_size(GTK_DRAWING_AREA(w->paperstrip_drawing_area),200,500);
gtk_box_pack_start(GTK_BOX(hbox2),w->paperstrip_drawing_area,FALSE,TRUE,0);
gtk_signal_connect(GTK_OBJECT(w->paperstrip_drawing_area),"expose_event",
(GtkSignalFunc)paperstrip_expose_event, w);
gtk_widget_set_events(w->paperstrip_drawing_area, GDK_EXPOSURE_MASK);
gtk_widget_show(w->paperstrip_drawing_area);
GtkWidget *vbox2 = gtk_vbox_new(FALSE,10);
gtk_box_pack_start(GTK_BOX(hbox2),vbox2,TRUE,TRUE,0);
gtk_widget_show(vbox2);
w->output_drawing_area = gtk_drawing_area_new();
gtk_drawing_area_size(GTK_DRAWING_AREA(w->output_drawing_area),500,OUTPUT_WINDOW_HEIGHT);
gtk_box_pack_start(GTK_BOX(vbox2),w->output_drawing_area,FALSE,TRUE,0);
gtk_signal_connect(GTK_OBJECT(w->output_drawing_area),"expose_event",
(GtkSignalFunc)output_expose_event, w);
gtk_widget_set_events(w->output_drawing_area, GDK_EXPOSURE_MASK);
gtk_widget_show(w->output_drawing_area);
w->tic_drawing_area = gtk_drawing_area_new();
gtk_drawing_area_size(GTK_DRAWING_AREA(w->tic_drawing_area),500,200);
gtk_box_pack_start(GTK_BOX(vbox2),w->tic_drawing_area,TRUE,TRUE,0);
gtk_signal_connect(GTK_OBJECT(w->tic_drawing_area),"expose_event",
(GtkSignalFunc)tic_expose_event, w);
gtk_widget_set_events(w->tic_drawing_area, GDK_EXPOSURE_MASK);
gtk_widget_show(w->tic_drawing_area);
w->toc_drawing_area = gtk_drawing_area_new();
gtk_drawing_area_size(GTK_DRAWING_AREA(w->toc_drawing_area),500,200);
gtk_box_pack_start(GTK_BOX(vbox2),w->toc_drawing_area,TRUE,TRUE,0);
gtk_signal_connect(GTK_OBJECT(w->toc_drawing_area),"expose_event",
(GtkSignalFunc)toc_expose_event, w);
gtk_widget_set_events(w->toc_drawing_area, GDK_EXPOSURE_MASK);
gtk_widget_show(w->toc_drawing_area);
w->period_drawing_area = gtk_drawing_area_new();
gtk_drawing_area_size(GTK_DRAWING_AREA(w->period_drawing_area),500,200);
gtk_box_pack_start(GTK_BOX(vbox2),w->period_drawing_area,TRUE,TRUE,0);
gtk_signal_connect(GTK_OBJECT(w->period_drawing_area),"expose_event",
(GtkSignalFunc)period_expose_event, w);
gtk_widget_set_events(w->period_drawing_area, GDK_EXPOSURE_MASK);
gtk_widget_show(w->period_drawing_area);
#ifdef DEBUG
w->debug_drawing_area = gtk_drawing_area_new();
gtk_drawing_area_size(GTK_DRAWING_AREA(w->debug_drawing_area),500,200);
gtk_box_pack_start(GTK_BOX(vbox2),w->debug_drawing_area,TRUE,TRUE,0);
gtk_signal_connect(GTK_OBJECT(w->debug_drawing_area),"expose_event",
(GtkSignalFunc)debug_expose_event, w);
gtk_widget_set_events(w->debug_drawing_area, GDK_EXPOSURE_MASK);
gtk_widget_show(w->debug_drawing_area);
#endif
gtk_window_maximize(GTK_WINDOW(w->window));
gtk_widget_show(w->window);
gtk_window_set_focus(GTK_WINDOW(w->window), NULL);
}
int run_interface()
{
struct processing_buffers p[NSTEPS];
int i;
for(i=0; i<NSTEPS; i++) {
p[i].sample_rate = PA_SAMPLE_RATE;
p[i].sample_count = PA_SAMPLE_RATE * (1<<(i+FIRST_STEP));
setup_buffers(&p[i]);
p[i].period = -1;
}
if(start_portaudio()) return 1;
struct main_window w;
w.bfs = p;
w.old = NULL;
init_main_window(&w);
g_timeout_add_full(G_PRIORITY_LOW,100,(GSourceFunc)refresh,&w,NULL);
gtk_main();
return 0;
}
int main(int argc, char **argv)
{
gtk_init(&argc, &argv);
initialize_palette();
return run_interface();
}