Mercurial > audlegacy-plugins
view src/spectrum/spectrum.c @ 166:a118245b88c7 trunk
[svn] - use a quantized variance instead of a fast fft sum for beat detection with thresholding
author | nenolod |
---|---|
date | Tue, 31 Oct 2006 22:09:04 -0800 |
parents | 51f5b9cc0dc3 |
children | 2cf4d0182a86 |
line wrap: on
line source
/* Spectrum Analyzer Visualization Plugin for Audacious * * Copyright (C) 2006 William Pitcock * Copyright (C) 1998-2001 Vágvölgyi Attila, Peter Alm, Mikael Alm, * Olle Hallnas, Thomas Nilsson and 4Front Technologies * * This program 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 of the License, or * (at your option) any later version. * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include <gtk/gtk.h> #include <math.h> #include <audacious/plugin.h> #include <audacious/util.h> #include "logo.xpm" /* WIDTH should be kept 256, this is the hardwired resolution of the spectrum given by XMMS */ #define WIDTH 256 /* HEIGHT can be modified at your pleasure */ #define HEIGHT 128 /* Linearity of the amplitude scale (0.5 for linear, keep in [0.1, 0.9]) */ #define d 0.33 /* Time factor of the band dinamics. 3 means that the coefficient of the last value is half of the current one's. (see source) */ #define tau 3 /* Factor used for the diffusion. 4 means that half of the height is added to the neighbouring bars */ #define dif 4 static GtkWidget *window = NULL,*area; static GdkPixmap *bg_pixmap = NULL, *draw_pixmap = NULL, *bar = NULL; static GdkGC *gc = NULL; static gint16 bar_heights[WIDTH]; /*static gint timeout_tag;*/ static gdouble scale, x00, y00; static void fsanalyzer_init(void); static void fsanalyzer_cleanup(void); static void fsanalyzer_playback_start(void); static void fsanalyzer_playback_stop(void); static void fsanalyzer_render_freq(gint16 data[2][256]); VisPlugin fsanalyzer_vp = { NULL, NULL, 0, "Spectrum Analyzer " VERSION, 0, 1, fsanalyzer_init, /* init */ fsanalyzer_cleanup, /* cleanup */ NULL, /* about */ NULL, /* configure */ NULL, /* disable_plugin */ fsanalyzer_playback_start, /* playback_start */ fsanalyzer_playback_stop, /* playback_stop */ NULL, /* render_pcm */ fsanalyzer_render_freq /* render_freq */ }; VisPlugin *get_vplugin_info(void) { return &fsanalyzer_vp; } static void fsanalyzer_destroy_cb(GtkWidget *w,gpointer data) { fsanalyzer_vp.disable_plugin(&fsanalyzer_vp); } static void fsanalyzer_init(void) { GdkColor color; int i; if(window) return; window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window),"Spectrum Analyzer"); gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE); gtk_widget_realize(window); bg_pixmap = gdk_pixmap_create_from_xpm_d(window->window,NULL,NULL,logo_xpm); gdk_window_set_back_pixmap(window->window,bg_pixmap,0); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(fsanalyzer_destroy_cb),NULL); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_widget_destroyed), &window); gtk_widget_set_size_request(GTK_WIDGET(window), WIDTH, HEIGHT); gc = gdk_gc_new(window->window); draw_pixmap = gdk_pixmap_new(window->window,WIDTH,HEIGHT,gdk_rgb_get_visual()->depth); bar = gdk_pixmap_new(window->window,25, HEIGHT, gdk_rgb_get_visual()->depth); for(i = 0; i < HEIGHT / 2; i++) { color.red = 0xFFFF; color.green = ((i * 255) / (HEIGHT / 2)) << 8; color.blue = 0; gdk_color_alloc(gdk_colormap_get_system(),&color); gdk_gc_set_foreground(gc,&color); gdk_draw_line(bar,gc,0,i,24,i); } for(i = 0; i < HEIGHT / 2; i++) { color.red = (255 - ((i * 255) / (HEIGHT / 2))) <<8; color.green = 0xFFFF; color.blue = 0; gdk_color_alloc(gdk_colormap_get_system(),&color); gdk_gc_set_foreground(gc,&color); gdk_draw_line(bar,gc,0,i + (HEIGHT / 2),24,i + (HEIGHT / 2)); } scale = HEIGHT / ( log((1 - d) / d) * 2 ); x00 = d*d*32768.0/(2 * d - 1); y00 = -log(-x00) * scale; /* d=0.2, HEIGHT=128 scale = 46.1662413084; x00 = -2184.53333333; y00 = -354.979500941; */ gdk_color_black(gdk_colormap_get_system(),&color); gdk_gc_set_foreground(gc,&color); area = gtk_drawing_area_new(); gtk_container_add(GTK_CONTAINER(window),area); gtk_widget_realize(area); gdk_window_set_back_pixmap(area->window,bg_pixmap,0); gtk_widget_show(area); gtk_widget_show(window); gdk_window_clear(window->window); gdk_window_clear(area->window); } static void fsanalyzer_cleanup(void) { if(window) { gtk_widget_destroy(window); } if(gc) { gdk_gc_unref(gc); gc = NULL; } if(bg_pixmap) { gdk_pixmap_unref(bg_pixmap); bg_pixmap = NULL; } if(draw_pixmap) { gdk_pixmap_unref(draw_pixmap); draw_pixmap = NULL; } if(bar) { gdk_pixmap_unref(bar); bar = NULL; } } static gint draw_func(gpointer data) { gint i; /* FIXME: should allow spare redrawing like the vis. in the main window */ if(!window) { /* timeout_tag = 0;*/ return FALSE; } GDK_THREADS_ENTER(); gdk_draw_rectangle(draw_pixmap, gc, TRUE, 0, 0, WIDTH, HEIGHT); for(i = 0; i < WIDTH; i++) gdk_draw_pixmap(draw_pixmap, gc, bar, 0, HEIGHT-1-bar_heights[i], i, HEIGHT-1-bar_heights[i], 1, bar_heights[i]); gdk_window_clear(area->window); GDK_THREADS_LEAVE(); return TRUE; } static void fsanalyzer_playback_start(void) { if(window) { gdk_window_set_back_pixmap(area->window,draw_pixmap,0); gdk_window_clear(area->window); } } static void fsanalyzer_playback_stop(void) { if(GTK_WIDGET_REALIZED(area)) { gdk_window_set_back_pixmap(area->window,bg_pixmap,0); gdk_window_clear(area->window); } } static void fsanalyzer_render_freq(gint16 data[2][256]) { gint i; gdouble y; if(!window) return; /* FIXME: can anything taken out of the main thread? */ for (i = 0; i < WIDTH; i++) { y = (gdouble)data[0][i] * (i + 1); /* Compensating the energy */ y = ( log(y - x00) * scale + y00 ); /* Logarithmic amplitude */ y = ( (dif-2)*y + /* FIXME: conditionals should be rolled out of the loop */ (i==0 ? y : bar_heights[i-1]) + (i==WIDTH-1 ? y : bar_heights[i+1])) / dif; /* Add some diffusion */ y = ((tau-1)*bar_heights[i] + y) / tau; /* Add some dynamics */ bar_heights[i] = (gint16)y; } draw_func(NULL); return; }