Mercurial > audlegacy-plugins
view src/crossfade/monitor.c @ 3059:2e241e90494a
Import work in progress xmms-crossfade rewrite.
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Fri, 24 Apr 2009 05:57:35 -0500 |
parents | |
children |
line wrap: on
line source
/* * XMMS Crossfade Plugin * Copyright (C) 2000-2007 Peter Eisenlohr <peter@eisenlohr.org> * * based on the original OSS Output Plugin * Copyright (C) 1998-2000 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. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include <string.h> #include <gtk/gtk.h> #include "monitor.h" #include "configure.h" #include "cfgutil.h" #include "crossfade.h" #include "interface-2.0.h" #include "support-2.0.h" extern MUTEX buffer_mutex; GtkWidget *monitor_win = NULL; GtkWidget *monitor_display_drawingarea; GtkEntry *monitor_output_entry; GtkProgress *monitor_output_progress; static GtkLabel *monitor_position_label; static GtkLabel *monitor_total_label; static GtkLabel *monitor_left_label; static GtkLabel *monitor_output_time_label; static GtkLabel *monitor_output_time_sep; static GtkLabel *monitor_written_time_label; static gchar *default_position_str = NULL; static gchar *default_total_str = NULL; static gchar *default_left_str = NULL; static gchar *default_output_time_str = NULL; static gchar *default_written_time_str = NULL; static gboolean monitor_active = FALSE; static guint monitor_tag; static gint monitor_output_max; static gint monitor_closing; #define RUNNING 0 #define CLOSING 1 #define CLOSED 2 #define SMOD(x,n) (((x)<0)?((n)-(x))%(n):((x)%(n))) static void draw_wrapped(GtkWidget * widget, gint pos, gint width, GdkGC * gc) { GdkDrawable *win = widget->window; gint ww = widget->allocation.width; gint wh = widget->allocation.height; if (width <= 0) return; if (width < ww) { gint x = SMOD(pos, ww); if ((x + width) >= ww) { gdk_draw_rectangle(win, gc, TRUE, x, 0, ww - x, wh); gdk_draw_rectangle(win, gc, TRUE, 0, 0, width - (ww - x), wh); } else gdk_draw_rectangle(win, gc, TRUE, x, 0, width, wh); } else gdk_draw_rectangle(win, gc, TRUE, 0, 0, ww, wh); } gboolean on_monitor_display_drawingarea_expose_event(GtkWidget * widget, GdkEventExpose * event, gpointer user_data) { if (buffer && buffer->size && output_opened) { gint ww = widget->allocation.width; gint x1 = 0; gint x2 = buffer->used; gint x3 = buffer->used + buffer->mix; gint x4 = buffer->size; x1 = (gint64) (x1 + buffer->rd_index) * ww / buffer->size; x2 = (gint64) (x2 + buffer->rd_index) * ww / buffer->size; x3 = (gint64) (x3 + buffer->rd_index) * ww / buffer->size; x4 = (gint64) (x4 + buffer->rd_index) * ww / buffer->size; draw_wrapped(widget, x1, x2 - x1, widget->style->fg_gc[GTK_STATE_NORMAL]); draw_wrapped(widget, x2, x3 - x2, widget->style->white_gc); draw_wrapped(widget, x3, x4 - x3, widget->style->bg_gc[GTK_STATE_NORMAL]); } else gdk_window_clear_area(widget->window, event->area.x, event->area.y, event->area.width, event->area.height); return TRUE; } gboolean on_monitor_win_delete_event(GtkWidget * widget, GdkEvent * event, gpointer user_data) { /* V0.1.1 20000618: removed, didn't make much sense since it wasn't saved */ /* if (config) config->enable_monitor = FALSE; */ if (default_position_str) { g_free(default_position_str); default_position_str = NULL; } if (default_total_str) { g_free(default_total_str); default_total_str = NULL; } if (default_left_str) { g_free(default_left_str); default_left_str = NULL; } if (default_output_time_str) { g_free(default_output_time_str); default_output_time_str = NULL; } if (default_written_time_str) { g_free(default_written_time_str); default_written_time_str = NULL; } return (FALSE); /* FALSE: destroy window */ } void xfade_check_monitor_win() { gchar *str; if (config->enable_monitor) { if (!monitor_win && !(monitor_win = create_monitor_win())) { DEBUG(("[crossfade] check_monitor_win: error creating window!\n")); return; } #if 0 if (!GDK_IS_WINDOW(monitor_win)) { DEBUG(("[crossfade] check_monitor_win: GDK_IS_WINDOW(monitor_win) failed!\n")); DEBUG(("[crossfade] check_monitor_win: probably running in headless mode!\n")); monitor_win = NULL; return; } #endif /* automatically set monitor_win to NULL when window is destroyed */ gtk_signal_connect(GTK_OBJECT(monitor_win), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &monitor_win); /* show window */ gtk_widget_hide(GTK_WIDGET(lookup_widget(monitor_win, "monitor_seekeof_button"))); gtk_widget_show(monitor_win); /* get pointers to widgets (used by crossfade.c to update the monitor) */ monitor_display_drawingarea = lookup_widget(monitor_win, "monitor_display_drawingarea"); monitor_output_progress = GTK_PROGRESS(lookup_widget(monitor_win, "monitor_output_progress")); monitor_position_label = GTK_LABEL (lookup_widget(monitor_win, "monpos_position_label")); monitor_total_label = GTK_LABEL (lookup_widget(monitor_win, "monpos_total_label")); monitor_left_label = GTK_LABEL (lookup_widget(monitor_win, "monpos_left_label")); monitor_output_time_label = GTK_LABEL (lookup_widget(monitor_win, "monpos_output_time_label")); monitor_output_time_sep = GTK_LABEL (lookup_widget(monitor_win, "monpos_output_time_separator_label")); monitor_written_time_label = GTK_LABEL (lookup_widget(monitor_win, "monpos_written_time_label")); /* get default strings (displayed when monitor is stopped) */ if (!default_position_str) { gtk_label_get(monitor_position_label, &str); default_position_str = g_strdup(str); } if (!default_total_str) { gtk_label_get(monitor_total_label, &str); default_total_str = g_strdup(str); } if (!default_left_str) { gtk_label_get(monitor_left_label, &str); default_left_str = g_strdup(str); } if (!default_output_time_str) { gtk_label_get(monitor_output_time_label, &str); default_output_time_str = g_strdup(str); } if (!default_written_time_str) { gtk_label_get(monitor_written_time_label, &str); default_written_time_str = g_strdup(str); } /* force gtk_progress_configure */ monitor_output_max = 0; } else if (monitor_win) gtk_widget_destroy(monitor_win); } void label_set_text(GtkLabel * label, gchar * text) { gchar *old_text; gtk_label_get(label, &old_text); if (strcmp(old_text, text) == 0) return; gtk_label_set_text(label, text); } gint xfade_update_monitor(gpointer userdata) { GdkRectangle update_rect; /* HACK: (see xfade_stop_monitor() below) */ if (monitor_closing == CLOSED) return TRUE; if (monitor_closing == CLOSING) monitor_closing = CLOSED; if (!monitor_win) return TRUE; /* lock buffer (only if we need to) */ if (monitor_closing != CLOSED) MUTEX_LOCK(&buffer_mutex); gint output_time = the_op->output_time(); gint written_time = the_op->written_time(); gint output_used = written_time - output_time; /*** Mixing Buffer ***/ update_rect.x = 0; update_rect.y = 0; update_rect.width = monitor_display_drawingarea->allocation.width; update_rect.height = monitor_display_drawingarea->allocation.height; if (monitor_closing == CLOSED) gdk_window_clear_area(monitor_display_drawingarea->window, update_rect.x, update_rect.y, update_rect.width, update_rect.height); else gtk_widget_draw(monitor_display_drawingarea, &update_rect); /*** Output Buffer ***/ if (monitor_closing == CLOSED) { gtk_progress_configure(monitor_output_progress, 0, 0, 0); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(monitor_output_progress), " "); monitor_output_max = 0; } else { if (output_opened && the_op->buffer_playing()) { if (output_used < 0) output_used = 0; if (output_used > monitor_output_max) { monitor_output_max = output_used; gtk_progress_configure(monitor_output_progress, output_used, 0, monitor_output_max); } else gtk_progress_set_value(monitor_output_progress, output_used); { gchar temp[32]; g_snprintf(temp, sizeof(temp), "%d", output_used); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(monitor_output_progress), temp); } } else { gtk_progress_configure(monitor_output_progress, 0, 0, 0); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(monitor_output_progress), " "); monitor_output_max = 0; } } /*** Position ***/ if (!xfplayer_input_playing() || (monitor_closing == CLOSED)) { gtk_label_set_text(monitor_position_label, default_position_str); gtk_label_set_text(monitor_total_label, default_total_str); gtk_label_set_text(monitor_left_label, default_left_str); } else { gchar buffer[32]; gint position = output_time - output_offset; gint total = xfplaylist_current_length(); gint left = total - position; /* position */ g_snprintf(buffer, sizeof(buffer), position < 0 ? "-%d:%02d.%01d" : "%d:%02d.%01d", ABS(position) / 60000, ABS(position) / 1000 % 60, ABS(position) / 100 % 10); gtk_label_set_text(monitor_position_label, buffer); /* total */ if (total > 0) { g_snprintf(buffer, sizeof(buffer), "%d:%02d", total / 60000, total / 1000 % 60); gtk_label_set_text(monitor_total_label, buffer); } else label_set_text(monitor_total_label, default_total_str); /* left */ if (total > 0) { g_snprintf(buffer, sizeof(buffer), left < 0 ? "-%d:%02d" : "%d:%02d", ABS(left) / 60000, ABS(left) / 1000 % 60); gtk_label_set_text(monitor_left_label, buffer); } else label_set_text(monitor_left_label, default_left_str); } /* Output Plugin position */ if (monitor_closing == CLOSED) { gtk_widget_hide(GTK_WIDGET(monitor_output_time_label)); gtk_widget_hide(GTK_WIDGET(monitor_output_time_sep)); gtk_label_set_text(monitor_written_time_label, default_written_time_str); } else { gchar buffer[32]; /* check for output plugin bug -- diff should always be 0 */ gint diff = written_time - (gint) (output_streampos * 1000 / OUTPUT_BPS); if (diff) { gtk_widget_show(GTK_WIDGET(monitor_output_time_label)); gtk_widget_show(GTK_WIDGET(monitor_output_time_sep)); g_snprintf(buffer, sizeof(buffer), output_time < 0 ? "-%d:%02d.%03d" : "%d:%02d.%03d", ABS(diff) / 60000, ABS(diff) / 1000 % 60, ABS(diff) % 1000); gtk_label_set_text(monitor_output_time_label, buffer); } else { gtk_widget_hide(GTK_WIDGET(monitor_output_time_label)); gtk_widget_hide(GTK_WIDGET(monitor_output_time_sep)); } /* written_time */ g_snprintf(buffer, sizeof(buffer), written_time < 0 ? "-%d:%02d:%02d.%01d" : "%d:%02d:%02d.%01d", ABS(written_time) / 3600000, ABS(written_time) / 60000 % 60, ABS(written_time) / 1000 % 60, ABS(written_time) / 100 % 10); gtk_label_set_text(monitor_written_time_label, buffer); } /* unlock buffer */ if (monitor_closing != CLOSED) MUTEX_UNLOCK(&buffer_mutex); return TRUE; /* continue calling this function */ } void xfade_start_monitor() { if (monitor_active) return; monitor_output_max = 0; monitor_closing = RUNNING; monitor_active = TRUE; monitor_tag = gtk_timeout_add(UPDATE_INTERVAL, xfade_update_monitor, NULL); } void xfade_stop_monitor() { gint max_wait = UPDATE_INTERVAL / 10 + 1 + 1; /* round up / add safety */ if (!monitor_active) return; /* HACK, ugly HACK: force a final call of xfade_update_monitor */ monitor_closing = CLOSING; while ((monitor_closing == CLOSING) && (max_wait-- > 0)) xfade_usleep(10000); if (max_wait <= 0) DEBUG(("[crossfade] stop_monitor: timeout!\n")); /* stop calling xfade_update_monitor() */ gtk_timeout_remove(monitor_tag); monitor_active = FALSE; } #if defined(HAVE_INPUT_SEEK) void input_seek(int time); /* XMMS */ void on_monitor_seekeof_button_clicked(GtkButton *button, gpointer user_data) { gint total = xfplaylist_current_length(); gint offset = xfade_cfg_offset(&config->fc[FADE_CONFIG_XFADE]) - config->songchange_timeout; gint position = total + offset - 2500; if (position < 0) return; DEBUG(("[crossfade] monitor_seek_eof: total=%d offset=%d position=%d\n", total, offset, position)) input_seek(position/1000); /* XMMS */ } #else void on_monitor_seekeof_button_clicked(GtkButton *button, gpointer user_data) { } #endif