/* MSA spectrum analyzer * Copyright (C) 2000 Michal Kunikowski * * 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 #include #include #include // printf,... #include // atoi,... #include // strcpy,... #include "xmms/plugin.h" #include "xmms/configfile.h" #include "xmms/xmmsctrl.h" #include "msa.h" #include "msa_skin.h" #include "msa_config.h" #include "debug.h" #define MAX_NUM_BANDS 32 static GtkWidget *analyzerwin = NULL,*area; static GdkPixmap *draw_pixmap = NULL; static GdkPixmap *leds_off_pixmap = NULL, *leds_on_pixmap = NULL; static GdkGC *gc = NULL; static gint16 bar_heights[MAX_NUM_BANDS]; static gint16 peak_heights[MAX_NUM_BANDS]; static gint16 peak_delay[MAX_NUM_BANDS]; static gdouble scale; static gboolean drawingallowed = TRUE; msaconfig msacfg; msaskinconfig msaskincfg; // xmms version dependend extern GtkWidget *mainwin; extern GtkWidget *equalizerwin; extern GtkWidget *playlistwin; static struct { gint mainwin_x, mainwin_y, mainwin_w, mainwin_h; gboolean mainwin_visible; gint equalizerwin_x, equalizerwin_y, equalizerwin_w, equalizerwin_h; gboolean equalizerwin_visible; gint playlistwin_x, playlistwin_y, playlistwin_w, playlistwin_h; gboolean playlistwin_visible; } xmmswindowinfo; void update_xmmswindowinfo() { xmmswindowinfo.mainwin_visible = gdk_window_is_visible(mainwin->window); gdk_window_get_position(mainwin->window, &xmmswindowinfo.mainwin_x, &xmmswindowinfo.mainwin_y); gdk_window_get_size(mainwin->window, &xmmswindowinfo.mainwin_w, &xmmswindowinfo.mainwin_h); xmmswindowinfo.equalizerwin_visible = gdk_window_is_visible(equalizerwin->window); gdk_window_get_position(equalizerwin->window, &xmmswindowinfo.equalizerwin_x, &xmmswindowinfo.equalizerwin_y); gdk_window_get_size(equalizerwin->window, &xmmswindowinfo.equalizerwin_w, &xmmswindowinfo.equalizerwin_h); xmmswindowinfo.equalizerwin_visible = gdk_window_is_visible(equalizerwin->window); gdk_window_get_position(playlistwin->window, &xmmswindowinfo.playlistwin_x, &xmmswindowinfo.playlistwin_y); gdk_window_get_size(playlistwin->window, &xmmswindowinfo.playlistwin_w, &xmmswindowinfo.playlistwin_h); } // xmms version dependend void msa_dock(gint *x, gint *y, gint ox, gint oy, gint ow, gint oh) { gint w, h; gint snapd = msacfg.snap_distance; DPRINT(1, "msa [msa_dock]: dock: x=%d y=%d w=%d h=%d\n",ox,oy,ow,oh); w = msaskincfg.window_width; h = msaskincfg.window_height; if (*x + w > ox - snapd && *x + w < ox + snapd && *y > oy - h && *y < oy + oh) { *x = ox - w; if (*y > oy - snapd && *y < oy + snapd) *y = oy; if (*y + h > oy + oh - snapd && *y + h < oy + oh + snapd) *y = oy + oh - h; } if (*x > ox + ow - snapd && *x < ox + ow + snapd && *y > oy - h && *y < oy + oh) { *x = ox + ow; if (*y > oy - snapd && *y < oy + snapd) *y = oy; if (*y + h > oy + oh - snapd && *y + h < oy + oh + snapd) *y = oy + oh - h; } if (*y + h > oy - snapd && *y + h < oy + snapd && *x > ox - w && *x < ox + ow) { *y = oy - h; if (*x > ox - snapd && *x < ox + snapd) *x = ox; if (*x + w > ox + ow - snapd && *x + w < ox + ow + snapd) *x = ox + ow - w; } if (*y > oy + oh - snapd && *y < oy + oh + snapd && *x > ox - w && *x < ox + ow) { *y = oy + oh; if (*x > ox - snapd && *x < ox + snapd) *x = ox; if (*x + w > ox + ow - snapd && *x + w < ox + ow + snapd) *x = ox + ow - w; } } void set_peak_mode(int mode) { DPRINT(1, "msa [set_peak_mode]: %d\n",mode); if (msacfg.peak_mode == mode) return; msacfg.peak_mode = mode; msaconfig_update_peakmodebtn(); } void set_reverse_mode(gboolean state) { DPRINT(1, "msa [set_reverse_mode]: %s\n",state?"on":"off"); if (msacfg.reverse_mode == state) return; msacfg.reverse_mode = state; msaconfig_update_checkbutton_reversed(); set_suitable_analyzer_pixmaps(&leds_off_pixmap, &leds_on_pixmap); if (!msacfg.isplaying) return; gdk_draw_pixmap(draw_pixmap, gc, leds_off_pixmap, 0, 0, 0, 0, msaskincfg.window_width, msaskincfg.window_height); add_suitable_titlebar_to_pixmap(gc, draw_pixmap); } void set_mirror_mode(gboolean state) { DPRINT(1, "msa [set_mirror_mode]: %s\n",state?"on":"off"); if (msacfg.mirror_mode == state) return; msacfg.mirror_mode = state; msaconfig_update_checkbutton_mirrored(); set_suitable_analyzer_pixmaps(&leds_off_pixmap, &leds_on_pixmap); if (!msacfg.isplaying) return; gdk_draw_pixmap(draw_pixmap, gc, leds_off_pixmap, 0, 0, 0, 0, msaskincfg.window_width, msaskincfg.window_height); add_suitable_titlebar_to_pixmap(gc, draw_pixmap); } void unrefpixmap(GdkPixmap **pixmap) { if (*pixmap == NULL) return; gdk_pixmap_unref(*pixmap); *pixmap = NULL; } void unrefallpixmaps() { unrefpixmap(&draw_pixmap); } static void analyzer_init(void); static void analyzer_cleanup(void); static void analyzer_playback_start(void); static void analyzer_playback_stop(void); static void analyzer_render_freq(gint16 data[2][256]); static gint analyzerwin_move_x, analyzerwin_move_y; static gboolean analyzerwin_moving = FALSE; VisPlugin analyzer_vp = { NULL, NULL, 0, MSA_VERSION_STRING, 0, 1, analyzer_init, /* init */ analyzer_cleanup, /* cleanup */ msa_about, /* about */ msa_config, /* configure */ NULL, /* disable_plugin */ analyzer_playback_start, /* playback_start */ analyzer_playback_stop, /* playback_stop */ NULL, /* render_pcm */ analyzer_render_freq /* render_freq */ }; VisPlugin *get_vplugin_info(void) { return &analyzer_vp; } static void analyzer_destroy_cb(GtkWidget *w,gpointer data) { ConfigFile *cfg; gchar *fn; DPRINT(1, "msa [analyzer_destroy_cb]: analyzer_destroy_cb\n"); // save window position information fn = g_strconcat(g_get_home_dir(), "/.xmms/config", NULL); cfg = xmms_cfg_open_file(fn); if (!cfg) cfg = xmms_cfg_new(); xmms_cfg_write_int(cfg, "msa", "window_pos_x", msacfg.window_x); xmms_cfg_write_int(cfg, "msa", "window_pos_y", msacfg.window_y); xmms_cfg_write_file(cfg, fn); xmms_cfg_free(cfg); g_free(fn); analyzer_vp.disable_plugin(&analyzer_vp); } static void analyzerwin_press(GtkWidget * widget, GdkEventButton * event, gpointer callback_data) { DPRINT(1, "msa [analyzerwin_press]"); analyzerwin_move_x=event->x; analyzerwin_move_y=event->y; if (event->button == 1 && event->type == GDK_BUTTON_PRESS && event->x >= msaskincfg.exitbutton_x && event->x <= msaskincfg.exitbutton_x+msaskincfg.exitbutton_width && event->y >= msaskincfg.exitbutton_y && event->y <= msaskincfg.exitbutton_y+msaskincfg.exitbutton_height) { DPRINT(1, ": exit button\n"); analyzer_cleanup(); } else if (event->button == 1 && event->type == GDK_BUTTON_PRESS && event->x >= msaskincfg.menubutton_x && event->x <= msaskincfg.menubutton_x+msaskincfg.menubutton_width && event->y >= msaskincfg.menubutton_y && event->y <= msaskincfg.menubutton_y+msaskincfg.menubutton_height) { DPRINT(1, ": menu button\n"); msa_config(); } else if (event->button == 1 && event->type == GDK_BUTTON_PRESS && event->y <= msaskincfg.titlebar_height) { DPRINT(1, ": titlebar\n"); analyzerwin_moving = TRUE; msacfg.screen_width=gdk_screen_width(); msacfg.screen_height=gdk_screen_height(); // dock to xmms window code update_xmmswindowinfo(); // dock to xmms window code gdk_window_raise(analyzerwin->window); gdk_pointer_grab(analyzerwin->window, FALSE, GDK_BUTTON_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, GDK_NONE, GDK_NONE, GDK_CURRENT_TIME); } else if (event->button == 1 && event->type == GDK_BUTTON_PRESS) { DPRINT(1, ": first button\n"); set_peak_mode((msacfg.peak_mode+1)%3); } else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) { DPRINT(1, ": second button\n"); set_mirror_mode(!msacfg.mirror_mode); } else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { DPRINT(1, ": third button\n"); set_reverse_mode(!msacfg.reverse_mode); } } static void analyzerwin_motion(GtkWidget * widget, GdkEventMotion * event, gpointer callback_data) { DPRINT(1, "msa [analyzerwin_motion]\n"); if (analyzerwin_moving) { GdkModifierType modmask; gint mx, my, newx, newy; gint sd; // snap distance gint w; // window width gint h; // window height gint sw; // screen width gint sh; // screen height gdk_window_get_pointer(NULL, &mx, &my, &modmask); newx = mx - analyzerwin_move_x; newy = my - analyzerwin_move_y; sd = msacfg.snap_distance; sw = msacfg.screen_width; sh = msacfg.screen_height; w = msaskincfg.window_width; h = msaskincfg.window_height; // dock to screen border if (newx > -sd && newx < sd) newx = 0; if ((newx + w) > sw - sd && (newx + w) < sw + sd) newx = sw - w; if (newy > -sd && newy < sd) newy = 0; if ((newy + h) > sh - sd && (newy + h) < sh + sd) newy = sh - h; // dock to xmms windows - code if (xmmswindowinfo.mainwin_visible) msa_dock(&newx, &newy, xmmswindowinfo.mainwin_x, xmmswindowinfo.mainwin_y, xmmswindowinfo.mainwin_w, xmmswindowinfo.mainwin_h); if (xmmswindowinfo.equalizerwin_visible) msa_dock(&newx, &newy, xmmswindowinfo.equalizerwin_x, xmmswindowinfo.equalizerwin_y, xmmswindowinfo.equalizerwin_w, xmmswindowinfo.equalizerwin_h); if (xmmswindowinfo.playlistwin_visible) msa_dock(&newx, &newy, xmmswindowinfo.playlistwin_x, xmmswindowinfo.playlistwin_y, xmmswindowinfo.playlistwin_w, xmmswindowinfo.playlistwin_h); msacfg.window_x=newx; msacfg.window_y=newy; gdk_window_move(analyzerwin->window, newx, newy); } } static void analyzerwin_release(GtkWidget * widget, GdkEventButton * event, gpointer callback_data) { DPRINT(1, "msa [analyzerwin_release]\n"); gdk_pointer_ungrab(GDK_CURRENT_TIME); if (analyzerwin_moving && event->button == 1 && event->type == GDK_BUTTON_RELEASE) { analyzerwin_moving = FALSE; } } static void analyzerwin_focus_in(GtkWidget * widget, GdkEvent * event, gpointer callback_data) { DPRINT(1, "msa [analyzerwin_focus_in]\n"); msacfg.hasfocus = TRUE; if (!analyzerwin) return; add_suitable_titlebar_to_pixmap(gc, draw_pixmap); gdk_window_clear(area->window); } static void analyzerwin_focus_out(GtkWidget * widget, GdkEventButton * event, gpointer callback_data) { DPRINT(1, "msa [analyzerwin_focus_out]\n"); msacfg.hasfocus = FALSE; if (!analyzerwin) return; add_suitable_titlebar_to_pixmap(gc, draw_pixmap); gdk_window_clear(area->window); } static gboolean analyzerwin_keypress(GtkWidget * w, GdkEventKey * event, gpointer data) { DPRINT(1, "msa [analyzerwin_keypress]"); switch(event->keyval) { case GDK_Escape: // exit plugin analyzer_cleanup(); break; case GDK_r: set_mirror_mode(!msacfg.mirror_mode); break; case GDK_f: set_peak_mode((msacfg.peak_mode+1)%3); break; case GDK_q: if (msacfg.bar_falloff<10) { msacfg.bar_falloff++; msaconfig_update_barfalloffsc(); } DPRINT(1, ": inc: bar_falloff = %d",msacfg.bar_falloff); break; case GDK_a: if (msacfg.bar_falloff>1) { msacfg.bar_falloff--; msaconfig_update_barfalloffsc(); } DPRINT(1, ": dec: bar_spped = %d",msacfg.bar_falloff); break; case GDK_w: if (msacfg.peak_falloff<10) { msacfg.peak_falloff++; msaconfig_update_peakfalloffsc(); } DPRINT(1, ": inc: peak_spped = %d",msacfg.peak_falloff); break; case GDK_s: if (msacfg.peak_falloff>1) { msacfg.peak_falloff--; msaconfig_update_peakfalloffsc(); } DPRINT(1, ": dec: peak_spped = %d",msacfg.peak_falloff); break; case GDK_e: if (msacfg.peak_delay<50) { msacfg.peak_delay++; msaconfig_update_peakdelaysc(); } DPRINT(1, ": inc: peak_delay = %d",msacfg.peak_delay); break; case GDK_d: if (msacfg.peak_delay>0) { msacfg.peak_delay--; msaconfig_update_peakdelaysc(); } DPRINT(1, ": dec: peak_delay = %d",msacfg.peak_delay); break; case GDK_z: DPRINT(1, ": prev"); xmms_remote_playlist_prev(analyzer_vp.xmms_session); break; case GDK_x: DPRINT(1, ": play"); xmms_remote_play(analyzer_vp.xmms_session); break; case GDK_c: DPRINT(1, ": pause"); xmms_remote_pause(analyzer_vp.xmms_session); break; case GDK_v: DPRINT(1, ": stop"); xmms_remote_stop(analyzer_vp.xmms_session); break; case GDK_b: DPRINT(1, ": next"); xmms_remote_playlist_next(analyzer_vp.xmms_session); break; default: break; } DPRINT(1, "\n"); return TRUE; } // ******************************* SKIN ******************************* void setdefaultcfg(msaconfig *cfg) { cfg->snap_distance=10; cfg->screen_width=gdk_screen_width(); cfg->screen_height=gdk_screen_height(); }; void setskin(gboolean setlogo) { DPRINT(1, "msa [setskin]\n"); if (!analyzerwin) return; drawingallowed = FALSE; if (setlogo) { // draw logo set_logo_pixmap(gc, draw_pixmap); add_suitable_titlebar_to_pixmap(gc, draw_pixmap); } gdk_window_clear(area->window); // and then set skin set_default_skin(analyzerwin->window, gc); scale = msaskincfg.analyzer_height / log(256); unrefallpixmaps(); draw_pixmap = gdk_pixmap_new(analyzerwin->window, msaskincfg.window_width, msaskincfg.window_height, gdk_visual_get_best_depth()); gdk_window_set_back_pixmap(area->window, draw_pixmap, 0); gtk_widget_set_usize(analyzerwin, msaskincfg.window_width, msaskincfg.window_height); if (msacfg.isplaying) { set_suitable_analyzer_pixmaps(&leds_off_pixmap, &leds_on_pixmap); gdk_draw_pixmap(draw_pixmap, gc, leds_off_pixmap, 0, 0, 0, 0, msaskincfg.window_width, msaskincfg.window_height); } else if (!msacfg.isplaying) { set_logo_pixmap(gc, draw_pixmap); } add_suitable_titlebar_to_pixmap(gc, draw_pixmap); gdk_window_clear(area->window); drawingallowed = TRUE; } void load_msa_config() { ConfigFile *cfg; gchar *fn; gint i; gboolean b; gchar *s; fn = g_strconcat(g_get_home_dir(), "/.xmms/config", NULL); DPRINT(1, "msa [load_msa_config]: loading msa config from %s\n",fn); cfg = xmms_cfg_open_file(fn); if (cfg) { if ( xmms_cfg_read_int(cfg, "msa", "window_pos_x", &i) ) msacfg.window_x=i; else msacfg.window_x=0; if ( xmms_cfg_read_int(cfg, "msa", "window_pos_y", &i) ) msacfg.window_y=i; else msacfg.window_y=0; if ( xmms_cfg_read_int(cfg, "msa", "bar_falloff", &i) ) msacfg.bar_falloff=i; if ( xmms_cfg_read_int(cfg, "msa", "peak_mode", &i) ) msacfg.peak_mode=i; if ( xmms_cfg_read_int(cfg, "msa", "peak_falloff", &i) ) msacfg.peak_falloff=i; if ( xmms_cfg_read_int(cfg, "msa", "peak_delay", &i) ) msacfg.peak_delay=i; if ( xmms_cfg_read_boolean(cfg, "msa", "reverse_mode", &b) ) msacfg.reverse_mode=b; if ( xmms_cfg_read_boolean(cfg, "msa", "mirror_mode", &b) ) msacfg.mirror_mode=b; if ( xmms_cfg_read_string(cfg, "msa", "skin_dir", &s) ) { strcpy(msacfg.skindir, s); g_free(s); } else strcpy(msacfg.skindir, ""); if ( xmms_cfg_read_string(cfg, "msa", "skin_color", &s) ) { sscanf(s, "%02x%02x%02x-%02x%02x%02x-%02x%02x%02x-%02x%02x%02x", &msacfg.color[0][0], &msacfg.color[0][1], &msacfg.color[0][2], &msacfg.color[1][0], &msacfg.color[1][1], &msacfg.color[1][2], &msacfg.color[2][0], &msacfg.color[2][1], &msacfg.color[2][2], &msacfg.color[3][0], &msacfg.color[3][1], &msacfg.color[3][2]); g_free(s); } else { sscanf("000000-31350b-737b1b-ecfd37", "%02x%02x%02x-%02x%02x%02x-%02x%02x%02x-%02x%02x%02x", &msacfg.color[0][0], &msacfg.color[0][1], &msacfg.color[0][2], &msacfg.color[1][0], &msacfg.color[1][1], &msacfg.color[1][2], &msacfg.color[2][0], &msacfg.color[2][1], &msacfg.color[2][2], &msacfg.color[3][0], &msacfg.color[3][1], &msacfg.color[3][2]); } xmms_cfg_free(cfg); } g_free(fn); } void save_msa_config() { ConfigFile *cfg; gchar *fn, *color; fn = g_strconcat(g_get_home_dir(), "/.xmms/config", NULL); DPRINT(1, "msa [save_msa_config]: saving msa config in %s\n",fn); cfg = xmms_cfg_open_file(fn); if (!cfg) cfg = xmms_cfg_new(); xmms_cfg_write_int(cfg, "msa", "window_pos_x", msacfg.window_x); xmms_cfg_write_int(cfg, "msa", "window_pos_y", msacfg.window_y); xmms_cfg_write_int(cfg, "msa", "bar_falloff", msacfg.bar_falloff); xmms_cfg_write_int(cfg, "msa", "peak_mode", msacfg.peak_mode); xmms_cfg_write_int(cfg, "msa", "peak_falloff", msacfg.peak_falloff); xmms_cfg_write_int(cfg, "msa", "peak_delay", msacfg.peak_delay); xmms_cfg_write_boolean(cfg, "msa", "reverse_mode", msacfg.reverse_mode); xmms_cfg_write_boolean(cfg, "msa", "mirror_mode", msacfg.mirror_mode); xmms_cfg_write_string(cfg, "msa", "skin_dir", msacfg.skindir); color = g_strdup_printf("%02x%02x%02x-%02x%02x%02x-%02x%02x%02x-%02x%02x%02x", msacfg.color[0][0], msacfg.color[0][1], msacfg.color[0][2], msacfg.color[1][0], msacfg.color[1][1], msacfg.color[1][2], msacfg.color[2][0], msacfg.color[2][1], msacfg.color[2][2], msacfg.color[3][0], msacfg.color[3][1], msacfg.color[3][2]); xmms_cfg_write_string(cfg, "msa", "skin_color", color); g_free(color); xmms_cfg_write_file(cfg, fn); xmms_cfg_free(cfg); g_free(fn); } static void analyzer_init(void) { DPRINT(1, "msa [analyzer_init]\n"); if (analyzerwin) return; msacfg.bar_falloff = 2; msacfg.peak_mode = 1; msacfg.peak_delay = 20; msacfg.peak_falloff = 2; msacfg.reverse_mode = FALSE; setdefaultcfg(&msacfg); msaskin_setdefaultcfg(&msaskincfg); load_msa_config(); analyzerwin = gtk_window_new(GTK_WINDOW_DIALOG); gtk_window_set_title(GTK_WINDOW(analyzerwin), "XMMS MSA"); gtk_window_set_policy(GTK_WINDOW(analyzerwin), FALSE, FALSE, FALSE); gtk_widget_set_events(analyzerwin, GDK_FOCUS_CHANGE_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); gtk_widget_realize(analyzerwin); gdk_window_set_decorations(analyzerwin->window, 0); gtk_signal_connect(GTK_OBJECT(analyzerwin), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &analyzerwin); gtk_signal_connect(GTK_OBJECT(analyzerwin), "destroy", GTK_SIGNAL_FUNC(analyzer_destroy_cb), NULL); gtk_signal_connect(GTK_OBJECT(analyzerwin), "button_press_event", GTK_SIGNAL_FUNC(analyzerwin_press), NULL); gtk_signal_connect(GTK_OBJECT(analyzerwin), "button_release_event", GTK_SIGNAL_FUNC(analyzerwin_release), NULL); gtk_signal_connect(GTK_OBJECT(analyzerwin), "motion_notify_event", GTK_SIGNAL_FUNC(analyzerwin_motion), NULL); gtk_signal_connect(GTK_OBJECT(analyzerwin), "focus_in_event", GTK_SIGNAL_FUNC(analyzerwin_focus_in), NULL); gtk_signal_connect(GTK_OBJECT(analyzerwin), "focus_out_event", GTK_SIGNAL_FUNC(analyzerwin_focus_out), NULL); gtk_signal_connect(GTK_OBJECT(analyzerwin), "key-press-event", GTK_SIGNAL_FUNC(analyzerwin_keypress), NULL); area = gtk_drawing_area_new(); gtk_container_add(GTK_CONTAINER(analyzerwin), area); gtk_widget_realize(area); gc = gdk_gc_new(analyzerwin->window); // setwindowsizeandallpixmaps(); setskin(TRUE); set_logo_pixmap(gc, draw_pixmap); add_suitable_titlebar_to_pixmap(gc, draw_pixmap); gdk_window_set_back_pixmap(area->window, draw_pixmap, 0); gdk_window_clear(analyzerwin->window); gdk_window_clear(area->window); gtk_widget_show(area); gtk_widget_show(analyzerwin); gdk_window_move(analyzerwin->window, msacfg.window_x, msacfg.window_y); } static void analyzer_cleanup(void) { DPRINT(1, "msa [analyzer_cleanup]\n"); if (analyzerwin) gtk_widget_destroy(analyzerwin); if (gc) { gdk_gc_unref(gc); gc = NULL; } msaskin_unref_skin_pixmaps(); unrefallpixmaps(); } static void analyzer_playback_start(void) { DPRINT(1, "msa [analyzer_playback_start]\n"); drawingallowed = TRUE; msacfg.isplaying = TRUE; if (analyzerwin) { set_suitable_analyzer_pixmaps(&leds_off_pixmap, &leds_on_pixmap); gdk_draw_pixmap(draw_pixmap, gc, leds_off_pixmap, 0, 0, 0, 0, msaskincfg.window_width, msaskincfg.window_height); add_suitable_titlebar_to_pixmap(gc, draw_pixmap); gdk_window_clear(area->window); } } static void analyzer_playback_stop(void) { DPRINT(1, "msa [analyzer_playback_stop]\n"); drawingallowed = FALSE; msacfg.isplaying = FALSE; if (GTK_WIDGET_REALIZED(area)) { set_logo_pixmap(gc, draw_pixmap); add_suitable_titlebar_to_pixmap(gc, draw_pixmap); gdk_window_clear(area->window); } } static gboolean draw_func(gpointer data) { gint i; gint bar_width; if (!analyzerwin) return FALSE; GDK_THREADS_ENTER(); gdk_draw_pixmap(draw_pixmap, gc, leds_off_pixmap, msaskincfg.analyzer_x, msaskincfg.analyzer_y, msaskincfg.analyzer_x, msaskincfg.analyzer_y, msaskincfg.analyzer_width, msaskincfg.analyzer_height); bar_width = msaskincfg.analyzer_width / msaskincfg.num_bands; for (i = 0; i < msaskincfg.num_bands; i++) { gint bar_height = bar_heights[i]; gint peak_height = peak_heights[i]; gint x, bar_src_y, bar_dst_y, peak_y; gint mir_bar_dst_y=0, mir_bar_src_y=0, mir_bar_height=0, mir_peak_height=0, mir_peak_y=0; x = msaskincfg.analyzer_x + i * bar_width; if (msacfg.mirror_mode) { // mirror mir_bar_height = bar_height/3; mir_peak_height = peak_height/3; bar_height = (2*bar_height)/3; peak_height = (2*peak_height)/3; } if (!msacfg.reverse_mode) { /* normal */ bar_src_y=bar_dst_y = msaskincfg.analyzer_y + msaskincfg.analyzer_height - bar_height; peak_y = msaskincfg.analyzer_y + msaskincfg.analyzer_height - peak_height; if (msacfg.mirror_mode) { /* mirror */ gint analyzer_height13 = msaskincfg.analyzer_height/3; gint analyzer_height23 = (2*msaskincfg.analyzer_height)/3; bar_src_y=bar_dst_y = bar_dst_y - analyzer_height13; peak_y = peak_y - analyzer_height13; mir_bar_src_y=mir_bar_dst_y = msaskincfg.analyzer_y + analyzer_height23; mir_peak_y = msaskincfg.analyzer_y + analyzer_height23 + mir_peak_height; } } else { /* reversed */ bar_src_y=bar_dst_y = msaskincfg.analyzer_y; peak_y = msaskincfg.analyzer_y+peak_height; if (msacfg.mirror_mode) { /* mirror */ mir_bar_src_y=mir_bar_dst_y = msaskincfg.analyzer_y + msaskincfg.analyzer_height - mir_bar_height; mir_peak_y = msaskincfg.analyzer_y + msaskincfg.analyzer_height - mir_peak_height; } } // draw bars and peaks gdk_draw_pixmap(draw_pixmap, gc, leds_on_pixmap, x, bar_src_y, x, bar_dst_y, bar_width, bar_height); if (msacfg.peak_mode > 0 && peak_height > 0) gdk_draw_pixmap(draw_pixmap, gc, leds_on_pixmap, x, peak_y, x, peak_y, bar_width, msaskincfg.peak_height); // draw mirror of bars and peaks if (msacfg.mirror_mode) { /* mirror */ gdk_draw_pixmap(draw_pixmap, gc, leds_on_pixmap, x, mir_bar_src_y, x, mir_bar_dst_y, bar_width, mir_bar_height); if (msacfg.peak_mode > 0 && peak_height > 0) gdk_draw_pixmap(draw_pixmap, gc, leds_on_pixmap, x, mir_peak_y, x, mir_peak_y, bar_width, msaskincfg.peak_height); } } gdk_window_clear(area->window); GDK_THREADS_LEAVE(); return TRUE; } static void analyzer_render_freq(gint16 data[2][256]) { gint xscale16[] = { 0, 1, 2, 3, 5, 7, 10, 14, 20, 28, 40, 54, 74,101,137,187,255}; gint xscale32[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 16, 18, 20, 24, 28, 34, 40, 47, 54, 64, 74, 87,101,119,137,162,187,221,255 }; gint *xscale; gint i, c; gint y; if (!analyzerwin) return; if (!drawingallowed) return; if (msaskincfg.num_bands==16) xscale=xscale16; else if (msaskincfg.num_bands==32) xscale=xscale32; else { printf("msa [analyzer_render_freq]: fatal: num_bands!=16 or 32\n"); msaskincfg.num_bands=32; xscale=xscale32; } for (i = 0; i < msaskincfg.num_bands; i++) { // y = max ( data[xscale[i]], ..., data[xscale[i+1]] ) for (c = xscale[i], y = 0; c < xscale[i+1]; c++) { if (data[0][c] > y) y = data[0][c]; } y >>= 7; if (y != 0) { y = (gint)(log(y) * scale); if (y > msaskincfg.analyzer_height - 1) y = msaskincfg.analyzer_height - 1; } if (y > bar_heights[i]) bar_heights[i] = y; else { bar_heights[i] -= msacfg.bar_falloff; if (bar_heights[i]<0) bar_heights[i] = 0; } if (msacfg.peak_mode > 0) { if (y > peak_heights[i]) { peak_heights[i]=y; peak_delay[i]=msacfg.peak_delay; } else if (peak_heights[i] >= 0) { if (peak_delay[i] > 0) peak_delay[i]--; else if (msacfg.peak_mode == 1) { peak_heights[i]-=msacfg.peak_falloff; if (peak_heights[i] < 0) peak_heights[i]=-1; } else { peak_heights[i]+=msacfg.peak_falloff; if (peak_heights[i] > msaskincfg.analyzer_height) peak_heights[i]=-1; } } } } draw_func(NULL); return; }