Mercurial > audlegacy-plugins
comparison 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 |
comparison
equal
deleted
inserted
replaced
3058:2e649bf16ebc | 3059:2e241e90494a |
---|---|
1 /* | |
2 * XMMS Crossfade Plugin | |
3 * Copyright (C) 2000-2007 Peter Eisenlohr <peter@eisenlohr.org> | |
4 * | |
5 * based on the original OSS Output Plugin | |
6 * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies | |
7 * | |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |
21 * USA. | |
22 */ | |
23 | |
24 #ifdef HAVE_CONFIG_H | |
25 # include "config.h" | |
26 #endif | |
27 | |
28 #include <string.h> | |
29 #include <gtk/gtk.h> | |
30 | |
31 #include "monitor.h" | |
32 #include "configure.h" | |
33 #include "cfgutil.h" | |
34 #include "crossfade.h" | |
35 | |
36 #include "interface-2.0.h" | |
37 #include "support-2.0.h" | |
38 | |
39 extern MUTEX buffer_mutex; | |
40 | |
41 GtkWidget *monitor_win = NULL; | |
42 GtkWidget *monitor_display_drawingarea; | |
43 GtkEntry *monitor_output_entry; | |
44 GtkProgress *monitor_output_progress; | |
45 | |
46 static GtkLabel *monitor_position_label; | |
47 static GtkLabel *monitor_total_label; | |
48 static GtkLabel *monitor_left_label; | |
49 static GtkLabel *monitor_output_time_label; | |
50 static GtkLabel *monitor_output_time_sep; | |
51 static GtkLabel *monitor_written_time_label; | |
52 | |
53 static gchar *default_position_str = NULL; | |
54 static gchar *default_total_str = NULL; | |
55 static gchar *default_left_str = NULL; | |
56 static gchar *default_output_time_str = NULL; | |
57 static gchar *default_written_time_str = NULL; | |
58 | |
59 static gboolean monitor_active = FALSE; | |
60 static guint monitor_tag; | |
61 static gint monitor_output_max; | |
62 static gint monitor_closing; | |
63 | |
64 #define RUNNING 0 | |
65 #define CLOSING 1 | |
66 #define CLOSED 2 | |
67 | |
68 #define SMOD(x,n) (((x)<0)?((n)-(x))%(n):((x)%(n))) | |
69 | |
70 | |
71 static void | |
72 draw_wrapped(GtkWidget * widget, gint pos, gint width, GdkGC * gc) | |
73 { | |
74 GdkDrawable *win = widget->window; | |
75 | |
76 gint ww = widget->allocation.width; | |
77 gint wh = widget->allocation.height; | |
78 | |
79 if (width <= 0) | |
80 return; | |
81 | |
82 if (width < ww) | |
83 { | |
84 gint x = SMOD(pos, ww); | |
85 if ((x + width) >= ww) | |
86 { | |
87 gdk_draw_rectangle(win, gc, TRUE, x, 0, ww - x, wh); | |
88 gdk_draw_rectangle(win, gc, TRUE, 0, 0, width - (ww - x), wh); | |
89 } | |
90 else | |
91 gdk_draw_rectangle(win, gc, TRUE, x, 0, width, wh); | |
92 } | |
93 else | |
94 gdk_draw_rectangle(win, gc, TRUE, 0, 0, ww, wh); | |
95 } | |
96 | |
97 gboolean | |
98 on_monitor_display_drawingarea_expose_event(GtkWidget * widget, GdkEventExpose * event, gpointer user_data) | |
99 { | |
100 if (buffer && buffer->size && output_opened) | |
101 { | |
102 gint ww = widget->allocation.width; | |
103 | |
104 gint x1 = 0; | |
105 gint x2 = buffer->used; | |
106 gint x3 = buffer->used + buffer->mix; | |
107 gint x4 = buffer->size; | |
108 | |
109 x1 = (gint64) (x1 + buffer->rd_index) * ww / buffer->size; | |
110 x2 = (gint64) (x2 + buffer->rd_index) * ww / buffer->size; | |
111 x3 = (gint64) (x3 + buffer->rd_index) * ww / buffer->size; | |
112 x4 = (gint64) (x4 + buffer->rd_index) * ww / buffer->size; | |
113 | |
114 draw_wrapped(widget, x1, x2 - x1, widget->style->fg_gc[GTK_STATE_NORMAL]); | |
115 draw_wrapped(widget, x2, x3 - x2, widget->style->white_gc); | |
116 draw_wrapped(widget, x3, x4 - x3, widget->style->bg_gc[GTK_STATE_NORMAL]); | |
117 } | |
118 else | |
119 gdk_window_clear_area(widget->window, event->area.x, event->area.y, event->area.width, event->area.height); | |
120 | |
121 return TRUE; | |
122 } | |
123 | |
124 gboolean | |
125 on_monitor_win_delete_event(GtkWidget * widget, GdkEvent * event, gpointer user_data) | |
126 { | |
127 /* V0.1.1 20000618: removed, didn't make much sense since it wasn't saved */ | |
128 /* if (config) config->enable_monitor = FALSE; */ | |
129 if (default_position_str) | |
130 { | |
131 g_free(default_position_str); | |
132 default_position_str = NULL; | |
133 } | |
134 if (default_total_str) | |
135 { | |
136 g_free(default_total_str); | |
137 default_total_str = NULL; | |
138 } | |
139 if (default_left_str) | |
140 { | |
141 g_free(default_left_str); | |
142 default_left_str = NULL; | |
143 } | |
144 if (default_output_time_str) | |
145 { | |
146 g_free(default_output_time_str); | |
147 default_output_time_str = NULL; | |
148 } | |
149 if (default_written_time_str) | |
150 { | |
151 g_free(default_written_time_str); | |
152 default_written_time_str = NULL; | |
153 } | |
154 return (FALSE); /* FALSE: destroy window */ | |
155 } | |
156 | |
157 void | |
158 xfade_check_monitor_win() | |
159 { | |
160 gchar *str; | |
161 | |
162 if (config->enable_monitor) | |
163 { | |
164 if (!monitor_win && !(monitor_win = create_monitor_win())) | |
165 { | |
166 DEBUG(("[crossfade] check_monitor_win: error creating window!\n")); | |
167 return; | |
168 } | |
169 #if 0 | |
170 if (!GDK_IS_WINDOW(monitor_win)) | |
171 { | |
172 DEBUG(("[crossfade] check_monitor_win: GDK_IS_WINDOW(monitor_win) failed!\n")); | |
173 DEBUG(("[crossfade] check_monitor_win: probably running in headless mode!\n")); | |
174 monitor_win = NULL; | |
175 return; | |
176 } | |
177 #endif | |
178 /* automatically set monitor_win to NULL when window is destroyed */ | |
179 gtk_signal_connect(GTK_OBJECT(monitor_win), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &monitor_win); | |
180 | |
181 /* show window */ | |
182 gtk_widget_hide(GTK_WIDGET(lookup_widget(monitor_win, "monitor_seekeof_button"))); | |
183 gtk_widget_show(monitor_win); | |
184 | |
185 /* get pointers to widgets (used by crossfade.c to update the monitor) */ | |
186 monitor_display_drawingarea = lookup_widget(monitor_win, "monitor_display_drawingarea"); | |
187 monitor_output_progress = GTK_PROGRESS(lookup_widget(monitor_win, "monitor_output_progress")); | |
188 monitor_position_label = GTK_LABEL (lookup_widget(monitor_win, "monpos_position_label")); | |
189 monitor_total_label = GTK_LABEL (lookup_widget(monitor_win, "monpos_total_label")); | |
190 monitor_left_label = GTK_LABEL (lookup_widget(monitor_win, "monpos_left_label")); | |
191 monitor_output_time_label = GTK_LABEL (lookup_widget(monitor_win, "monpos_output_time_label")); | |
192 monitor_output_time_sep = GTK_LABEL (lookup_widget(monitor_win, "monpos_output_time_separator_label")); | |
193 monitor_written_time_label = GTK_LABEL (lookup_widget(monitor_win, "monpos_written_time_label")); | |
194 | |
195 /* get default strings (displayed when monitor is stopped) */ | |
196 if (!default_position_str) | |
197 { | |
198 gtk_label_get(monitor_position_label, &str); | |
199 default_position_str = g_strdup(str); | |
200 } | |
201 if (!default_total_str) | |
202 { | |
203 gtk_label_get(monitor_total_label, &str); | |
204 default_total_str = g_strdup(str); | |
205 } | |
206 if (!default_left_str) | |
207 { | |
208 gtk_label_get(monitor_left_label, &str); | |
209 default_left_str = g_strdup(str); | |
210 } | |
211 if (!default_output_time_str) | |
212 { | |
213 gtk_label_get(monitor_output_time_label, &str); | |
214 default_output_time_str = g_strdup(str); | |
215 } | |
216 if (!default_written_time_str) | |
217 { | |
218 gtk_label_get(monitor_written_time_label, &str); | |
219 default_written_time_str = g_strdup(str); | |
220 } | |
221 | |
222 /* force gtk_progress_configure */ | |
223 monitor_output_max = 0; | |
224 } | |
225 else if (monitor_win) | |
226 gtk_widget_destroy(monitor_win); | |
227 } | |
228 | |
229 void | |
230 label_set_text(GtkLabel * label, gchar * text) | |
231 { | |
232 gchar *old_text; | |
233 gtk_label_get(label, &old_text); | |
234 if (strcmp(old_text, text) == 0) | |
235 return; | |
236 gtk_label_set_text(label, text); | |
237 } | |
238 | |
239 gint | |
240 xfade_update_monitor(gpointer userdata) | |
241 { | |
242 GdkRectangle update_rect; | |
243 | |
244 /* HACK: (see xfade_stop_monitor() below) */ | |
245 if (monitor_closing == CLOSED) | |
246 return TRUE; | |
247 | |
248 if (monitor_closing == CLOSING) | |
249 monitor_closing = CLOSED; | |
250 | |
251 if (!monitor_win) | |
252 return TRUE; | |
253 | |
254 /* lock buffer (only if we need to) */ | |
255 if (monitor_closing != CLOSED) | |
256 MUTEX_LOCK(&buffer_mutex); | |
257 | |
258 gint output_time = the_op->output_time(); | |
259 gint written_time = the_op->written_time(); | |
260 gint output_used = written_time - output_time; | |
261 | |
262 /*** Mixing Buffer ***/ | |
263 update_rect.x = 0; | |
264 update_rect.y = 0; | |
265 update_rect.width = monitor_display_drawingarea->allocation.width; | |
266 update_rect.height = monitor_display_drawingarea->allocation.height; | |
267 | |
268 if (monitor_closing == CLOSED) | |
269 gdk_window_clear_area(monitor_display_drawingarea->window, | |
270 update_rect.x, update_rect.y, | |
271 update_rect.width, update_rect.height); | |
272 else | |
273 gtk_widget_draw(monitor_display_drawingarea, &update_rect); | |
274 | |
275 /*** Output Buffer ***/ | |
276 if (monitor_closing == CLOSED) | |
277 { | |
278 gtk_progress_configure(monitor_output_progress, 0, 0, 0); | |
279 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(monitor_output_progress), " "); | |
280 monitor_output_max = 0; | |
281 } | |
282 else | |
283 { | |
284 if (output_opened && the_op->buffer_playing()) | |
285 { | |
286 if (output_used < 0) | |
287 output_used = 0; | |
288 | |
289 if (output_used > monitor_output_max) | |
290 { | |
291 monitor_output_max = output_used; | |
292 gtk_progress_configure(monitor_output_progress, | |
293 output_used, 0, monitor_output_max); | |
294 } | |
295 else | |
296 gtk_progress_set_value(monitor_output_progress, output_used); | |
297 | |
298 { | |
299 gchar temp[32]; | |
300 g_snprintf(temp, sizeof(temp), "%d", output_used); | |
301 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(monitor_output_progress), temp); | |
302 } | |
303 } | |
304 else | |
305 { | |
306 gtk_progress_configure(monitor_output_progress, 0, 0, 0); | |
307 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(monitor_output_progress), " "); | |
308 monitor_output_max = 0; | |
309 } | |
310 } | |
311 | |
312 /*** Position ***/ | |
313 if (!xfplayer_input_playing() || (monitor_closing == CLOSED)) | |
314 { | |
315 gtk_label_set_text(monitor_position_label, default_position_str); | |
316 gtk_label_set_text(monitor_total_label, default_total_str); | |
317 gtk_label_set_text(monitor_left_label, default_left_str); | |
318 } | |
319 else | |
320 { | |
321 gchar buffer[32]; | |
322 gint position = output_time - output_offset; | |
323 gint total = xfplaylist_current_length(); | |
324 gint left = total - position; | |
325 | |
326 /* position */ | |
327 g_snprintf(buffer, sizeof(buffer), | |
328 position < 0 ? "-%d:%02d.%01d" : "%d:%02d.%01d", | |
329 ABS(position) / 60000, | |
330 ABS(position) / 1000 % 60, | |
331 ABS(position) / 100 % 10); | |
332 gtk_label_set_text(monitor_position_label, buffer); | |
333 | |
334 /* total */ | |
335 if (total > 0) | |
336 { | |
337 g_snprintf(buffer, sizeof(buffer), | |
338 "%d:%02d", | |
339 total / 60000, | |
340 total / 1000 % 60); | |
341 gtk_label_set_text(monitor_total_label, buffer); | |
342 } | |
343 else | |
344 label_set_text(monitor_total_label, default_total_str); | |
345 | |
346 /* left */ | |
347 if (total > 0) | |
348 { | |
349 g_snprintf(buffer, sizeof(buffer), | |
350 left < 0 ? "-%d:%02d" : "%d:%02d", | |
351 ABS(left) / 60000, | |
352 ABS(left) / 1000 % 60); | |
353 gtk_label_set_text(monitor_left_label, buffer); | |
354 } | |
355 else | |
356 label_set_text(monitor_left_label, default_left_str); | |
357 } | |
358 | |
359 | |
360 /* Output Plugin position */ | |
361 if (monitor_closing == CLOSED) | |
362 { | |
363 gtk_widget_hide(GTK_WIDGET(monitor_output_time_label)); | |
364 gtk_widget_hide(GTK_WIDGET(monitor_output_time_sep)); | |
365 gtk_label_set_text(monitor_written_time_label, default_written_time_str); | |
366 } | |
367 else | |
368 { | |
369 gchar buffer[32]; | |
370 | |
371 /* check for output plugin bug -- diff should always be 0 */ | |
372 gint diff = written_time - (gint) (output_streampos * 1000 / OUTPUT_BPS); | |
373 if (diff) | |
374 { | |
375 gtk_widget_show(GTK_WIDGET(monitor_output_time_label)); | |
376 gtk_widget_show(GTK_WIDGET(monitor_output_time_sep)); | |
377 g_snprintf(buffer, sizeof(buffer), | |
378 output_time < 0 ? "-%d:%02d.%03d" : "%d:%02d.%03d", | |
379 ABS(diff) / 60000, | |
380 ABS(diff) / 1000 % 60, | |
381 ABS(diff) % 1000); | |
382 gtk_label_set_text(monitor_output_time_label, buffer); | |
383 } | |
384 else | |
385 { | |
386 gtk_widget_hide(GTK_WIDGET(monitor_output_time_label)); | |
387 gtk_widget_hide(GTK_WIDGET(monitor_output_time_sep)); | |
388 } | |
389 | |
390 /* written_time */ | |
391 g_snprintf(buffer, sizeof(buffer), | |
392 written_time < 0 ? "-%d:%02d:%02d.%01d" : "%d:%02d:%02d.%01d", | |
393 ABS(written_time) / 3600000, | |
394 ABS(written_time) / 60000 % 60, | |
395 ABS(written_time) / 1000 % 60, | |
396 ABS(written_time) / 100 % 10); | |
397 gtk_label_set_text(monitor_written_time_label, buffer); | |
398 } | |
399 | |
400 /* unlock buffer */ | |
401 if (monitor_closing != CLOSED) | |
402 MUTEX_UNLOCK(&buffer_mutex); | |
403 | |
404 return TRUE; /* continue calling this function */ | |
405 } | |
406 | |
407 void | |
408 xfade_start_monitor() | |
409 { | |
410 if (monitor_active) | |
411 return; | |
412 | |
413 monitor_output_max = 0; | |
414 monitor_closing = RUNNING; | |
415 monitor_active = TRUE; | |
416 monitor_tag = gtk_timeout_add(UPDATE_INTERVAL, xfade_update_monitor, NULL); | |
417 } | |
418 | |
419 void | |
420 xfade_stop_monitor() | |
421 { | |
422 gint max_wait = UPDATE_INTERVAL / 10 + 1 + 1; /* round up / add safety */ | |
423 | |
424 if (!monitor_active) | |
425 return; | |
426 | |
427 /* HACK, ugly HACK: force a final call of xfade_update_monitor */ | |
428 monitor_closing = CLOSING; | |
429 while ((monitor_closing == CLOSING) && (max_wait-- > 0)) | |
430 xfade_usleep(10000); | |
431 | |
432 if (max_wait <= 0) | |
433 DEBUG(("[crossfade] stop_monitor: timeout!\n")); | |
434 | |
435 /* stop calling xfade_update_monitor() */ | |
436 gtk_timeout_remove(monitor_tag); | |
437 monitor_active = FALSE; | |
438 } | |
439 | |
440 #if defined(HAVE_INPUT_SEEK) | |
441 void input_seek(int time); /* XMMS */ | |
442 void | |
443 on_monitor_seekeof_button_clicked(GtkButton *button, gpointer user_data) | |
444 { | |
445 gint total = xfplaylist_current_length(); | |
446 gint offset = xfade_cfg_offset(&config->fc[FADE_CONFIG_XFADE]) | |
447 - config->songchange_timeout; | |
448 gint position = total + offset - 2500; | |
449 | |
450 if (position < 0) | |
451 return; | |
452 | |
453 DEBUG(("[crossfade] monitor_seek_eof: total=%d offset=%d position=%d\n", total, offset, position)) | |
454 | |
455 input_seek(position/1000); /* XMMS */ | |
456 } | |
457 #else | |
458 void on_monitor_seekeof_button_clicked(GtkButton *button, gpointer user_data) | |
459 { } | |
460 #endif |