📄 fourier_mode_funcs.c
字号:
#include "fft-spectra.h"#include <math.h>#define SB_TAGS_MARGIN 30 /* Margins for drawing the spectra */#define DELTA_ZOOM 0.1 /* How much will be scaled the zoom */#define DELTA_MOVE 0.05 /* How much will we move left or right */#define MAX_ZOOM 5GSList *linetags=NULL; /* Display custom vertical lines to see tones of interest. */static float ymax=0; /* The largest intensity contribution is needed for intensity_scale_mode. */extern PangoLayout *pango_layout; /* Pango for rendering text */static GdkGC /* Gdk Graphic contexts used for drawing: */ *gc_bg=NULL, /* .. background */ *gc_spectra=NULL, /* .. the spectra lines */ *gc_sb_bg=NULL, /* .. scalebar background */ *gc_sb_fg=NULL, /* .. text of pointer in scalebar */ *gc_sb_tags=NULL, /* .. scalebar numbers */ *gc_small_tics_lines=NULL, /* .. grid with smaller intervals */ *gc_large_tics_lines=NULL; /* .. grid with larger intervals */static GdkPoint *points=NULL; /* Points for drawing the spectra */static int /* Grid of equaly spaced frequency lines is made of two types: */ scalebar_small_dfreq, /* .. smaller intervals with dashed lines */ scalebar_large_dfreq; /* .. larger intervals with full lines */static int scalebar_small_tics_start_at_freq=0; /* Where to start with the frequency lines */int data_display_from=0, /* Zoom boundaries - range of data points which should be displayed */ data_display_to=0;static int ori_data_display_from, /* Save the orginal zoom position and restore it on user request */ ori_data_display_to;int intensity_scale_mode=INTENSITY_SCALE_FLEXIBLE; /* Whether to remember y scale of spectra (intensities) */static int logscale = 0; /* Scale the intensity logarithmically? */#define DISPLAY_CURVE 0 /* New name for the same thing: Data interpolation, the default should */#define DISPLAY_VLINES 1 /* be off, so that single check button may be used also for spectrogram mode. */static int display_type = DISPLAY_VLINES;inline float idata_to_pixel(float idata,float width){ return (idata-data_display_from)*width/(data_display_to-data_display_from+1);}inline float pixel_to_idata(float pixel,float width){ return pixel*(data_display_to-data_display_from+1)/width + data_display_from;}inline float pixel_to_freq(float pixel,float width){ return idata_to_freq(pixel_to_idata(pixel,width));}inline float freq_to_pixel(float freq,float width){ return idata_to_pixel(freq_to_idata(freq),width);}inline float dfreq_to_dpixel(float df,float width){ return freq_to_idata(df)*width/(data_display_to-data_display_from+1);}inline float freq_to_idata(float freq){ return freq/dfreq;}inline float idata_to_freq(float idata){ return idata*dfreq;}linetag_t *get_new_tag(float freq,char *label,char *color){ linetag_t *tag; MALLOC(tag,linetag_t,1); tag->freq = freq; tag->idata = freq_to_idata(freq); tag->label = label; tag->gc = get_gc(color); return tag;}/* Read the profile from the config file: - custom line tags - window dimensions - colors - original display range (but not the current one!)*/void fourier_read_profile(int *width, int *height){ char *color, *note; GSList *l; linetag_t *tag; float freq_from=0, freq_to=0, freq; /* Remove any existing tags.. */ while (linetags) { tag = (linetag_t*)linetags->data; /* Dont unref GdkGC before an analogue of get_gc() is ready. g_object_unref(tag->gc); */ free(tag); linetags = linetags->next; } /* Read the new tags.. */ if ( settings ) { l = sconf_get_gslist(settings,"linetags"); while (l) { note = (char*)l->data; l = l->next; color = l ? (char*)l->data : "#ffffff"; l = l->next; if ( !sconf_get_float("labels",note,&freq) ) sscanf(note,"%f",&freq); tag = get_new_tag(freq,note,color); linetags = g_slist_append(linetags,tag); } } /* Read the colors */ gc_bg = get_gc( sconf_get_string_or_die(settings,"spectra_bg_color") ); gc_spectra = get_gc( sconf_get_string_or_die(settings,"spectra_color") ); gc_sb_bg = get_gc( sconf_get_string_or_die(settings,"scalebar_bg_color") ); gc_sb_fg = get_gc( sconf_get_string_or_die(settings,"scalebar_pointer") ); gc_sb_tags = get_gc( sconf_get_string_or_die(settings,"scalebar_numbers") ); gc_large_tics_lines = get_gc( sconf_get_string_or_die(settings,"large_grid_color") ); gc_small_tics_lines = get_gc_new( sconf_get_string_or_die(settings,"small_grid_color") ); gdk_gc_set_line_attributes(gc_small_tics_lines,1,GDK_LINE_ON_OFF_DASH,GDK_CAP_NOT_LAST,GDK_JOIN_MITER); /* Window dimension */ if ( !sconf_get_int(settings,"spectra_width",width) ) exit_nicely("Could not read config value of \"%s/spectra_width\".\n", settings?settings:"default"); if ( !sconf_get_int(settings,"spectra_height",height) ) exit_nicely("Could not read config value of \"%s/spectra_height\".\n", settings?settings:"default"); /* The original display range*/ if ( !sconf_get_float(settings,"display_from",&freq_from) ) freq_from = 0; else freq_from = freq_to_idata(freq_from); if ( !sconf_get_float(settings,"display_to",&freq_to) ) freq_to = ndata_out-1; else freq_to = freq_to_idata(freq_to); if ( freq_from<0 || freq_from>=ndata_out ) freq_from=0; if ( freq_to<0 || freq_to>=ndata_out ) freq_to=ndata_out-1; ori_data_display_from = freq_from; ori_data_display_to = freq_to; if ( data_display_to==data_display_from ) default_zoom_restore();}void fourier_gtk_configure(void){ if (points) FREE(points); MALLOC(points,GdkPoint,main_width);}void fourier_main_draw(GdkPixmap *pixmap, int width,int height){ int ipixel,idata_min,idata_max,i,freq_tics; float max,scale,ymax_tmp=ymax,samples_per_pixel,min; GSList *l=linetags; linetag_t *tag; /* Clean the area */ gdk_draw_rectangle(pixmap,gc_bg, TRUE, 0,0,width,height); /* Draw vertical tic lines */ if ( view_grid ) { freq_tics = scalebar_small_tics_start_at_freq; ipixel = freq_to_pixel(freq_tics,width); while (ipixel<width) { if ( (freq_tics%scalebar_large_dfreq)==0 ) gdk_draw_line(pixmap,gc_large_tics_lines, ipixel,0,ipixel,height); else gdk_draw_line(pixmap,gc_small_tics_lines, ipixel,0,ipixel,height); freq_tics += scalebar_small_dfreq; ipixel = freq_to_pixel(freq_tics,width); } } /* Draw custom tags */ if ( view_custom_grid ) { while (l) { tag = (linetag_t *) l->data; if ( tag->idata>data_display_from && tag->idata<data_display_to ) { ipixel = floor( 0.5+idata_to_pixel(tag->idata,width) ); gdk_draw_line(pixmap,tag->gc, ipixel,0,ipixel,height); pango_layout_set_text(pango_layout,tag->label,strlen(tag->label)); //pango_layout_get_pixel_size(pango_layout, &tw,&th); gdk_draw_layout(pixmap, tag->gc, ipixel+5, 5*SB_MARGIN, pango_layout); } l = l->next; } } /* Get the sound data, unless reading was stopped by the user. */ if ( !(refresh_status&REFRESH_FFT_STOP) ) get_fft_sample(ndata_in, data, data_display_from,data_display_to,&min,&ymax_tmp,logscale); if ( intensity_scale_mode==INTENSITY_SCALE_CONSTANT ) { if ( ymax_tmp>ymax ) ymax=ymax_tmp; } else ymax=ymax_tmp; scale = ymax ? height/(ymax-min) : 0; /* Plot results */ samples_per_pixel = 1.0*(data_display_to-data_display_from+1)/width; if ( samples_per_pixel > 1 ) { /* More samples than pixels: For each pixel, go through the nearby data samples and select the one with the largest intensity */ for (ipixel=0; ipixel<width; ipixel++) { idata_min = pixel_to_idata(ipixel-0.5,width); idata_max = pixel_to_idata(ipixel+0.5,width); max = data[idata_min]; for (i=idata_min+1; i<idata_max; i++) if ( max<data[i] ) max=data[i]; points[ipixel].x = ipixel; points[ipixel].y = height-(max-min)*scale; } } else { /* More pixels than data samples: For each data sample calculate the corresponding pixel. */ for (i=data_display_from; i<=data_display_to; i++) { ipixel = idata_to_pixel(i,width); if ( ipixel<0 || ipixel>=width ) exit_nicely("FIXME: ipixel=%d!\n",ipixel); points[i-data_display_from].x = ipixel; points[i-data_display_from].y = height-(data[i]-min)*scale; } ipixel = data_display_to-data_display_from+1; } if ( display_type==DISPLAY_CURVE ) gdk_draw_lines(pixmap,gc_spectra,points,ipixel); else { /* Display vertical bars.. */ for (i=0; i<ipixel; i++) gdk_draw_line(pixmap,gc_spectra,points[i].x,points[i].y,points[i].x,height); }}void fourier_display_type_toggle(void){ if ( display_type == DISPLAY_CURVE ) display_type = DISPLAY_VLINES; else display_type = DISPLAY_CURVE;}void fourier_grid_toggle(void){ view_grid = view_grid ? 0 : 1;}void default_zoom_restore(void){ data_display_from = ori_data_display_from; data_display_to = ori_data_display_to; if ( mode==MODE_SPECTROGRAM ) spectrogram_clean_screen();}void default_zoom_event(float pressed_x, float released_x){ float from_x,to_x,samples_per_pixel; if (pressed_x<released_x) { from_x = pressed_x; to_x = released_x; } else { from_x = released_x; to_x = pressed_x; } samples_per_pixel = 1.0*(data_display_to-data_display_from+1)/main_width; from_x = samples_per_pixel*from_x + data_display_from; to_x = samples_per_pixel*to_x + data_display_from; if ( from_x<0 || from_x>=ndata_out ) from_x = 0; if ( to_x>=ndata_out || to_x<0 ) to_x = ndata_out-1; if ( to_x-from_x>MAX_ZOOM ) { data_display_from = from_x; data_display_to = to_x; } if ( mode==MODE_SPECTROGRAM ) spectrogram_clean_screen();}void default_move_left(void){ float shift; if ( data_display_from<=0 ) return; shift = DELTA_MOVE*(data_display_to-data_display_from+1); if ( shift<1 ) shift=1; if ( data_display_from<shift ) { data_display_to -= data_display_from; data_display_from = 0; } else { data_display_from -= shift; data_display_to -= shift; } if ( mode==MODE_SPECTROGRAM ) spectrogram_clean_screen();}void default_move_right(void){ float shift; if ( data_display_to>=ndata_out ) return; shift = DELTA_MOVE*(data_display_to-data_display_from+1); if ( shift<1 ) shift=1; if ( ndata_out-data_display_to<shift ) { data_display_from += ndata_out-data_display_to; data_display_to = ndata_out-1; } else { data_display_from += shift; data_display_to += shift; } if ( mode==MODE_SPECTROGRAM ) spectrogram_clean_screen();}void default_zoom_in(void){ float tmp; tmp = (data_display_to-data_display_from+1)*(DELTA_ZOOM/(1+2*DELTA_ZOOM)); if ( data_display_to-tmp-MAX_ZOOM<data_display_from+tmp ) return; data_display_from += tmp; data_display_to -= tmp; if ( mode==MODE_SPECTROGRAM ) spectrogram_clean_screen();}void default_zoom_out(void){ float tmp; tmp = DELTA_ZOOM*(data_display_to-data_display_from); if ( tmp<1 ) tmp=1; data_display_from -= tmp; data_display_to += tmp; if ( data_display_from<0 ) data_display_from = 0; if ( data_display_to>=ndata_out ) data_display_to = ndata_out-1; if ( mode==MODE_SPECTROGRAM ) spectrogram_clean_screen();}void default_zoom_out_total(void){ data_display_from = 0; data_display_to = ndata_out-1; if ( mode==MODE_SPECTROGRAM ) spectrogram_clean_screen();}void default_custom_grid_toggle(void){ view_custom_grid = view_custom_grid ? 0 : 1;}void default_scalebar_draw(GdkPixmap *pixmap, int width,int height){ char buf[10]; float ipixel,freq; int dw,n,tw,th,i; n = snprintf(buf,10,"%.0f",idata_to_freq(data_display_to)); pango_layout_set_text(pango_layout,buf,n); pango_layout_get_pixel_size(pango_layout, &tw,&th); /* Let's have the numbering spaced 5,10,15etc. */ scalebar_large_dfreq=1; for (i=0; i<10; i++) { dw = dfreq_to_dpixel(scalebar_large_dfreq,width); if ( dw>SB_TAGS_MARGIN+tw ) break; if ( i%2 ) { scalebar_large_dfreq *= 2; scalebar_small_dfreq = scalebar_large_dfreq/10; } else { scalebar_small_dfreq = scalebar_large_dfreq; scalebar_large_dfreq *= 5; } } /* Let the tics and scalebar numbers start on some neat rounded value. */ ipixel = tw/2; freq = pixel_to_freq(ipixel,width); if ( freq!=scalebar_large_dfreq ) freq = (int)freq-((int)freq)%scalebar_large_dfreq + scalebar_large_dfreq; scalebar_small_tics_start_at_freq = freq; while (freq_to_pixel(scalebar_small_tics_start_at_freq,width)>0) scalebar_small_tics_start_at_freq -= scalebar_small_dfreq; if ( freq_to_pixel(scalebar_small_tics_start_at_freq,width)<0 ) scalebar_small_tics_start_at_freq += scalebar_small_dfreq; gdk_draw_rectangle(pixmap,gc_sb_bg, TRUE, 0,0,width,height); do { ipixel = freq_to_pixel(freq,width); n = snprintf(buf,10,"%.0f",freq); pango_layout_set_text(pango_layout,buf,n); pango_layout_get_pixel_size(pango_layout, &tw,&th); gdk_draw_layout(pixmap, gc_sb_tags, ipixel-tw/2, SB_MARGIN, pango_layout); freq += scalebar_large_dfreq; } while ( ipixel+tw+SB_TAGS_MARGIN<width );}void default_scalebar_pointer_draw(GdkPixmap *pixmap, int width,int height,float x){ char buf[10]; float freq; int n,tw,th; freq = pixel_to_freq(x,width); n = snprintf(buf,10,"%.0f", freq); pango_layout_set_text(pango_layout,buf,n); pango_layout_get_pixel_size(pango_layout, &tw,&th); gdk_draw_rectangle(pixmap,gc_sb_bg, TRUE, x-tw/2-SB_MARGIN,0, tw+2*SB_MARGIN,height); gdk_draw_layout(pixmap, gc_sb_fg, x-tw/2, SB_MARGIN, pango_layout);}void fourier_logarithmic_intensity_toggle(void){ logscale = logscale ? 0 : 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -