1 /*
2 Volume Meter plugin for the DeaDBeeF audio player
3
4 Copyright (C) 2014 Christian Boxdörfer <christian.boxdoerfer@posteo.de>
5
6 Based on DeaDBeeFs stock vumeter.
7 Copyright (c) 2009-2014 Alexey Yakovenko <waker@users.sourceforge.net>
8 Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>
9
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 */
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <math.h>
31 #include <fcntl.h>
32 #include <gtk/gtk.h>
33
34 #include <deadbeef/deadbeef.h>
35 #include <deadbeef/gtkui_api.h>
36
37 #include "fastftoi.h"
38 #include "support.h"
39
40 #define REFRESH_INTERVAL 25
41 #define MAX_CHANNELS 6
42 #define GRADIENT_TABLE_SIZE 1024
43
44 #define STR_GRADIENT_VERTICAL "Vertical"
45 #define STR_GRADIENT_HORIZONTAL "Horizontal"
46
47 #define CONFSTR_MS_REFRESH_INTERVAL "vu_meter.refresh_interval"
48 #define CONFSTR_MS_DB_RANGE "vu_meter.db_range"
49 #define CONFSTR_MS_ENABLE_HGRID "vu_meter.enable_hgrid"
50 #define CONFSTR_MS_ENABLE_VGRID "vu_meter.enable_vgrid"
51 #define CONFSTR_MS_ENABLE_BAR_MODE "vu_meter.enable_bar_mode"
52 #define CONFSTR_MS_BAR_FALLOFF "vu_meter.bar_falloff"
53 #define CONFSTR_MS_BAR_DELAY "vu_meter.bar_delay"
54 #define CONFSTR_MS_PEAK_FALLOFF "vu_meter.peak_falloff"
55 #define CONFSTR_MS_PEAK_DELAY "vu_meter.peak_delay"
56 #define CONFSTR_MS_GRADIENT_ORIENTATION "vu_meter.gradient_orientation"
57 #define CONFSTR_MS_COLOR_BG "vu_meter.color.background"
58 #define CONFSTR_MS_COLOR_VGRID "vu_meter.color.vgrid"
59 #define CONFSTR_MS_COLOR_HGRID "vu_meter.color.hgrid"
60 #define CONFSTR_MS_COLOR_GRADIENT_00 "vu_meter.color.gradient_00"
61 #define CONFSTR_MS_COLOR_GRADIENT_01 "vu_meter.color.gradient_01"
62 #define CONFSTR_MS_COLOR_GRADIENT_02 "vu_meter.color.gradient_02"
63 #define CONFSTR_MS_COLOR_GRADIENT_03 "vu_meter.color.gradient_03"
64 #define CONFSTR_MS_COLOR_GRADIENT_04 "vu_meter.color.gradient_04"
65 #define CONFSTR_MS_COLOR_GRADIENT_05 "vu_meter.color.gradient_05"
66
67 /* Global variables */
68 static DB_misc_t plugin;
69 static DB_functions_t * deadbeef = NULL;
70 static ddb_gtkui_t * gtkui_plugin = NULL;
71
72 typedef struct {
73 ddb_gtkui_widget_t base;
74 GtkWidget *drawarea;
75 GtkWidget *popup;
76 GtkWidget *popup_item;
77 cairo_surface_t *surf;
78 cairo_surface_t *surf_png;
79 guint drawtimer;
80 uint32_t colors[GRADIENT_TABLE_SIZE];
81 float data[MAX_CHANNELS];
82 float bars[MAX_CHANNELS];
83 int delay[MAX_CHANNELS];
84 float peaks[MAX_CHANNELS];
85 int delay_peak[MAX_CHANNELS];
86 int channels;
87 intptr_t mutex;
88 } w_vumeter_t;
89
90 enum STYLE { STYLE_BARS = 0, STYLE_RETRO = 1 };
91
92 static int CONFIG_STYLE = STYLE_BARS;
93 static int CONFIG_REFRESH_INTERVAL = 25;
94 static int CONFIG_DB_RANGE = 70;
95 static int CONFIG_ENABLE_HGRID = 1;
96 static int CONFIG_ENABLE_VGRID = 1;
97 static int CONFIG_ENABLE_BAR_MODE = 0;
98 static int CONFIG_BAR_FALLOFF = -1;
99 static int CONFIG_BAR_DELAY = 0;
100 static int CONFIG_PEAK_FALLOFF = 90;
101 static int CONFIG_PEAK_DELAY = 500;
102 static int CONFIG_GRADIENT_ORIENTATION = 0;
103 static int CONFIG_NUM_COLORS = 6;
104 static GdkColor CONFIG_COLOR_BG;
105 static GdkColor CONFIG_COLOR_VGRID;
106 static GdkColor CONFIG_COLOR_HGRID;
107 static GdkColor CONFIG_GRADIENT_COLORS[6];
108 static uint32_t CONFIG_COLOR_BG32 = 0xff222222;
109 static uint32_t CONFIG_COLOR_VGRID32 = 0xff000000;
110 static uint32_t CONFIG_COLOR_HGRID32 = 0xff666666;
111
112 static void
save_config(void)113 save_config (void)
114 {
115 deadbeef->conf_set_int (CONFSTR_MS_REFRESH_INTERVAL, CONFIG_REFRESH_INTERVAL);
116 deadbeef->conf_set_int (CONFSTR_MS_DB_RANGE, CONFIG_DB_RANGE);
117 deadbeef->conf_set_int (CONFSTR_MS_ENABLE_HGRID, CONFIG_ENABLE_HGRID);
118 deadbeef->conf_set_int (CONFSTR_MS_ENABLE_VGRID, CONFIG_ENABLE_VGRID);
119 deadbeef->conf_set_int (CONFSTR_MS_ENABLE_BAR_MODE, CONFIG_ENABLE_BAR_MODE);
120 deadbeef->conf_set_int (CONFSTR_MS_BAR_FALLOFF, CONFIG_BAR_FALLOFF);
121 deadbeef->conf_set_int (CONFSTR_MS_BAR_DELAY, CONFIG_BAR_DELAY);
122 deadbeef->conf_set_int (CONFSTR_MS_PEAK_FALLOFF, CONFIG_PEAK_FALLOFF);
123 deadbeef->conf_set_int (CONFSTR_MS_PEAK_DELAY, CONFIG_PEAK_DELAY);
124 deadbeef->conf_set_int (CONFSTR_MS_GRADIENT_ORIENTATION, CONFIG_GRADIENT_ORIENTATION);
125 char color[100];
126 snprintf (color, sizeof (color), "%d %d %d", CONFIG_COLOR_BG.red, CONFIG_COLOR_BG.green, CONFIG_COLOR_BG.blue);
127 deadbeef->conf_set_str (CONFSTR_MS_COLOR_BG, color);
128 snprintf (color, sizeof (color), "%d %d %d", CONFIG_COLOR_VGRID.red, CONFIG_COLOR_VGRID.green, CONFIG_COLOR_VGRID.blue);
129 deadbeef->conf_set_str (CONFSTR_MS_COLOR_VGRID, color);
130 snprintf (color, sizeof (color), "%d %d %d", CONFIG_COLOR_HGRID.red, CONFIG_COLOR_HGRID.green, CONFIG_COLOR_HGRID.blue);
131 deadbeef->conf_set_str (CONFSTR_MS_COLOR_HGRID, color);
132 snprintf (color, sizeof (color), "%d %d %d", CONFIG_GRADIENT_COLORS[0].red, CONFIG_GRADIENT_COLORS[0].green, CONFIG_GRADIENT_COLORS[0].blue);
133 deadbeef->conf_set_str (CONFSTR_MS_COLOR_GRADIENT_00, color);
134 snprintf (color, sizeof (color), "%d %d %d", CONFIG_GRADIENT_COLORS[1].red, CONFIG_GRADIENT_COLORS[1].green, CONFIG_GRADIENT_COLORS[1].blue);
135 deadbeef->conf_set_str (CONFSTR_MS_COLOR_GRADIENT_01, color);
136 snprintf (color, sizeof (color), "%d %d %d", CONFIG_GRADIENT_COLORS[2].red, CONFIG_GRADIENT_COLORS[2].green, CONFIG_GRADIENT_COLORS[2].blue);
137 deadbeef->conf_set_str (CONFSTR_MS_COLOR_GRADIENT_02, color);
138 snprintf (color, sizeof (color), "%d %d %d", CONFIG_GRADIENT_COLORS[3].red, CONFIG_GRADIENT_COLORS[3].green, CONFIG_GRADIENT_COLORS[3].blue);
139 deadbeef->conf_set_str (CONFSTR_MS_COLOR_GRADIENT_03, color);
140 snprintf (color, sizeof (color), "%d %d %d", CONFIG_GRADIENT_COLORS[4].red, CONFIG_GRADIENT_COLORS[4].green, CONFIG_GRADIENT_COLORS[4].blue);
141 deadbeef->conf_set_str (CONFSTR_MS_COLOR_GRADIENT_04, color);
142 snprintf (color, sizeof (color), "%d %d %d", CONFIG_GRADIENT_COLORS[5].red, CONFIG_GRADIENT_COLORS[5].green, CONFIG_GRADIENT_COLORS[5].blue);
143 deadbeef->conf_set_str (CONFSTR_MS_COLOR_GRADIENT_05, color);
144 }
145
146 static void
load_config(void)147 load_config (void)
148 {
149 deadbeef->conf_lock ();
150 CONFIG_GRADIENT_ORIENTATION = deadbeef->conf_get_int (CONFSTR_MS_GRADIENT_ORIENTATION, 0);
151 CONFIG_DB_RANGE = deadbeef->conf_get_int (CONFSTR_MS_DB_RANGE, 70);
152 CONFIG_ENABLE_HGRID = deadbeef->conf_get_int (CONFSTR_MS_ENABLE_HGRID, 1);
153 CONFIG_ENABLE_VGRID = deadbeef->conf_get_int (CONFSTR_MS_ENABLE_VGRID, 1);
154 CONFIG_ENABLE_BAR_MODE = deadbeef->conf_get_int (CONFSTR_MS_ENABLE_BAR_MODE, 0);
155 CONFIG_REFRESH_INTERVAL = deadbeef->conf_get_int (CONFSTR_MS_REFRESH_INTERVAL, 25);
156 CONFIG_BAR_FALLOFF = deadbeef->conf_get_int (CONFSTR_MS_BAR_FALLOFF, -1);
157 CONFIG_BAR_DELAY = deadbeef->conf_get_int (CONFSTR_MS_BAR_DELAY, 0);
158 CONFIG_PEAK_FALLOFF = deadbeef->conf_get_int (CONFSTR_MS_PEAK_FALLOFF, 90);
159 CONFIG_PEAK_DELAY = deadbeef->conf_get_int (CONFSTR_MS_PEAK_DELAY, 500);
160 const char *color;
161 color = deadbeef->conf_get_str_fast (CONFSTR_MS_COLOR_BG, "8738 8738 8738");
162 sscanf (color, "%hd %hd %hd", &CONFIG_COLOR_BG.red, &CONFIG_COLOR_BG.green, &CONFIG_COLOR_BG.blue);
163 color = deadbeef->conf_get_str_fast (CONFSTR_MS_COLOR_VGRID, "0 0 0");
164 sscanf (color, "%hd %hd %hd", &CONFIG_COLOR_VGRID.red, &CONFIG_COLOR_VGRID.green, &CONFIG_COLOR_VGRID.blue);
165 color = deadbeef->conf_get_str_fast (CONFSTR_MS_COLOR_HGRID, "26214 26214 26214");
166 sscanf (color, "%hd %hd %hd", &CONFIG_COLOR_HGRID.red, &CONFIG_COLOR_HGRID.green, &CONFIG_COLOR_HGRID.blue);
167 color = deadbeef->conf_get_str_fast (CONFSTR_MS_COLOR_GRADIENT_00, "65535 0 0");
168 sscanf (color, "%hd %hd %hd", &(CONFIG_GRADIENT_COLORS[0].red), &(CONFIG_GRADIENT_COLORS[0].green), &(CONFIG_GRADIENT_COLORS[0].blue));
169 color = deadbeef->conf_get_str_fast (CONFSTR_MS_COLOR_GRADIENT_01, "65535 32896 0");
170 sscanf (color, "%hd %hd %hd", &(CONFIG_GRADIENT_COLORS[1].red), &(CONFIG_GRADIENT_COLORS[1].green), &(CONFIG_GRADIENT_COLORS[1].blue));
171 color = deadbeef->conf_get_str_fast (CONFSTR_MS_COLOR_GRADIENT_02, "65535 65535 0");
172 sscanf (color, "%hd %hd %hd", &(CONFIG_GRADIENT_COLORS[2].red), &(CONFIG_GRADIENT_COLORS[2].green), &(CONFIG_GRADIENT_COLORS[2].blue));
173 color = deadbeef->conf_get_str_fast (CONFSTR_MS_COLOR_GRADIENT_03, "32896 65535 30840");
174 sscanf (color, "%hd %hd %hd", &(CONFIG_GRADIENT_COLORS[3].red), &(CONFIG_GRADIENT_COLORS[3].green), &(CONFIG_GRADIENT_COLORS[3].blue));
175 color = deadbeef->conf_get_str_fast (CONFSTR_MS_COLOR_GRADIENT_04, "0 38036 41120");
176 sscanf (color, "%hd %hd %hd", &(CONFIG_GRADIENT_COLORS[4].red), &(CONFIG_GRADIENT_COLORS[4].green), &(CONFIG_GRADIENT_COLORS[4].blue));
177 color = deadbeef->conf_get_str_fast (CONFSTR_MS_COLOR_GRADIENT_05, "0 8224 25700");
178 sscanf (color, "%hd %hd %hd", &(CONFIG_GRADIENT_COLORS[5].red), &(CONFIG_GRADIENT_COLORS[5].green), &(CONFIG_GRADIENT_COLORS[5].blue));
179
180 float scale = 255/65535.f;
181 CONFIG_COLOR_BG32 = ((uint32_t)(CONFIG_COLOR_BG.red * scale) & 0xFF) << 16 |
182 ((uint32_t)(CONFIG_COLOR_BG.green * scale) & 0xFF) << 8 |
183 ((uint32_t)(CONFIG_COLOR_BG.blue * scale) & 0xFF) << 0;
184
185 CONFIG_COLOR_VGRID32 = ((uint32_t)(CONFIG_COLOR_VGRID.red * scale) & 0xFF) << 16 |
186 ((uint32_t)(CONFIG_COLOR_VGRID.green * scale) & 0xFF) << 8 |
187 ((uint32_t)(CONFIG_COLOR_VGRID.blue * scale) & 0xFF) << 0;
188
189 CONFIG_COLOR_HGRID32 = ((uint32_t)(CONFIG_COLOR_HGRID.red * scale) & 0xFF) << 16 |
190 ((uint32_t)(CONFIG_COLOR_HGRID.green * scale) & 0xFF) << 8 |
191 ((uint32_t)(CONFIG_COLOR_HGRID.blue * scale) & 0xFF) << 0;
192 deadbeef->conf_unlock ();
193 }
194
195 static inline void
_memset_pattern(char * data,const void * pattern,size_t data_len,size_t pattern_len)196 _memset_pattern (char *data, const void* pattern, size_t data_len, size_t pattern_len)
197 {
198 memmove ((char *)data, pattern, pattern_len);
199 char *start = (char *)data;
200 char *current = (char *)data + pattern_len;
201 char *end = start + data_len;
202 while(current + pattern_len < end) {
203 memmove (current, start, pattern_len);
204 current += pattern_len;
205 pattern_len *= 2;
206 }
207 memmove (current, start, end-current);
208 }
209
210 static inline void
_draw_vline(uint8_t * data,int stride,int x0,int y0,int y1,uint32_t color)211 _draw_vline (uint8_t *data, int stride, int x0, int y0, int y1, uint32_t color) {
212 if (y0 > y1) {
213 int tmp = y0;
214 y0 = y1;
215 y1 = tmp;
216 y1--;
217 }
218 else if (y0 < y1) {
219 y0++;
220 }
221 uint32_t *ptr = (uint32_t*)&data[y0*stride+x0*4];
222 while (y0 <= y1) {
223 *ptr = color;
224 ptr += stride/4;
225 y0++;
226 }
227 }
228
229 static inline void
_draw_hline(uint8_t * data,int stride,int x0,int y0,int x1,uint32_t color)230 _draw_hline (uint8_t *data, int stride, int x0, int y0, int x1, uint32_t color) {
231 uint32_t *ptr = (uint32_t*)&data[y0*stride+x0*4];
232 while (x0 <= x1) {
233 *ptr++ = color;
234 x0++;
235 }
236 }
237
238 static inline void
_draw_background(uint8_t * data,int w,int h,uint32_t color)239 _draw_background (uint8_t *data, int w, int h, uint32_t color)
240 {
241 size_t fillLen = w * h * sizeof (uint32_t);
242 _memset_pattern ((char *)data, &color, fillLen, sizeof (uint32_t));
243 }
244
245 static inline void
_draw_bar(uint8_t * data,int stride,int x0,int y0,int w,int h,uint32_t color)246 _draw_bar (uint8_t *data, int stride, int x0, int y0, int w, int h, uint32_t color) {
247 int y1 = y0+h-1;
248 int x1 = x0+w-1;
249 uint32_t *ptr = (uint32_t*)&data[y0*stride+x0*4];
250 while (y0 <= y1) {
251 int x = x0;
252 while (x++ <= x1) {
253 *ptr++ = color;
254 }
255 y0++;
256 ptr += stride/4-w;
257 }
258 }
259
260 static inline void
_draw_bar_gradient_v(gpointer user_data,uint8_t * data,int stride,int x0,int y0,int w,int h,int total_h)261 _draw_bar_gradient_v (gpointer user_data, uint8_t *data, int stride, int x0, int y0, int w, int h, int total_h) {
262 w_vumeter_t *s = user_data;
263 int y1 = y0+h-1;
264 int x1 = x0+w-1;
265 uint32_t *ptr = (uint32_t*)&data[y0*stride+x0*4];
266 while (y0 <= y1) {
267 int x = x0;
268 int index = ftoi(((double)y0/(double)total_h) * (GRADIENT_TABLE_SIZE - 1));
269 index = CLAMP (index, 0, GRADIENT_TABLE_SIZE - 1);
270 while (x++ <= x1) {
271 *ptr++ = s->colors[index];
272 }
273 y0++;
274 ptr += stride/4-w;
275 }
276 }
277
278 static inline void
_draw_bar_gradient_h(gpointer user_data,uint8_t * data,int stride,int x0,int y0,int w,int h,int total_w)279 _draw_bar_gradient_h (gpointer user_data, uint8_t *data, int stride, int x0, int y0, int w, int h, int total_w) {
280 w_vumeter_t *s = user_data;
281 int y1 = y0+h-1;
282 int x1 = x0+w-1;
283 uint32_t *ptr = (uint32_t*)&data[y0*stride+x0*4];
284 while (y0 <= y1) {
285 int x = x0;
286 while (x++ <= x1) {
287 int index = ftoi(((double)x/(double)total_w) * (GRADIENT_TABLE_SIZE - 1));
288 index = CLAMP (index, 0, GRADIENT_TABLE_SIZE - 1);
289 *ptr++ = s->colors[index];
290 }
291 y0++;
292 ptr += stride/4-w;
293 }
294 }
295
296 static inline void
_draw_bar_gradient_bar_mode_v(gpointer user_data,uint8_t * data,int stride,int x0,int y0,int w,int h,int total_h)297 _draw_bar_gradient_bar_mode_v (gpointer user_data, uint8_t *data, int stride, int x0, int y0, int w, int h, int total_h) {
298 w_vumeter_t *s = user_data;
299 int y1 = y0+h-1;
300 int x1 = x0+w-1;
301 y0 -= y0 % 2;
302 uint32_t *ptr = (uint32_t*)&data[y0*stride+x0*4];
303 while (y0 <= y1) {
304 int x = x0;
305 int index = ftoi(((double)y0/(double)total_h) * (GRADIENT_TABLE_SIZE - 1));
306 index = CLAMP (index, 0, GRADIENT_TABLE_SIZE - 1);
307 while (x++ <= x1) {
308 *ptr++ = s->colors[index];
309 }
310 y0 += 2;
311 ptr += stride/2-w;
312 }
313 }
314
315 static inline void
_draw_bar_gradient_bar_mode_h(gpointer user_data,uint8_t * data,int stride,int x0,int y0,int w,int h,int total_w)316 _draw_bar_gradient_bar_mode_h (gpointer user_data, uint8_t *data, int stride, int x0, int y0, int w, int h, int total_w) {
317 w_vumeter_t *s = user_data;
318 int y1 = y0+h-1;
319 int x1 = x0+w-1;
320 y0 -= y0 % 2;
321 uint32_t *ptr = (uint32_t*)&data[y0*stride+x0*4];
322 while (y0 <= y1) {
323 int x = x0;
324 while (x++ <= x1) {
325 int index = ftoi(((double)x/(double)total_w) * (GRADIENT_TABLE_SIZE - 1));
326 index = CLAMP (index, 0, GRADIENT_TABLE_SIZE - 1);
327 *ptr++ = s->colors[index];
328 }
329 y0 += 2;
330 ptr += stride/2-w;
331 }
332 }
333
334 /* based on Delphi function by Witold J.Janik */
335 void
create_gradient_table(gpointer user_data,GdkColor * colors,int num_colors)336 create_gradient_table (gpointer user_data, GdkColor *colors, int num_colors)
337 {
338 w_vumeter_t *w = user_data;
339
340 num_colors -= 1;
341
342 for (int i = 0; i < GRADIENT_TABLE_SIZE; i++) {
343 double position = (double)i/GRADIENT_TABLE_SIZE;
344 /* if position > 1 then we have repetition of colors it maybe useful */
345 if (position > 1.0) {
346 if (position - ftoi (position) == 0.0) {
347 position = 1.0;
348 }
349 else {
350 position = position - ftoi (position);
351 }
352 }
353
354 double m= num_colors * position;
355 int n=(int)m; // integer of m
356 double f=m-n; // fraction of m
357
358 w->colors[i] = 0xFF000000;
359 float scale = 255/65535.f;
360 if (num_colors == 0) {
361 w->colors[i] = (uint32_t)(colors[0].red*scale) << 16 |
362 (uint32_t)(colors[0].green*scale) << 8 |
363 (uint32_t)(colors[0].blue*scale) << 0;
364 }
365 else if (n < num_colors) {
366 w->colors[i] = (uint32_t)((colors[n].red*scale) + f * ((colors[n+1].red*scale)-(colors[n].red*scale))) << 16 |
367 (uint32_t)((colors[n].green*scale) + f * ((colors[n+1].green*scale)-(colors[n].green*scale))) << 8 |
368 (uint32_t)((colors[n].blue*scale) + f * ((colors[n+1].blue*scale)-(colors[n].blue*scale))) << 0;
369 }
370 else if (n == num_colors) {
371 w->colors[i] = (uint32_t)(colors[n].red*scale) << 16 |
372 (uint32_t)(colors[n].green*scale) << 8 |
373 (uint32_t)(colors[n].blue*scale) << 0;
374 }
375 else {
376 w->colors[i] = 0xFFFFFFFF;
377 }
378 }
379 }
380
381 static int
on_config_changed(gpointer user_data,uintptr_t ctx)382 on_config_changed (gpointer user_data, uintptr_t ctx)
383 {
384 w_vumeter_t *w = user_data;
385 load_config ();
386 return 0;
387 }
388
389 #pragma GCC diagnostic push
390 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
391 static void
on_button_config(GtkMenuItem * menuitem,gpointer user_data)392 on_button_config (GtkMenuItem *menuitem, gpointer user_data)
393 {
394 GtkWidget *vumeter_properties;
395 GtkWidget *config_dialog;
396 GtkWidget *vbox01;
397 GtkWidget *vbox02;
398 GtkWidget *vbox03;
399 GtkWidget *vbox04;
400 GtkWidget *hbox01;
401 GtkWidget *hbox02;
402 GtkWidget *valign_01;
403 GtkWidget *valign_02;
404 GtkWidget *valign_03;
405 GtkWidget *color_label;
406 GtkWidget *color_frame;
407 GtkWidget *color_bg_label;
408 GtkWidget *color_bg;
409 GtkWidget *color_vgrid_label;
410 GtkWidget *color_vgrid;
411 GtkWidget *color_hgrid_label;
412 GtkWidget *color_hgrid;
413 GtkWidget *hseparator_01;
414 GtkWidget *color_gradient_00;
415 GtkWidget *color_gradient_01;
416 GtkWidget *color_gradient_02;
417 GtkWidget *color_gradient_03;
418 GtkWidget *color_gradient_04;
419 GtkWidget *color_gradient_05;
420 GtkWidget *num_colors_label;
421 GtkWidget *num_colors;
422 GtkWidget *hbox03;
423 GtkWidget *db_range_label0;
424 GtkWidget *db_range;
425 GtkWidget *hgrid;
426 GtkWidget *vgrid;
427 GtkWidget *bar_mode;
428 GtkWidget *hbox06;
429 GtkWidget *style_label;
430 GtkWidget *style;
431 GtkWidget *hbox05;
432 GtkWidget *gradient_orientation_label;
433 GtkWidget *gradient_orientation;
434 GtkWidget *dialog_action_area13;
435 GtkWidget *applybutton1;
436 GtkWidget *cancelbutton1;
437 GtkWidget *okbutton1;
438 vumeter_properties = gtk_dialog_new ();
439 gtk_window_set_title (GTK_WINDOW (vumeter_properties), "vumeter Properties");
440 gtk_window_set_type_hint (GTK_WINDOW (vumeter_properties), GDK_WINDOW_TYPE_HINT_DIALOG);
441
442 config_dialog = gtk_dialog_get_content_area (GTK_DIALOG (vumeter_properties));
443 gtk_widget_show (config_dialog);
444
445 hbox01 = gtk_hbox_new (FALSE, 8);
446 gtk_widget_show (hbox01);
447 gtk_box_pack_start (GTK_BOX (config_dialog), hbox01, FALSE, FALSE, 0);
448 gtk_container_set_border_width (GTK_CONTAINER (hbox01), 12);
449
450 color_label = gtk_label_new (NULL);
451 gtk_label_set_markup (GTK_LABEL (color_label),"<b>Colors</b>");
452 gtk_widget_show (color_label);
453
454 color_frame = gtk_frame_new ("Colors");
455 gtk_frame_set_label_widget ((GtkFrame *)color_frame, color_label);
456 gtk_frame_set_shadow_type ((GtkFrame *)color_frame, GTK_SHADOW_IN);
457 gtk_widget_show (color_frame);
458 gtk_box_pack_start (GTK_BOX (hbox01), color_frame, TRUE, FALSE, 0);
459
460 vbox01 = gtk_vbox_new (FALSE, 8);
461 gtk_widget_show (vbox01);
462 gtk_container_add (GTK_CONTAINER (color_frame), vbox01);
463 gtk_container_set_border_width (GTK_CONTAINER (vbox01), 12);
464
465 hbox02 = gtk_hbox_new (FALSE, 8);
466 gtk_widget_show (hbox02);
467 gtk_box_pack_start (GTK_BOX (vbox01), hbox02, TRUE, TRUE, 0);
468
469 vbox03 = gtk_vbox_new (FALSE, 8);
470 gtk_widget_show (vbox03);
471 gtk_box_pack_start (GTK_BOX (hbox02), vbox03, TRUE, TRUE, 0);
472
473 vbox04 = gtk_vbox_new (FALSE, 8);
474 gtk_widget_show (vbox04);
475 gtk_box_pack_start (GTK_BOX (hbox02), vbox04, TRUE, TRUE, 0);
476
477 valign_01 = gtk_alignment_new(0, 1, 0, 1);
478 gtk_container_add(GTK_CONTAINER(vbox03), valign_01);
479 gtk_widget_show (valign_01);
480
481 color_bg_label = gtk_label_new (NULL);
482 gtk_label_set_markup (GTK_LABEL (color_bg_label),"Background:");
483 gtk_widget_show (color_bg_label);
484 gtk_container_add(GTK_CONTAINER(valign_01), color_bg_label);
485
486 color_bg = gtk_color_button_new ();
487 gtk_color_button_set_use_alpha ((GtkColorButton *)color_bg, TRUE);
488 gtk_widget_show (color_bg);
489 gtk_box_pack_start (GTK_BOX (vbox04), color_bg, TRUE, TRUE, 0);
490
491 valign_02 = gtk_alignment_new(0, 1, 0, 1);
492 gtk_container_add(GTK_CONTAINER(vbox03), valign_02);
493 gtk_widget_show (valign_02);
494
495 color_vgrid_label = gtk_label_new (NULL);
496 gtk_label_set_markup (GTK_LABEL (color_vgrid_label),"Vertical grid:");
497 gtk_widget_show (color_vgrid_label);
498 gtk_container_add(GTK_CONTAINER(valign_02), color_vgrid_label);
499
500 color_vgrid = gtk_color_button_new ();
501 gtk_color_button_set_use_alpha ((GtkColorButton *)color_vgrid, TRUE);
502 gtk_widget_show (color_vgrid);
503 gtk_box_pack_start (GTK_BOX (vbox04), color_vgrid, TRUE, TRUE, 0);
504
505 valign_03 = gtk_alignment_new(0, 1, 0, 1);
506 gtk_container_add(GTK_CONTAINER(vbox03), valign_03);
507 gtk_widget_show (valign_03);
508
509 color_hgrid_label = gtk_label_new (NULL);
510 gtk_label_set_markup (GTK_LABEL (color_hgrid_label),"Horizontal grid:");
511 gtk_widget_show (color_hgrid_label);
512 gtk_container_add(GTK_CONTAINER(valign_03), color_hgrid_label);
513
514 color_hgrid = gtk_color_button_new ();
515 gtk_color_button_set_use_alpha ((GtkColorButton *)color_hgrid, TRUE);
516 gtk_widget_show (color_hgrid);
517 gtk_box_pack_start (GTK_BOX (vbox04), color_hgrid, TRUE, TRUE, 0);
518
519 hseparator_01 = gtk_hseparator_new ();
520 gtk_widget_show (hseparator_01);
521 gtk_box_pack_start (GTK_BOX (vbox01), hseparator_01, TRUE, TRUE, 0);
522
523 num_colors_label = gtk_label_new (NULL);
524 gtk_label_set_markup (GTK_LABEL (num_colors_label),"Number of colors:");
525 gtk_widget_show (num_colors_label);
526 gtk_box_pack_start (GTK_BOX (vbox01), num_colors_label, FALSE, FALSE, 0);
527
528 num_colors = gtk_spin_button_new_with_range (1,6,1);
529 gtk_widget_show (num_colors);
530 gtk_box_pack_start (GTK_BOX (vbox01), num_colors, FALSE, FALSE, 0);
531
532 color_gradient_00 = gtk_color_button_new ();
533 gtk_color_button_set_use_alpha ((GtkColorButton *)color_gradient_00, TRUE);
534 gtk_widget_show (color_gradient_00);
535 gtk_box_pack_start (GTK_BOX (vbox01), color_gradient_00, TRUE, FALSE, 0);
536 gtk_widget_set_size_request (color_gradient_00, -1, 30);
537
538 color_gradient_01 = gtk_color_button_new ();
539 gtk_color_button_set_use_alpha ((GtkColorButton *)color_gradient_01, TRUE);
540 gtk_widget_show (color_gradient_01);
541 gtk_box_pack_start (GTK_BOX (vbox01), color_gradient_01, TRUE, FALSE, 0);
542 gtk_widget_set_size_request (color_gradient_01, -1, 30);
543
544 color_gradient_02 = gtk_color_button_new ();
545 gtk_color_button_set_use_alpha ((GtkColorButton *)color_gradient_02, TRUE);
546 gtk_widget_show (color_gradient_02);
547 gtk_box_pack_start (GTK_BOX (vbox01), color_gradient_02, TRUE, FALSE, 0);
548 gtk_widget_set_size_request (color_gradient_02, -1, 30);
549
550 color_gradient_03 = gtk_color_button_new ();
551 gtk_color_button_set_use_alpha ((GtkColorButton *)color_gradient_03, TRUE);
552 gtk_widget_show (color_gradient_03);
553 gtk_box_pack_start (GTK_BOX (vbox01), color_gradient_03, TRUE, FALSE, 0);
554 gtk_widget_set_size_request (color_gradient_03, -1, 30);
555
556 color_gradient_04 = gtk_color_button_new ();
557 gtk_color_button_set_use_alpha ((GtkColorButton *)color_gradient_04, TRUE);
558 gtk_widget_show (color_gradient_04);
559 gtk_box_pack_start (GTK_BOX (vbox01), color_gradient_04, TRUE, FALSE, 0);
560 gtk_widget_set_size_request (color_gradient_04, -1, 30);
561
562 color_gradient_05 = gtk_color_button_new ();
563 gtk_color_button_set_use_alpha ((GtkColorButton *)color_gradient_05, TRUE);
564 gtk_widget_show (color_gradient_05);
565 gtk_box_pack_start (GTK_BOX (vbox01), color_gradient_05, TRUE, FALSE, 0);
566 gtk_widget_set_size_request (color_gradient_05, -1, 30);
567
568 vbox02 = gtk_vbox_new (FALSE, 8);
569 gtk_widget_show (vbox02);
570 gtk_box_pack_start (GTK_BOX (hbox01), vbox02, FALSE, FALSE, 0);
571 gtk_container_set_border_width (GTK_CONTAINER (vbox02), 12);
572
573 hbox03 = gtk_hbox_new (FALSE, 8);
574 gtk_widget_show (hbox03);
575 gtk_box_pack_start (GTK_BOX (vbox02), hbox03, FALSE, FALSE, 0);
576
577 db_range_label0 = gtk_label_new (NULL);
578 gtk_label_set_markup (GTK_LABEL (db_range_label0),"dB range:");
579 gtk_widget_show (db_range_label0);
580 gtk_box_pack_start (GTK_BOX (hbox03), db_range_label0, FALSE, TRUE, 0);
581
582 db_range = gtk_spin_button_new_with_range (50,120,10);
583 gtk_widget_show (db_range);
584 gtk_box_pack_start (GTK_BOX (hbox03), db_range, TRUE, TRUE, 0);
585
586 hbox05 = gtk_hbox_new (FALSE, 8);
587 gtk_widget_show (hbox05);
588 gtk_box_pack_start (GTK_BOX (vbox02), hbox05, FALSE, FALSE, 0);
589
590 gradient_orientation_label = gtk_label_new (NULL);
591 gtk_label_set_markup (GTK_LABEL (gradient_orientation_label),"Gradient orientation:");
592 gtk_widget_show (gradient_orientation_label);
593 gtk_box_pack_start (GTK_BOX (hbox05), gradient_orientation_label, FALSE, TRUE, 0);
594
595 gradient_orientation = gtk_combo_box_text_new ();
596 gtk_widget_show (gradient_orientation);
597 gtk_box_pack_start (GTK_BOX (hbox05), gradient_orientation, TRUE, TRUE, 0);
598 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(gradient_orientation), STR_GRADIENT_VERTICAL);
599 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(gradient_orientation), STR_GRADIENT_HORIZONTAL);
600
601 hbox06 = gtk_hbox_new (FALSE, 8);
602 gtk_widget_show (hbox06);
603 gtk_box_pack_start (GTK_BOX (vbox02), hbox06, FALSE, FALSE, 0);
604
605 style_label = gtk_label_new (NULL);
606 gtk_label_set_markup (GTK_LABEL (style_label),"Style:");
607 gtk_widget_show (style_label);
608 gtk_box_pack_start (GTK_BOX (hbox06), style_label, FALSE, TRUE, 0);
609
610 style = gtk_combo_box_text_new ();
611 gtk_widget_show (style);
612 gtk_box_pack_start (GTK_BOX (hbox06), style, TRUE, TRUE, 0);
613 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(style), "Bars");
614 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(style), "Retro");
615
616 hgrid = gtk_check_button_new_with_label ("Horizontal grid");
617 gtk_widget_show (hgrid);
618 gtk_box_pack_start (GTK_BOX (vbox02), hgrid, FALSE, FALSE, 0);
619
620 vgrid = gtk_check_button_new_with_label ("Vertical grid");
621 gtk_widget_show (vgrid);
622 gtk_box_pack_start (GTK_BOX (vbox02), vgrid, FALSE, FALSE, 0);
623
624 bar_mode = gtk_check_button_new_with_label ("Bar mode");
625 gtk_widget_show (bar_mode);
626 gtk_box_pack_start (GTK_BOX (vbox02), bar_mode, FALSE, FALSE, 0);
627
628 dialog_action_area13 = gtk_dialog_get_action_area (GTK_DIALOG (vumeter_properties));
629 gtk_widget_show (dialog_action_area13);
630 gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area13), GTK_BUTTONBOX_END);
631
632 applybutton1 = gtk_button_new_from_stock ("gtk-apply");
633 gtk_widget_show (applybutton1);
634 gtk_dialog_add_action_widget (GTK_DIALOG (vumeter_properties), applybutton1, GTK_RESPONSE_APPLY);
635 gtk_widget_set_can_default (applybutton1, TRUE);
636
637 cancelbutton1 = gtk_button_new_from_stock ("gtk-cancel");
638 gtk_widget_show (cancelbutton1);
639 gtk_dialog_add_action_widget (GTK_DIALOG (vumeter_properties), cancelbutton1, GTK_RESPONSE_CANCEL);
640 gtk_widget_set_can_default (cancelbutton1, TRUE);
641
642 okbutton1 = gtk_button_new_from_stock ("gtk-ok");
643 gtk_widget_show (okbutton1);
644 gtk_dialog_add_action_widget (GTK_DIALOG (vumeter_properties), okbutton1, GTK_RESPONSE_OK);
645 gtk_widget_set_can_default (okbutton1, TRUE);
646
647 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (hgrid), CONFIG_ENABLE_HGRID);
648 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (vgrid), CONFIG_ENABLE_VGRID);
649 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bar_mode), CONFIG_ENABLE_BAR_MODE);
650 gtk_combo_box_set_active (GTK_COMBO_BOX (gradient_orientation), CONFIG_GRADIENT_ORIENTATION);
651 gtk_combo_box_set_active (GTK_COMBO_BOX (style), CONFIG_STYLE);
652 gtk_spin_button_set_value (GTK_SPIN_BUTTON (num_colors), CONFIG_NUM_COLORS);
653 gtk_spin_button_set_value (GTK_SPIN_BUTTON (db_range), CONFIG_DB_RANGE);
654 gtk_color_button_set_color (GTK_COLOR_BUTTON (color_bg), &CONFIG_COLOR_BG);
655 gtk_color_button_set_color (GTK_COLOR_BUTTON (color_vgrid), &CONFIG_COLOR_VGRID);
656 gtk_color_button_set_color (GTK_COLOR_BUTTON (color_hgrid), &CONFIG_COLOR_HGRID);
657 gtk_color_button_set_color (GTK_COLOR_BUTTON (color_gradient_00), &(CONFIG_GRADIENT_COLORS[0]));
658 gtk_color_button_set_color (GTK_COLOR_BUTTON (color_gradient_01), &(CONFIG_GRADIENT_COLORS[1]));
659 gtk_color_button_set_color (GTK_COLOR_BUTTON (color_gradient_02), &(CONFIG_GRADIENT_COLORS[2]));
660 gtk_color_button_set_color (GTK_COLOR_BUTTON (color_gradient_03), &(CONFIG_GRADIENT_COLORS[3]));
661 gtk_color_button_set_color (GTK_COLOR_BUTTON (color_gradient_04), &(CONFIG_GRADIENT_COLORS[4]));
662 gtk_color_button_set_color (GTK_COLOR_BUTTON (color_gradient_05), &(CONFIG_GRADIENT_COLORS[5]));
663
664 char text[100];
665 for (;;) {
666 int response = gtk_dialog_run (GTK_DIALOG (vumeter_properties));
667 if (response == GTK_RESPONSE_OK || response == GTK_RESPONSE_APPLY) {
668 gtk_color_button_get_color (GTK_COLOR_BUTTON (color_bg), &CONFIG_COLOR_BG);
669 gtk_color_button_get_color (GTK_COLOR_BUTTON (color_vgrid), &CONFIG_COLOR_VGRID);
670 gtk_color_button_get_color (GTK_COLOR_BUTTON (color_hgrid), &CONFIG_COLOR_HGRID);
671 gtk_color_button_get_color (GTK_COLOR_BUTTON (color_gradient_00), &CONFIG_GRADIENT_COLORS[0]);
672 gtk_color_button_get_color (GTK_COLOR_BUTTON (color_gradient_01), &CONFIG_GRADIENT_COLORS[1]);
673 gtk_color_button_get_color (GTK_COLOR_BUTTON (color_gradient_02), &CONFIG_GRADIENT_COLORS[2]);
674 gtk_color_button_get_color (GTK_COLOR_BUTTON (color_gradient_03), &CONFIG_GRADIENT_COLORS[3]);
675 gtk_color_button_get_color (GTK_COLOR_BUTTON (color_gradient_04), &CONFIG_GRADIENT_COLORS[4]);
676 gtk_color_button_get_color (GTK_COLOR_BUTTON (color_gradient_05), &CONFIG_GRADIENT_COLORS[5]);
677
678 CONFIG_ENABLE_HGRID = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (hgrid));
679 CONFIG_ENABLE_VGRID = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (vgrid));
680 CONFIG_ENABLE_BAR_MODE = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (bar_mode));
681 CONFIG_DB_RANGE = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (db_range));
682 CONFIG_NUM_COLORS = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (num_colors));
683 switch (CONFIG_NUM_COLORS) {
684 case 1:
685 gtk_widget_hide (color_gradient_01);
686 gtk_widget_hide (color_gradient_02);
687 gtk_widget_hide (color_gradient_03);
688 gtk_widget_hide (color_gradient_04);
689 gtk_widget_hide (color_gradient_05);
690 break;
691 case 2:
692 gtk_widget_show (color_gradient_01);
693 gtk_widget_hide (color_gradient_02);
694 gtk_widget_hide (color_gradient_03);
695 gtk_widget_hide (color_gradient_04);
696 gtk_widget_hide (color_gradient_05);
697 break;
698 case 3:
699 gtk_widget_show (color_gradient_01);
700 gtk_widget_show (color_gradient_02);
701 gtk_widget_hide (color_gradient_03);
702 gtk_widget_hide (color_gradient_04);
703 gtk_widget_hide (color_gradient_05);
704 break;
705 case 4:
706 gtk_widget_show (color_gradient_01);
707 gtk_widget_show (color_gradient_02);
708 gtk_widget_show (color_gradient_03);
709 gtk_widget_hide (color_gradient_04);
710 gtk_widget_hide (color_gradient_05);
711 break;
712 case 5:
713 gtk_widget_show (color_gradient_01);
714 gtk_widget_show (color_gradient_02);
715 gtk_widget_show (color_gradient_03);
716 gtk_widget_show (color_gradient_04);
717 gtk_widget_hide (color_gradient_05);
718 break;
719 case 6:
720 gtk_widget_show (color_gradient_01);
721 gtk_widget_show (color_gradient_02);
722 gtk_widget_show (color_gradient_03);
723 gtk_widget_show (color_gradient_04);
724 gtk_widget_show (color_gradient_05);
725 break;
726 }
727 snprintf (text, sizeof (text), "%s", gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (gradient_orientation)));
728 if (strcmp (text, STR_GRADIENT_VERTICAL) == 0) {
729 CONFIG_GRADIENT_ORIENTATION = 0;
730 }
731 else if (strcmp (text, STR_GRADIENT_HORIZONTAL) == 0) {
732 CONFIG_GRADIENT_ORIENTATION = 1;
733 }
734 else {
735 CONFIG_GRADIENT_ORIENTATION = -1;
736 }
737 snprintf (text, sizeof (text), "%s", gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (style)));
738 if (strcmp (text, "Bars") == 0) {
739 CONFIG_STYLE = STYLE_BARS;
740 }
741 else if (strcmp (text, "Retro") == 0) {
742 CONFIG_STYLE = STYLE_RETRO;
743 }
744 else {
745 CONFIG_STYLE = STYLE_BARS;
746 }
747 save_config ();
748 deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
749 }
750 if (response == GTK_RESPONSE_APPLY) {
751 continue;
752 }
753 break;
754 }
755 gtk_widget_destroy (vumeter_properties);
756 return;
757 }
758 #pragma GCC diagnostic pop
759
760 ///// vumeter vis
761 void
w_vumeter_destroy(ddb_gtkui_widget_t * w)762 w_vumeter_destroy (ddb_gtkui_widget_t *w) {
763 w_vumeter_t *s = (w_vumeter_t *)w;
764 deadbeef->vis_waveform_unlisten (w);
765 if (s->drawtimer) {
766 g_source_remove (s->drawtimer);
767 s->drawtimer = 0;
768 }
769 if (s->surf) {
770 cairo_surface_destroy (s->surf);
771 s->surf = NULL;
772 }
773 if (s->surf_png) {
774 cairo_surface_destroy (s->surf_png);
775 s->surf_png = NULL;
776 }
777 if (s->mutex) {
778 deadbeef->mutex_free (s->mutex);
779 s->mutex = 0;
780 }
781 }
782
783 gboolean
w_vumeter_draw_cb(void * data)784 w_vumeter_draw_cb (void *data) {
785 w_vumeter_t *s = data;
786 gtk_widget_queue_draw (s->drawarea);
787 return TRUE;
788 }
789
790 static void
vumeter_wavedata_listener(void * ctx,ddb_audio_data_t * data)791 vumeter_wavedata_listener (void *ctx, ddb_audio_data_t *data) {
792 w_vumeter_t *w = ctx;
793 deadbeef->mutex_lock (w->mutex);
794 w->channels = MIN (MAX_CHANNELS, data->fmt->channels);
795 int nsamples = data->nframes/w->channels;
796
797 for (int c = 0; c < w->channels; c++) {
798 w->data[c] = 0;
799 for (int s = 0; s < nsamples + c; s++) {
800 w->data[c] += (data->data[ftoi (s * data->fmt->channels) + c] * data->data[ftoi (s * data->fmt->channels) + c]);
801 }
802 w->data[c] = sqrt (w->data[c]/nsamples);
803 }
804 deadbeef->mutex_unlock (w->mutex);
805 }
806
807 static void
vumeter_draw_retro(w_vumeter_t * w,cairo_t * cr,int width,int height)808 vumeter_draw_retro (w_vumeter_t *w, cairo_t *cr, int width, int height)
809 {
810 if (!w->surf_png) {
811 char path[PATH_MAX];
812 if (snprintf (path, PATH_MAX, "%s/vumeter.png",
813 deadbeef->get_pixmap_dir()) < 0) {
814 return;
815 }
816 w->surf_png = cairo_image_surface_create_from_png (path);
817 }
818
819 int m_radius = 130;
820 float start = M_PI * 3/4;
821 float value = 0;
822 int c = 0;
823 for (; c < w->channels; c++) {
824 value = MAX (value, w->bars[c]);
825 }
826 cairo_set_source_surface (cr, w->surf_png, 0, 0);
827 cairo_paint (cr);
828 cairo_set_source_rgb(cr, 0.3, 0.3, 0.3);
829 cairo_set_line_width(cr, 2);
830 int surf_width = cairo_image_surface_get_width (w->surf_png);
831 int surf_height = cairo_image_surface_get_height (w->surf_png);
832 cairo_move_to (cr, surf_width/2, surf_height - 23);
833 cairo_line_to (cr, surf_width/2 + m_radius * cos (value * M_PI / (CONFIG_DB_RANGE*2.5) - start), surf_height - 23 + m_radius * sin (value * M_PI / (CONFIG_DB_RANGE*2.5)-start));
834 cairo_stroke (cr);
835 }
836
837 static void
vumeter_draw_bars(w_vumeter_t * w,cairo_t * cr,int width,int height)838 vumeter_draw_bars (w_vumeter_t *w, cairo_t *cr, int width, int height)
839 {
840 // start drawing
841 int bands = MIN (w->channels, MAX_CHANNELS);
842 bands = MAX (bands, 1);
843 if (!w->surf || cairo_image_surface_get_width (w->surf) != width || cairo_image_surface_get_height (w->surf) != height) {
844 printf("create surf\n");
845 if (w->surf) {
846 cairo_surface_destroy (w->surf);
847 w->surf = NULL;
848 }
849 w->surf = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
850 }
851 float base_s = (height / (float)CONFIG_DB_RANGE);
852
853 cairo_surface_flush (w->surf);
854
855 unsigned char *data = cairo_image_surface_get_data (w->surf);
856 if (!data) {
857 return;
858 }
859 int stride = cairo_image_surface_get_stride (w->surf);
860 memset (data, 0, height * stride);
861
862 int barw = CLAMP (width / bands, 2, 1000);
863
864 //draw background
865 _draw_background (data, width, height, CONFIG_COLOR_BG32);
866 // draw vertical grid
867 if (CONFIG_ENABLE_VGRID) {
868 int num_lines = MIN (width/barw, bands);
869 for (int i = 1; i < num_lines; i++) {
870 _draw_vline (data, stride, barw * i, 0, height-1, CONFIG_COLOR_VGRID32);
871 }
872 }
873
874 int hgrid_num = CONFIG_DB_RANGE/10;
875 // draw horizontal grid
876 if (CONFIG_ENABLE_HGRID && height > 2*hgrid_num && width > 1) {
877 for (int i = 1; i < hgrid_num; i++) {
878 _draw_hline (data, stride, 0, ftoi (i/(float)hgrid_num * height), width-1, CONFIG_COLOR_HGRID32);
879 }
880 }
881
882 for (gint i = 0; i < bands; i++)
883 {
884 int x = barw * i;
885 int y = height - ftoi (w->bars[i] * base_s);
886 if (y < 0) {
887 y = 0;
888 }
889 int bw = barw-1;
890 if (x + bw >= width) {
891 bw = width-x-1;
892 }
893 if (CONFIG_GRADIENT_ORIENTATION == 0) {
894 if (CONFIG_ENABLE_BAR_MODE == 0) {
895 _draw_bar_gradient_v (w, data, stride, x+1, y, bw, height-y, height);
896 }
897 else {
898 _draw_bar_gradient_bar_mode_v (w, data, stride, x+1, y, bw, height-y, height);
899 }
900 }
901 else {
902 if (CONFIG_ENABLE_BAR_MODE == 0) {
903 _draw_bar_gradient_h (w, data, stride, x+1, y, bw, height-y, width);
904 }
905 else {
906 _draw_bar_gradient_bar_mode_h (w, data, stride, x+1, y, bw, height-y, width);
907 }
908 }
909 y = height - w->peaks[i] * base_s;
910 if (y < height-1) {
911 if (CONFIG_GRADIENT_ORIENTATION == 0) {
912 _draw_bar_gradient_v (w, data, stride, x + 1, y, bw, 1, height);
913 }
914 else {
915 _draw_bar_gradient_h (w, data, stride, x + 1, y, bw, 1, width);
916 }
917 }
918 }
919
920 cairo_surface_mark_dirty (w->surf);
921
922 cairo_save (cr);
923 cairo_set_source_surface (cr, w->surf, 0, 0);
924 cairo_rectangle (cr, 0, 0, width, height);
925 cairo_fill (cr);
926 cairo_restore (cr);
927 }
928
929 static gboolean
vumeter_draw(GtkWidget * widget,cairo_t * cr,gpointer user_data)930 vumeter_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data) {
931 w_vumeter_t *w = user_data;
932 GtkAllocation a;
933 gtk_widget_get_allocation (widget, &a);
934
935 deadbeef->mutex_lock (w->mutex);
936 int width, height, bands;
937 bands = MIN (w->channels, MAX_CHANNELS);
938 bands = MAX (bands, 1);
939 width = a.width;
940 height = a.height;
941
942 float bar_falloff = CONFIG_BAR_FALLOFF/1000.0 * CONFIG_REFRESH_INTERVAL;
943 float peak_falloff = CONFIG_PEAK_FALLOFF/1000.0 * CONFIG_REFRESH_INTERVAL;
944 int bar_delay = ftoi (CONFIG_BAR_DELAY/CONFIG_REFRESH_INTERVAL);
945 int peak_delay = ftoi (CONFIG_PEAK_DELAY/CONFIG_REFRESH_INTERVAL);
946
947 if (deadbeef->get_output ()->state () == OUTPUT_STATE_PLAYING) {
948 for (int i = 0; i < bands; i++)
949 {
950 float x = CONFIG_DB_RANGE + (10.0 * log10f (w->data[i]));
951 // TODO: get rid of hardcoding
952 //x += CONFIG_DB_RANGE - 63;
953 //if (x > CONFIG_DB_RANGE) {
954 // x = w->peaks[i];
955 //}
956 w->bars[i] = CLAMP (w->bars[i], 0, CONFIG_DB_RANGE);
957 w->peaks[i] = CLAMP (w->peaks[i], 0, CONFIG_DB_RANGE);
958
959 if (CONFIG_BAR_FALLOFF != -1) {
960 if (w->delay[i] < 0) {
961 w->bars[i] -= bar_falloff;
962 }
963 else {
964 w->delay[i]--;
965 }
966 }
967 else {
968 w->bars[i] = 0;
969 }
970 if (CONFIG_PEAK_FALLOFF != -1) {
971 if (w->delay_peak[i] < 0) {
972 w->peaks[i] -= peak_falloff;
973 }
974 else {
975 w->delay_peak[i]--;
976 }
977 }
978 else {
979 w->peaks[i] = 0;
980 }
981
982 if (x > w->bars[i])
983 {
984 w->bars[i] = x;
985 w->delay[i] = bar_delay;
986 }
987 if (x > w->peaks[i]) {
988 w->peaks[i] = x;
989 w->delay_peak[i] = peak_delay;
990 }
991 if (w->peaks[i] < w->bars[i]) {
992 w->peaks[i] = w->bars[i];
993 }
994 }
995 }
996
997 switch (CONFIG_STYLE) {
998 case STYLE_BARS:
999 vumeter_draw_bars (w, cr, width, height);
1000 break;
1001 case STYLE_RETRO:
1002 vumeter_draw_retro (w, cr, width, height);
1003 break;
1004 default:
1005 vumeter_draw_bars (w, cr, width, height);
1006 break;
1007 }
1008 deadbeef->mutex_unlock (w->mutex);
1009 return FALSE;
1010 }
1011
1012
1013 gboolean
vumeter_expose_event(GtkWidget * widget,GdkEventExpose * event,gpointer user_data)1014 vumeter_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) {
1015 cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (widget));
1016 gboolean res = vumeter_draw (widget, cr, user_data);
1017 cairo_destroy (cr);
1018 return res;
1019 }
1020
1021
1022 gboolean
vumeter_button_press_event(GtkWidget * widget,GdkEventButton * event,gpointer user_data)1023 vumeter_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
1024 {
1025 //w_vumeter_t *w = user_data;
1026 if (event->button == 3) {
1027 return TRUE;
1028 }
1029 return TRUE;
1030 }
1031
1032 gboolean
vumeter_button_release_event(GtkWidget * widget,GdkEventButton * event,gpointer user_data)1033 vumeter_button_release_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
1034 {
1035 w_vumeter_t *w = user_data;
1036 if (event->button == 3) {
1037 gtk_menu_popup (GTK_MENU (w->popup), NULL, NULL, NULL, w->drawarea, 0, gtk_get_current_event_time ());
1038 return TRUE;
1039 }
1040 return TRUE;
1041 }
1042
1043 static int
vumeter_message(ddb_gtkui_widget_t * widget,uint32_t id,uintptr_t ctx,uint32_t p1,uint32_t p2)1044 vumeter_message (ddb_gtkui_widget_t *widget, uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2)
1045 {
1046 w_vumeter_t *w = (w_vumeter_t *)widget;
1047
1048 switch (id) {
1049 case DB_EV_CONFIGCHANGED:
1050 on_config_changed (w, ctx);
1051 if (w->drawtimer) {
1052 g_source_remove (w->drawtimer);
1053 w->drawtimer = 0;
1054 }
1055 w->drawtimer = g_timeout_add (CONFIG_REFRESH_INTERVAL, w_vumeter_draw_cb, w);
1056 break;
1057 }
1058 return 0;
1059 }
1060
1061 void
w_vumeter_init(ddb_gtkui_widget_t * w)1062 w_vumeter_init (ddb_gtkui_widget_t *w) {
1063 w_vumeter_t *s = (w_vumeter_t *)w;
1064 load_config ();
1065 deadbeef->mutex_lock (s->mutex);
1066 create_gradient_table (s, CONFIG_GRADIENT_COLORS, CONFIG_NUM_COLORS);
1067
1068 if (s->drawtimer) {
1069 g_source_remove (s->drawtimer);
1070 s->drawtimer = 0;
1071 }
1072 s->drawtimer = g_timeout_add (CONFIG_REFRESH_INTERVAL, w_vumeter_draw_cb, w);
1073 deadbeef->mutex_unlock (s->mutex);
1074 }
1075
1076 ddb_gtkui_widget_t *
w_vu_meter_create(void)1077 w_vu_meter_create (void) {
1078 w_vumeter_t *w = malloc (sizeof (w_vumeter_t));
1079 memset (w, 0, sizeof (w_vumeter_t));
1080
1081 w->base.widget = gtk_event_box_new ();
1082 w->base.init = w_vumeter_init;
1083 w->base.destroy = w_vumeter_destroy;
1084 w->base.message = vumeter_message;
1085 w->drawarea = gtk_drawing_area_new ();
1086 w->popup = gtk_menu_new ();
1087 w->popup_item = gtk_menu_item_new_with_mnemonic ("Configure");
1088 w->mutex = deadbeef->mutex_create ();
1089 gtk_widget_set_size_request (w->base.widget, 16, 16);
1090
1091 gtk_container_add (GTK_CONTAINER (w->base.widget), w->drawarea);
1092 gtk_container_add (GTK_CONTAINER (w->popup), w->popup_item);
1093 gtk_widget_show (w->drawarea);
1094 gtk_widget_show (w->popup);
1095 gtk_widget_show (w->popup_item);
1096
1097 #if !GTK_CHECK_VERSION(3,0,0)
1098 g_signal_connect_after ((gpointer) w->drawarea, "expose_event", G_CALLBACK (vumeter_expose_event), w);
1099 #else
1100 g_signal_connect_after ((gpointer) w->drawarea, "draw", G_CALLBACK (vumeter_draw), w);
1101 #endif
1102 g_signal_connect_after ((gpointer) w->base.widget, "button_press_event", G_CALLBACK (vumeter_button_press_event), w);
1103 g_signal_connect_after ((gpointer) w->base.widget, "button_release_event", G_CALLBACK (vumeter_button_release_event), w);
1104 g_signal_connect_after ((gpointer) w->popup_item, "activate", G_CALLBACK (on_button_config), w);
1105 gtkui_plugin->w_override_signals (w->base.widget, w);
1106 gtk_widget_set_events (w->base.widget, GDK_EXPOSURE_MASK
1107 | GDK_LEAVE_NOTIFY_MASK
1108 | GDK_BUTTON_PRESS_MASK
1109 | GDK_POINTER_MOTION_MASK
1110 | GDK_POINTER_MOTION_HINT_MASK);
1111 deadbeef->vis_waveform_listen (w, vumeter_wavedata_listener);
1112 return (ddb_gtkui_widget_t *)w;
1113 }
1114
1115 int
vu_meter_connect(void)1116 vu_meter_connect (void)
1117 {
1118 gtkui_plugin = (ddb_gtkui_t *) deadbeef->plug_get_for_id (DDB_GTKUI_PLUGIN_ID);
1119 if (gtkui_plugin) {
1120 //trace("using '%s' plugin %d.%d\n", DDB_GTKUI_PLUGIN_ID, gtkui_plugin->gui.plugin.version_major, gtkui_plugin->gui.plugin.version_minor );
1121 if (gtkui_plugin->gui.plugin.version_major == 2) {
1122 //printf ("fb api2\n");
1123 // 0.6+, use the new widget API
1124 gtkui_plugin->w_reg_widget ("VU Meter", 0, w_vu_meter_create, "vu_meter", NULL);
1125 return 0;
1126 }
1127 }
1128 return -1;
1129 }
1130
1131 int
vu_meter_start(void)1132 vu_meter_start (void)
1133 {
1134 load_config ();
1135 return 0;
1136 }
1137
1138 int
vu_meter_stop(void)1139 vu_meter_stop (void)
1140 {
1141 save_config ();
1142 return 0;
1143 }
1144
1145 int
vu_meter_startup(GtkWidget * cont)1146 vu_meter_startup (GtkWidget *cont)
1147 {
1148 return 0;
1149 }
1150
1151 int
vu_meter_shutdown(GtkWidget * cont)1152 vu_meter_shutdown (GtkWidget *cont)
1153 {
1154 return 0;
1155 }
1156 int
vu_meter_disconnect(void)1157 vu_meter_disconnect (void)
1158 {
1159 gtkui_plugin = NULL;
1160 return 0;
1161 }
1162
1163 static const char settings_dlg[] =
1164 "property \"Refresh interval (ms): \" spinbtn[10,1000,1] " CONFSTR_MS_REFRESH_INTERVAL " 25 ;\n"
1165 "property \"Bar falloff (dB/s): \" spinbtn[-1,1000,1] " CONFSTR_MS_BAR_FALLOFF " -1 ;\n"
1166 "property \"Bar delay (ms): \" spinbtn[0,10000,100] " CONFSTR_MS_BAR_DELAY " 0 ;\n"
1167 "property \"Peak falloff (dB/s): \" spinbtn[-1,1000,1] " CONFSTR_MS_PEAK_FALLOFF " 90 ;\n"
1168 "property \"Peak delay (ms): \" spinbtn[0,10000,100] " CONFSTR_MS_PEAK_DELAY " 500 ;\n"
1169 ;
1170
1171 static DB_misc_t plugin = {
1172 //DB_PLUGIN_SET_API_VERSION
1173 .plugin.type = DB_PLUGIN_MISC,
1174 .plugin.api_vmajor = 1,
1175 .plugin.api_vminor = 5,
1176 .plugin.version_major = 0,
1177 .plugin.version_minor = 1,
1178 #if GTK_CHECK_VERSION(3,0,0)
1179 .plugin.id = "vu_meter-gtk3",
1180 #else
1181 .plugin.id = "vu_meter",
1182 #endif
1183 .plugin.name = "VU Meter",
1184 .plugin.descr = "VU Meter",
1185 .plugin.copyright =
1186 "Copyright (C) 2013 Christian Boxdörfer <christian.boxdoerfer@posteo.de>\n"
1187 "\n"
1188 "This program is free software; you can redistribute it and/or\n"
1189 "modify it under the terms of the GNU General Public License\n"
1190 "as published by the Free Software Foundation; either version 2\n"
1191 "of the License, or (at your option) any later version.\n"
1192 "\n"
1193 "This program is distributed in the hope that it will be useful,\n"
1194 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1195 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1196 "GNU General Public License for more details.\n"
1197 "\n"
1198 "You should have received a copy of the GNU General Public License\n"
1199 "along with this program; if not, write to the Free Software\n"
1200 "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
1201 ,
1202 .plugin.website = "https://github.com/cboxdoerfer/ddb_vu_meter",
1203 .plugin.start = vu_meter_start,
1204 .plugin.stop = vu_meter_stop,
1205 .plugin.connect = vu_meter_connect,
1206 .plugin.disconnect = vu_meter_disconnect,
1207 .plugin.configdialog = settings_dlg,
1208 };
1209
1210 #if !GTK_CHECK_VERSION(3,0,0)
1211 DB_plugin_t *
ddb_vis_vu_meter_GTK2_load(DB_functions_t * ddb)1212 ddb_vis_vu_meter_GTK2_load (DB_functions_t *ddb) {
1213 deadbeef = ddb;
1214 return &plugin.plugin;
1215 }
1216 #else
1217 DB_plugin_t *
ddb_vis_vu_meter_GTK3_load(DB_functions_t * ddb)1218 ddb_vis_vu_meter_GTK3_load (DB_functions_t *ddb) {
1219 deadbeef = ddb;
1220 return &plugin.plugin;
1221 }
1222 #endif
1223