|
61
|
1 /* BMP - Cross-platform multimedia player
|
|
|
2 * Copyright (C) 2003-2004 BMP development team.
|
|
|
3 *
|
|
|
4 * Based on XMMS:
|
|
|
5 * Copyright (C) 1998-2003 XMMS development team.
|
|
|
6 *
|
|
|
7 * This program is free software; you can redistribute it and/or modify
|
|
|
8 * it under the terms of the GNU General Public License as published by
|
|
|
9 * the Free Software Foundation; either version 2 of the License, or
|
|
|
10 * (at your option) any later version.
|
|
|
11 *
|
|
|
12 * This program is distributed in the hope that it will be useful,
|
|
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
15 * GNU General Public License for more details.
|
|
|
16 *
|
|
|
17 * You should have received a copy of the GNU General Public License
|
|
|
18 * w
|
|
|
19 * along with this program; if not, write to the Free Software
|
|
|
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
21 */
|
|
|
22
|
|
|
23 #ifdef HAVE_CONFIG_H
|
|
|
24 # include "config.h"
|
|
|
25 #endif
|
|
|
26
|
|
|
27 #include <glib.h>
|
|
|
28 #include <glib/gi18n.h>
|
|
|
29 #include <gtk/gtk.h>
|
|
|
30 #include <string.h>
|
|
|
31 #include "audacious/plugin.h"
|
|
|
32 #include "libaudacious/util.h"
|
|
|
33 #include "libaudacious/configdb.h"
|
|
|
34 #include "blur_scope.h"
|
|
|
35 #include "bscope_logo.xpm"
|
|
|
36
|
|
|
37 static GtkWidget *window = NULL, *area;
|
|
|
38 static GdkPixmap *bg_pixmap = NULL;
|
|
|
39 static gboolean config_read = FALSE;
|
|
|
40
|
|
|
41 static void bscope_init(void);
|
|
|
42 static void bscope_cleanup(void);
|
|
|
43 static void bscope_playback_stop(void);
|
|
|
44 static void bscope_render_pcm(gint16 data[2][512]);
|
|
|
45
|
|
|
46 BlurScopeConfig bscope_cfg;
|
|
|
47
|
|
|
48 GtkItemFactory *blurscope_popup;
|
|
|
49
|
|
|
50 enum { SCOPE_TOGGLE, SCOPE_CLOSE };
|
|
|
51
|
|
|
52 void blurscope_callback(gpointer data, guint action, GtkWidget * widget);
|
|
|
53 gboolean blurscope_popup_menu(GtkWidget * widget,
|
|
|
54 GdkEventButton * event, gpointer user_data);
|
|
|
55
|
|
|
56 GtkItemFactoryEntry blurscope_menu_entries[] = {
|
|
|
57 {N_("/Toggle Decorations"), NULL, blurscope_callback, SCOPE_TOGGLE,
|
|
|
58 "<Item>"},
|
|
|
59 {N_("/-"), NULL, NULL, 0, "<Separator>"},
|
|
|
60 {N_("/Close"), NULL, blurscope_callback, SCOPE_CLOSE, "<StockItem>",
|
|
|
61 GTK_STOCK_CLOSE},
|
|
|
62 };
|
|
|
63
|
|
|
64 static const int blurscope_menu_entries_num =
|
|
|
65 sizeof(blurscope_menu_entries) / sizeof(blurscope_menu_entries[0]);
|
|
|
66
|
|
|
67
|
|
|
68 VisPlugin bscope_vp = {
|
|
|
69 NULL,
|
|
|
70 NULL,
|
|
|
71 0, /* XMMS Session ID, filled in by XMMS */
|
|
|
72 NULL, /* description */
|
|
|
73 1, /* Number of PCM channels wanted */
|
|
|
74 0, /* Number of freq channels wanted */
|
|
|
75 bscope_init, /* init */
|
|
|
76 bscope_cleanup, /* cleanup */
|
|
|
77 NULL, /* about */
|
|
|
78 bscope_configure, /* configure */
|
|
|
79 NULL, /* disable_plugin */
|
|
|
80 NULL, /* playback_start */
|
|
|
81 bscope_playback_stop, /* playback_stop */
|
|
|
82 bscope_render_pcm, /* render_pcm */
|
|
|
83 NULL /* render_freq */
|
|
|
84 };
|
|
|
85
|
|
|
86 VisPlugin *
|
|
|
87 get_vplugin_info(void)
|
|
|
88 {
|
|
|
89 bscope_vp.description = g_strdup("Blur Scope");
|
|
|
90 return &bscope_vp;
|
|
|
91 }
|
|
|
92
|
|
|
93 #define WIDTH 256
|
|
|
94 #define HEIGHT 128
|
|
|
95 #define min(x,y) ((x)<(y)?(x):(y))
|
|
|
96 #define BPL ((WIDTH + 2))
|
|
|
97
|
|
|
98 static guchar rgb_buf[(WIDTH + 2) * (HEIGHT + 2)];
|
|
|
99 static GdkRgbCmap *cmap = NULL;
|
|
|
100
|
|
|
101 static void inline
|
|
|
102 draw_pixel_8(guchar * buffer, gint x, gint y, guchar c)
|
|
|
103 {
|
|
|
104 buffer[((y + 1) * BPL) + (x + 1)] = c;
|
|
|
105 }
|
|
|
106
|
|
|
107
|
|
|
108 void
|
|
|
109 bscope_read_config(void)
|
|
|
110 {
|
|
|
111 ConfigDb *db;
|
|
|
112
|
|
|
113 if (!config_read) {
|
|
|
114 bscope_cfg.color = 0xFF3F7F;
|
|
|
115 db = bmp_cfg_db_open();
|
|
|
116
|
|
|
117 if (db) {
|
|
|
118 bmp_cfg_db_get_int(db, "BlurScope", "color",
|
|
|
119 (int *) &bscope_cfg.color);
|
|
|
120 bmp_cfg_db_close(db);
|
|
|
121 }
|
|
|
122 config_read = TRUE;
|
|
|
123 }
|
|
|
124 }
|
|
|
125
|
|
|
126
|
|
|
127 #ifndef I386_ASSEM
|
|
|
128 void
|
|
|
129 bscope_blur_8(guchar * ptr, gint w, gint h, gint bpl)
|
|
|
130 {
|
|
|
131 register guint i, sum;
|
|
|
132 register guchar *iptr;
|
|
|
133
|
|
|
134 iptr = ptr + bpl + 1;
|
|
|
135 i = bpl * h;
|
|
|
136 while (i--) {
|
|
|
137 sum = (iptr[-bpl] + iptr[-1] + iptr[1] + iptr[bpl]) >> 2;
|
|
|
138 if (sum > 2)
|
|
|
139 sum -= 2;
|
|
|
140 *(iptr++) = sum;
|
|
|
141 }
|
|
|
142
|
|
|
143
|
|
|
144 }
|
|
|
145 #else
|
|
|
146 extern void bscope_blur_8(guchar * ptr, gint w, gint h, gint bpl);
|
|
|
147 #endif
|
|
|
148
|
|
|
149 void
|
|
|
150 generate_cmap(void)
|
|
|
151 {
|
|
|
152 guint32 colors[256], i, red, blue, green;
|
|
|
153 if (window) {
|
|
|
154 red = (guint32) (bscope_cfg.color / 0x10000);
|
|
|
155 green = (guint32) ((bscope_cfg.color % 0x10000) / 0x100);
|
|
|
156 blue = (guint32) (bscope_cfg.color % 0x100);
|
|
|
157 for (i = 255; i > 0; i--) {
|
|
|
158 colors[i] =
|
|
|
159 (((guint32) (i * red / 256) << 16) |
|
|
|
160 ((guint32) (i * green / 256) << 8) |
|
|
|
161 ((guint32) (i * blue / 256)));
|
|
|
162 }
|
|
|
163 colors[0] = 0;
|
|
|
164 if (cmap) {
|
|
|
165 gdk_rgb_cmap_free(cmap);
|
|
|
166 }
|
|
|
167 cmap = gdk_rgb_cmap_new(colors, 256);
|
|
|
168 }
|
|
|
169 }
|
|
|
170
|
|
|
171 static void
|
|
|
172 bscope_destroy_cb(GtkWidget * w, gpointer data)
|
|
|
173 {
|
|
|
174 bscope_vp.disable_plugin(&bscope_vp);
|
|
|
175 }
|
|
|
176
|
|
|
177 static void
|
|
|
178 bscope_init(void)
|
|
|
179 {
|
|
|
180 if (window)
|
|
|
181 return;
|
|
|
182 bscope_read_config();
|
|
|
183
|
|
|
184 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
|
185 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
|
|
|
186
|
|
|
187 blurscope_popup = gtk_item_factory_new(GTK_TYPE_MENU, "<Main>", NULL);
|
|
|
188
|
|
|
189 gtk_item_factory_create_items(GTK_ITEM_FACTORY(blurscope_popup),
|
|
|
190 blurscope_menu_entries_num,
|
|
|
191 blurscope_menu_entries, NULL);
|
|
|
192
|
|
|
193 gtk_widget_set_events(window,
|
|
|
194 GDK_FOCUS_CHANGE_MASK | GDK_BUTTON_MOTION_MASK |
|
|
|
195 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
|
|
|
196 GDK_SCROLL_MASK | GDK_VISIBILITY_NOTIFY_MASK);
|
|
|
197
|
|
|
198 gtk_window_set_title(GTK_WINDOW(window), _("Blur scope"));
|
|
|
199 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
|
|
|
200 gtk_widget_realize(window);
|
|
|
201 bg_pixmap =
|
|
|
202 gdk_pixmap_create_from_xpm_d(window->window, NULL, NULL, bscope_logo);
|
|
|
203 // gdk_window_set_back_pixmap(window->window,bg_pixmap,0);
|
|
|
204
|
|
|
205 g_signal_connect(G_OBJECT(window), "destroy",
|
|
|
206 G_CALLBACK(bscope_destroy_cb), NULL);
|
|
|
207 g_signal_connect(G_OBJECT(window), "destroy",
|
|
|
208 G_CALLBACK(gtk_widget_destroyed), &window);
|
|
|
209 g_signal_connect(G_OBJECT(window), "button-press-event",
|
|
|
210 G_CALLBACK(blurscope_popup_menu), NULL);
|
|
|
211
|
|
|
212 gtk_widget_set_size_request(window, WIDTH, HEIGHT);
|
|
|
213 area = gtk_drawing_area_new();
|
|
|
214 gtk_container_add(GTK_CONTAINER(window), area);
|
|
|
215 gtk_widget_realize(area);
|
|
|
216 gdk_window_set_back_pixmap(area->window, bg_pixmap, 0);
|
|
|
217 generate_cmap();
|
|
|
218 memset(rgb_buf, 0, (WIDTH + 2) * (HEIGHT + 2));
|
|
|
219
|
|
|
220
|
|
|
221
|
|
|
222 gtk_widget_show(area);
|
|
|
223 gtk_widget_show(window);
|
|
|
224 gdk_window_clear(window->window);
|
|
|
225 gdk_window_clear(area->window);
|
|
|
226
|
|
|
227
|
|
|
228 }
|
|
|
229
|
|
|
230 static void
|
|
|
231 bscope_cleanup(void)
|
|
|
232 {
|
|
|
233 if (window)
|
|
|
234 gtk_widget_destroy(window);
|
|
|
235 if (bg_pixmap) {
|
|
|
236 g_object_unref(bg_pixmap);
|
|
|
237 bg_pixmap = NULL;
|
|
|
238 }
|
|
|
239 if (cmap) {
|
|
|
240 gdk_rgb_cmap_free(cmap);
|
|
|
241 cmap = NULL;
|
|
|
242 }
|
|
|
243 }
|
|
|
244
|
|
|
245 static void
|
|
|
246 bscope_playback_stop(void)
|
|
|
247 {
|
|
|
248 if (GTK_WIDGET_REALIZED(area))
|
|
|
249 gdk_window_clear(area->window);
|
|
|
250 }
|
|
|
251
|
|
|
252 static inline void
|
|
|
253 draw_vert_line(guchar * buffer, gint x, gint y1, gint y2)
|
|
|
254 {
|
|
|
255 int y;
|
|
|
256 if (y1 < y2) {
|
|
|
257 for (y = y1; y <= y2; y++)
|
|
|
258 draw_pixel_8(buffer, x, y, 0xFF);
|
|
|
259 }
|
|
|
260 else if (y2 < y1) {
|
|
|
261 for (y = y2; y <= y1; y++)
|
|
|
262 draw_pixel_8(buffer, x, y, 0xFF);
|
|
|
263 }
|
|
|
264 else
|
|
|
265 draw_pixel_8(buffer, x, y1, 0xFF);
|
|
|
266 }
|
|
|
267
|
|
|
268 static void
|
|
|
269 bscope_render_pcm(gint16 data[2][512])
|
|
|
270 {
|
|
|
271 gint i, y, prev_y;
|
|
|
272
|
|
|
273 if (!window)
|
|
|
274 return;
|
|
|
275 bscope_blur_8(rgb_buf, WIDTH, HEIGHT, BPL);
|
|
|
276 prev_y = y = (HEIGHT / 2) + (data[0][0] >> 9);
|
|
|
277 for (i = 0; i < WIDTH; i++) {
|
|
|
278 y = (HEIGHT / 2) + (data[0][i >> 1] >> 9);
|
|
|
279 if (y < 0)
|
|
|
280 y = 0;
|
|
|
281 if (y >= HEIGHT)
|
|
|
282 y = HEIGHT - 1;
|
|
|
283 draw_vert_line(rgb_buf, i, prev_y, y);
|
|
|
284 prev_y = y;
|
|
|
285 }
|
|
|
286
|
|
|
287 GDK_THREADS_ENTER();
|
|
|
288 gdk_draw_indexed_image(area->window, area->style->white_gc, 0, 0,
|
|
|
289 WIDTH, HEIGHT, GDK_RGB_DITHER_NONE,
|
|
|
290 rgb_buf + BPL + 1, (WIDTH + 2), cmap);
|
|
|
291 GDK_THREADS_LEAVE();
|
|
|
292 return;
|
|
|
293 }
|
|
|
294
|
|
|
295 gboolean
|
|
|
296 blurscope_popup_menu(GtkWidget * widget,
|
|
|
297 GdkEventButton * event, gpointer user_data)
|
|
|
298 {
|
|
|
299
|
|
|
300 if (event->button == 3) {
|
|
|
301 gtk_item_factory_popup(blurscope_popup,
|
|
|
302 event->x_root,
|
|
|
303 event->y_root, event->button, event->time);
|
|
|
304 return TRUE;
|
|
|
305 }
|
|
|
306
|
|
|
307 return FALSE;
|
|
|
308 }
|
|
|
309
|
|
|
310 void
|
|
|
311 blurscope_callback(gpointer data, guint action, GtkWidget * widget)
|
|
|
312 {
|
|
|
313
|
|
|
314 switch (action) {
|
|
|
315 case SCOPE_TOGGLE:
|
|
|
316 gtk_window_set_decorated(GTK_WINDOW(window),
|
|
|
317 !gtk_window_get_decorated(GTK_WINDOW
|
|
|
318 (window)));
|
|
|
319 break;
|
|
|
320 case SCOPE_CLOSE:
|
|
|
321 gtk_widget_destroy(window);
|
|
|
322 break;
|
|
|
323 default:
|
|
|
324 break;
|
|
|
325 }
|
|
|
326 return;
|
|
|
327 }
|