⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spectrogram_mode_funcs.c

📁 linux下的FFT 频谱分析
💻 C
字号:
#include <math.h>#include "fft-spectra.h"#include "image.h"#define NSILENCE 20static float ymax=0,ymin=1e40;          /* Remember maximal and minimal intensity for plotting with a constant scale */static float *silence_data=NULL,        /* Remember a silence noise - a sample of FFT data acquired                                             in silence for INTENSITY_SCALE_SMART mode */                silence_threshold=0;    /* FFT sample with smaller correlation will be interpreted as a signal */static int silence_nacquire=0;          /* Use this many FFT samples for learning the silence noise. (Will be set                                            once to nonzero value and decremented untill zero */static int current_y = 0;               /* The position in the main_pixmap. */static image_t main_img = {0,0,NULL};   /* Few image lines for the spectrogram flow */static GdkPixmap *main_pixmap = NULL;static GdkGC     *gc_line=NULL,    *gc_bg=NULL,    *gc_silent=NULL; static color_t    *color_bg=NULL;static int interpolate_missing_data_points=0;static int logscale = 0;                /* Scale the intensity logarithmically? */extern GSList *linetags;                /* Display custom vertical lines to see tones of interest. */extern int data_display_from,           /* Zoom boundaries - range of data points which should be displayed */            data_display_to;extern PangoLayout *pango_layout;       /* Pango for rendering text */void spectrogram_read_profile(int *width, int *height){    /* Eh, not very nice, but it is no performance problem and saves typing:        Reuse the code of spectra display mode to read linetags etc.        Do not care about reading twice the colors and window dimensions.    */    fourier_read_profile(width,height);    if (!color_bg)        color_bg = get_color( sconf_get_string_or_die(settings,"spectrogram_bg_color") );    gc_bg     = get_gc( sconf_get_string_or_die(settings,"spectrogram_bg_color") );    gc_line   = get_gc( sconf_get_string_or_die(settings,"spectrogram_line") );    gc_silent = get_gc( sconf_get_string_or_die(settings,"scalebar_pointer") );    if ( !sconf_get_int(settings,"spectrogram_width",width) )        exit_nicely("Could not read config value of \"%s/spectrogram_width\".\n", settings?settings:"default");    if ( !sconf_get_int(settings,"spectrogram_height",height) )        exit_nicely("Could not read config value of \"%s/spectrogram_height\".\n", settings?settings:"default");}void spectrogram_gtk_configure(GtkWidget *widget){    if ( main_img.data && main_width!=main_img.width )        FREE(main_img.data);    if ( !main_img.data )    {        main_img.width  = main_width;        main_img.height = 1;        MALLOC(main_img.data,guchar,3*main_img.width*main_img.height);    }}/* The spectrogram mode does not refresh the whole screen,    but only a single line. It must be told explicitly     to clean the screen and therefore we need to remember    the main_pixmap pointer.*/void spectrogram_set_main_pixmap(GdkPixmap *pixmap){    main_pixmap = pixmap;}void spectrogram_clean_screen(void){    int w,h;    if ( main_img.data && color_bg )        image_fill_rectangle(&main_img,color_bg, 0,0,main_img.width,main_img.height);    if (main_pixmap && gc_bg)    {        gdk_drawable_get_size(main_pixmap,&w,&h);        gdk_draw_rectangle(main_pixmap,gc_bg, TRUE, 0,0,w,h);    }    current_y = 0;    spectrogram_init_intensity();}void spectrogram_init_intensity(void){    if ( intensity_scale_mode==INTENSITY_SCALE_CONSTANT )    {        ymax = 0;        ymin = 1e40;    }    if ( intensity_scale_mode==INTENSITY_SCALE_SMART )    {        silence_nacquire=NSILENCE;        silence_threshold=0;    }}inline void set_color_grade(int num, guchar *ptr){    if ( num<255 )    {        *ptr     = 0;        *(ptr+1) = 0;        *(ptr+2) = num;    }    else if ( num<2*255 )    {        *ptr     = 0;        *(ptr+1) = num-255;        *(ptr+2) = 2*255-num;    }    else if ( num<3*255 )    {        *ptr     = num-2*255;        *(ptr+1) = 3*255-num;        *(ptr+2) = 0;    }    else    {        *ptr     = 255;        *(ptr+1) = num-3*255;        *(ptr+2) = num-3*255;    }}void spectrogram_draw_side_scalebar(GdkPixmap *pixmap, int width,int height){    int ipixel, j;    float tmp;    guchar buf[width*3];    for (ipixel=0; ipixel<height; ipixel++)    {        tmp = (height-ipixel)*4*255.0/height;        for (j=0; j<width; j++)            set_color_grade(tmp, buf+j*3);        gdk_draw_rgb_image(pixmap, gc_bg,0,ipixel,width,1,GDK_RGB_DITHER_MAX,buf,width*3);    }}float calc_data_correlation(float *data1,float *data2,int ndata, int from, int to){    float coeff=0, tmp, *end1_ptr;    int n;    n = to-from+1;    data1 += from;    data2 += from;    end1_ptr = &(data1[n]);    while ( end1_ptr>data1 )    {        tmp = *data1 - *data2;        coeff += tmp*tmp/n;        data1++;        data2++;    }    return coeff;}void spectrogram_main_draw(GdkPixmap *pixmap, int width,int height){    float ymin_tmp,ymax_tmp,tmp,scale,samples_per_pixel,max,color,color_prev,dcolor,coef;    int idx,i,j,ipixel,ipixel_prev,idata_min,idata_max,tw,th;    GSList *l=linetags;    linetag_t *tag;    /* Get the data */    if ( !(refresh_status&REFRESH_FFT_STOP) )    {        get_fft_sample(ndata_in, data, data_display_from,data_display_to,&ymin_tmp,&ymax_tmp,logscale);        if ( intensity_scale_mode==INTENSITY_SCALE_FLEXIBLE )        {            ymax = ymax_tmp;            ymin = ymin_tmp;        }        else        {            if ( ymax_tmp>ymax ) ymax = ymax_tmp;            if ( ymin_tmp<ymin ) ymin = ymin_tmp;                        if ( intensity_scale_mode==INTENSITY_SCALE_CONSTANT )            {                ymax_tmp = ymax;                ymin_tmp = ymin;            }            else    /* INTENSITY_SCALE_SMART */            {                if (!silence_data)                 {                    MALLOC(silence_data,float,ndata_out);                    silence_nacquire = NSILENCE;                    memcpy(silence_data,data,ndata_out*sizeof(float));                }                                coef = calc_data_correlation(data,silence_data,ndata_out,data_display_from,data_display_to);                if ( silence_nacquire>0 )                {                    silence_nacquire--;                    if ( silence_threshold<coef ) silence_threshold=coef;                    ymax_tmp = ymax;                }                else if ( silence_threshold*2>coef )                    ymax_tmp = ymax;            }        }    }    scale = 4*255/(ymax_tmp-ymin_tmp);    /* Plot results */    samples_per_pixel = 1.0*(data_display_to-data_display_from+1)/width;    if ( samples_per_pixel > 1 )    {        idx = 0;        /* 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];            tmp = scale*(max-ymin_tmp);            set_color_grade(tmp, main_img.data+idx);            idx+=3;        }    }    else    {        /* More pixels than data samples: For each data sample calculate the            corresponding pixel. */        if (interpolate_missing_data_points)        {            ipixel = idata_to_pixel(data_display_from,width);            color  = scale*(data[data_display_from]-ymin_tmp);            for (i=data_display_from; i<=data_display_to; i++)            {                color_prev  = color;                ipixel_prev = ipixel;                ipixel = idata_to_pixel(i,width);                color  = scale*(data[i]-ymin_tmp);                dcolor = (color-color_prev)/(ipixel-ipixel_prev);                for (j=ipixel_prev+1; j<=ipixel; j++)                {                    if ( j<0 || j>=main_img.width ) exit_nicely("FIXME: ipixel=%d!\n",j);                    color_prev += dcolor;                    set_color_grade(color_prev, &(main_img.data[3*j]));                }            }        }        else        {            for (i=data_display_from; i<=data_display_to; i++)            {                ipixel = idata_to_pixel(i,width);                if ( ipixel<0 || ipixel>=main_img.width ) exit_nicely("FIXME: ipixel=%d!\n",ipixel);                color  = scale*(data[i]-ymin_tmp);                set_color_grade(color, &(main_img.data[3*ipixel]));            }        }    }    gdk_draw_rgb_image(pixmap, gc_bg,0,current_y, width,1,GDK_RGB_DITHER_MAX,main_img.data,width*3);    /* 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_rectangle(pixmap,gc_bg,TRUE,ipixel+4,5*SB_MARGIN-1,tw+2,th+2);                gdk_draw_layout(pixmap, tag->gc, ipixel+5, 5*SB_MARGIN, pango_layout);            }            l = l->next;        }    }    if ( ++current_y==height ) current_y = 0;    gdk_draw_line(pixmap, silence_nacquire>0? gc_silent:gc_line,0,current_y, width,current_y);}void spectrogram_interpolate_toggle(void){    interpolate_missing_data_points = interpolate_missing_data_points ? 0 : 1;    if (!interpolate_missing_data_points)        image_fill_rectangle(&main_img,color_bg, 0,0,main_img.width,main_img.height);}void spectrogram_logarithmic_intensity_toggle(void){    logscale = logscale ? 0 : 1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -