1 /* Calf DSP Library
2 * Custom controls (line graph, knob).
3 * Copyright (C) 2007-2010 Krzysztof Foltman, Torben Hohn, Markus Schmidt
4 * and others
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
20 */
21
22 #include <calf/ctl_vumeter.h>
23
24
25 ///////////////////////////////////////// vu meter ///////////////////////////////////////////////
26
27
28 static gboolean
calf_vumeter_expose(GtkWidget * widget,GdkEventExpose * event)29 calf_vumeter_expose (GtkWidget *widget, GdkEventExpose *event)
30 {
31 g_assert(CALF_IS_VUMETER(widget));
32
33 CalfVUMeter *vu = CALF_VUMETER(widget);
34 cairo_t *c = gdk_cairo_create(GDK_DRAWABLE(widget->window));
35
36 float r, g, b;
37
38 int x = widget->allocation.x;
39 int y = widget->allocation.y;
40 int width = widget->allocation.width;
41 int height = widget->allocation.height;
42 int border_x = widget->style->xthickness;
43 int border_y = widget->style->ythickness;
44 int space_x = 1; int space_y = 1; // inner border around led bar
45 int led = 2; // single LED size
46 int led_m = 1; // margin between LED
47 int led_s = led + led_m; // size of LED with margin
48 int led_x = widget->style->xthickness;
49 int led_y = widget->style->ythickness; // position of first LED
50 int led_w = width - 2 * led_x + led_m; // width of LED bar w/o text calc (additional led margin, is removed later; used for filling the led bar completely w/o margin gap)
51 int led_h = height - 2 * led_y; // height of LED bar w/o text calc
52 int text_x = 0; int text_y = 0;
53 int text_w = 0; int text_h = 0;
54
55 // only valid if vumeter is enabled
56 cairo_text_extents_t extents;
57
58 if(vu->vumeter_position) {
59 cairo_select_font_face(c, "cairo:sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
60 cairo_set_font_size(c, 8);
61
62 cairo_text_extents(c, "-88.88", &extents);
63 text_w = extents.width;
64 text_h = extents.height;
65 switch(vu->vumeter_position) {
66 case 1:
67 text_x = width / 2 - text_w / 2;
68 text_y = border_y + led_y - extents.y_bearing;
69 led_y += text_h + led_y;
70 led_h -= text_h + led_y;
71 break;
72 case 2:
73 text_x = width - border_x - led_x - text_w;
74 text_y = height / 2 - text_h / 2 - extents.y_bearing;
75 led_w -= led_x + text_w;
76 break;
77 case 3:
78 text_x = width / 2 - text_w / 2;
79 text_y = height - border_y - led_y - text_h - extents.y_bearing;
80 led_h -= led_y + text_h;
81 break;
82 case 4:
83 text_x = border_x + led_x;
84 text_y = height / 2 - text_h / 2 - extents.y_bearing;
85 led_x += led_x + text_w;
86 led_w -= led_x + text_w;
87 break;
88 }
89 }
90
91 led_w -= led_w % led_s + led_m; //round LED width to LED size and remove margin gap, width is filled with LED without margin gap now
92
93 if( vu->cache_surface == NULL ) {
94 // looks like its either first call or the widget has been resized.
95 // create the cache_surface.
96 vu->cache_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height );
97 cairo_t *cache_cr = cairo_create( vu->cache_surface );
98
99 float radius, bevel, glass;
100 get_bg_color(widget, NULL, &r, &g, &b);
101 gtk_widget_style_get(widget, "border-radius", &radius, "bevel", &bevel, "glass", &glass, NULL);
102 create_rectangle(cache_cr, 0, 0, width, height, radius);
103 cairo_set_source_rgb(cache_cr, r, g, b);
104 cairo_fill(cache_cr);
105 draw_bevel(cache_cr, 0, 0, width, height, radius, bevel);
106
107 // border around LED
108 cairo_rectangle(cache_cr, led_x, led_y, led_w, led_h);
109 cairo_set_source_rgb (cache_cr, 0, 0, 0);
110 cairo_fill(cache_cr);
111
112 led_x += space_x;
113 led_y += space_y;
114 led_w -= 2 * space_x;
115 led_h -= 2 * space_y;
116
117 // LED bases
118 cairo_set_line_width(cache_cr, 1);
119 for (int x = led_x; x + led <= led_x + led_w; x += led_s)
120 {
121 float ts = (x - led_x) * 1.0 / led_w;
122 float r = 0.f, g = 0.f, b = 0.f;
123 switch(vu->mode)
124 {
125 case VU_STANDARD:
126 default:
127 if (ts < 0.75)
128 r = ts / 0.75, g = 0.5 + ts * 0.66, b = 1 - ts / 0.75;
129 else
130 r = 1, g = 1 - (ts - 0.75) / 0.25, b = 0;
131 // if (vu->value < ts || vu->value <= 0)
132 // r *= 0.5, g *= 0.5, b *= 0.5;
133 break;
134 case VU_STANDARD_CENTER:
135 if (ts < 0.25)
136 // 0.0 -> 0.25
137 // green: 0.f -> 1.f
138 r = 1, g = (ts) / 0.25, b = 0;
139 else if (ts > 0.75)
140 // 0.75 -> 1.0
141 // green: 1.f -> 0.f
142 r = 1, g = 1 - (ts - 0.75) / 0.25, b = 0;
143 else if (ts > 0.5)
144 // 0.5 -> 0.75
145 // red: 0.f -> 1.f
146 // green: 0.5 -> 1.f
147 // blue: 1.f -> 0.f
148 r = (ts - 0.5) / 0.25, g = 0.5 + (ts - 0.5) * 2.f, b = 1 - (ts - 0.5) / 0.25;
149 else
150 // 0.25 -> 0.5
151 // red: 1.f -> 0.f
152 // green: 1.f -> 0.5
153 // blue: 0.f -> 1.f
154 r = 1 - (ts - 0.25) / 0.25, g = 1.f - (ts * 2.f - .5f), b = (ts - 0.25) / 0.25;
155 // if (vu->value < ts || vu->value <= 0)
156 // r *= 0.5, g *= 0.5, b *= 0.5;
157 break;
158 case VU_MONOCHROME_REVERSE:
159 r = 0, g = 170.0 / 255.0, b = 1;
160 // if (!(vu->value < ts) || vu->value >= 1.0)
161 // r *= 0.5, g *= 0.5, b *= 0.5;
162 break;
163 case VU_MONOCHROME:
164 r = 0, g = 170.0 / 255.0, b = 1;
165 // if (vu->value < ts || vu->value <= 0)
166 // r *= 0.5, g *= 0.5, b *= 0.5;
167 break;
168 case VU_MONOCHROME_CENTER:
169 r = 0, g = 170.0 / 255.0, b = 1;
170 // if (vu->value < ts || vu->value <= 0)
171 // r *= 0.5, g *= 0.5, b *= 0.5;
172 break;
173 }
174 GdkColor sc2 = { 0, (guint16)(65535 * r + 0.2), (guint16)(65535 * g), (guint16)(65535 * b) };
175 GdkColor sc3 = { 0, (guint16)(65535 * r * 0.7), (guint16)(65535 * g * 0.7), (guint16)(65535 * b * 0.7) };
176 gdk_cairo_set_source_color(cache_cr, &sc2);
177 cairo_move_to(cache_cr, x + 0.5, led_y);
178 cairo_line_to(cache_cr, x + 0.5, led_y + led_h);
179 cairo_stroke(cache_cr);
180 gdk_cairo_set_source_color(cache_cr, &sc3);
181 cairo_move_to(cache_cr, x + 1.5, led_y + led_h);
182 cairo_line_to(cache_cr, x + 1.5, led_y);
183 cairo_stroke(cache_cr);
184 }
185 // create blinder pattern
186 cairo_pattern_t *pat = cairo_pattern_create_linear (led_x, led_y, led_x, led_y + led_h);
187 if (glass > 0.f) {
188 cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, 0.25 * glass);
189 cairo_pattern_add_color_stop_rgba (pat, 0.5, 0.5, 0.5, 0.5, 0.0);
190 cairo_pattern_add_color_stop_rgba (pat, 1, 0.0, 0.0, 0.0, 0.25 * glass);
191 cairo_rectangle(cache_cr, led_x, led_y, led_w, led_h);
192 cairo_set_source(cache_cr, pat);
193 cairo_fill(cache_cr);
194 }
195
196 // create overlay
197 vu->cache_overlay = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
198 cairo_t *over_cr = cairo_create(vu->cache_overlay);
199
200 // copy surface to overlay
201 cairo_set_source_surface(over_cr, vu->cache_surface, 0, 0);
202 cairo_rectangle(over_cr, 0, 0, width, height);
203 cairo_fill(over_cr);
204
205 // create blinder pattern
206 pat = cairo_pattern_create_linear (led_x, led_y, led_x, led_y + led_h);
207 float c1 = 0.05 + 0.15 * glass;
208 cairo_pattern_add_color_stop_rgba (pat, 0, c1, c1, c1, 0.7);
209 cairo_pattern_add_color_stop_rgba (pat, 0.4, 0.05, 0.05, 0.05, 0.7);
210 cairo_pattern_add_color_stop_rgba (pat, 0.401, 0.05, 0.05, 0.05, 0.7 + 0.2 * glass);
211 cairo_pattern_add_color_stop_rgba (pat, 1, 0.05, 0.05, 0.05, 0.7 + 0.05 * glass);
212
213 // draw on top of overlay
214 cairo_set_source(over_cr, pat);
215 cairo_rectangle(over_cr, 0, 0, width, height);
216 cairo_paint(over_cr);
217
218 // clean up
219 cairo_destroy(cache_cr);
220 cairo_destroy(over_cr);
221 } else {
222 led_x += space_x;
223 led_y += space_y;
224 led_w -= 2 * space_x;
225 led_h -= 2 * space_y;
226 }
227 led_x += x;
228 led_y += y;
229 text_x += x;
230 text_y += y;
231 // draw LED blinder
232 cairo_set_source_surface( c, vu->cache_surface, x, y );
233 cairo_paint( c );
234 cairo_set_source_surface( c, vu->cache_overlay, x, y );
235
236 // get microseconds
237 timeval tv;
238 gettimeofday(&tv, 0);
239 long time = tv.tv_sec * 1000 * 1000 + tv.tv_usec;
240
241 // limit to 1.f
242 float value_orig = std::max(std::min(vu->value, 1.f), 0.f);
243 float value = 0.f;
244
245 // falloff?
246 if(vu->vumeter_falloff > 0.f and vu->mode != VU_MONOCHROME_REVERSE) {
247 // fall off a bit
248 float s = ((float)(time - vu->last_falltime) / 1000000.0);
249 float m = vu->last_falloff * s * vu->vumeter_falloff;
250 vu->last_falloff -= m;
251 // new max value?
252 if(value_orig > vu->last_falloff) {
253 vu->last_falloff = value_orig;
254 }
255 value = vu->last_falloff;
256 vu->last_falltime = time;
257 vu->falling = vu->last_falloff > 0.00000001;
258 } else {
259 // falloff disabled
260 vu->last_falloff = 0.f;
261 vu->last_falltime = 0.f;
262 value = value_orig;
263 vu->falling = false;
264 }
265
266 float draw = 0.f;
267 float draw_last = 0.f;
268
269 if(vu->vumeter_hold > 0.0) {
270 // peak hold timer
271 if(time - (long)(vu->vumeter_hold * 1000 * 1000) > vu->last_hold) {
272 // time's up, reset
273 vu->last_value = value;
274 vu->last_hold = time;
275 vu->holding = false;
276 vu->disp_value = value_orig;
277 }
278 if( vu->mode == VU_MONOCHROME_REVERSE ) {
279 if(value < vu->last_value) {
280 // value is above peak hold
281 vu->last_value = value;
282 vu->last_hold = time;
283 vu->holding = true;
284 }
285 draw = log10(1 + value * 9);
286 draw_last = log10(1 + vu->last_value * 9);
287
288 // blinder left -> hold LED
289 int hold_x = round((draw_last) * (led_w + led_m)); // add last led_m removed earlier
290 hold_x -= hold_x % led_s + led_m;
291 hold_x = std::max(0, hold_x);
292 cairo_rectangle( c, led_x, led_y, hold_x, led_h);
293
294 // blinder hold LED -> value
295 int val_x = round((1 - draw) * (led_w + led_m)); // add last led_m removed earlier
296 val_x -= val_x % led_s;
297 int blind_x = std::min(hold_x + led_s, led_w);
298 int blind_w = std::min(std::max(led_w - val_x - hold_x - led_s, 0), led_w);
299 cairo_rectangle(c, led_x + blind_x, led_y, blind_w, led_h);
300 } else if( vu->mode == VU_STANDARD_CENTER ) {
301 if(value > vu->last_value) {
302 // value is above peak hold
303 vu->last_value = value;
304 vu->last_hold = time;
305 vu->holding = true;
306 }
307 draw = log10(1 + value * 9);
308 int val_x = round((1 - draw) / 2.f * (led_w + led_m)); // add last led_m removed earlier
309 cairo_rectangle(c, led_x, led_y, val_x, led_h);
310 cairo_rectangle(c, led_x + led_w - val_x, led_y, val_x, led_h);
311
312 } else {
313 if(value > vu->last_value) {
314 // value is above peak hold
315 vu->last_value = value;
316 vu->last_hold = time;
317 vu->holding = true;
318 }
319 draw = log10(1 + value * 9);
320 draw_last = log10(1 + vu->last_value * 9);
321
322 int hold_x = round((1 - draw_last) * (led_w + led_m)); // add last led_m removed earlier
323 hold_x -= hold_x % led_s;
324 int val_x = round(draw * (led_w + led_m)); // add last led_m removed earlier
325 val_x -= val_x % led_s;
326 int blind_w = led_w - hold_x - led_s - val_x;
327 blind_w = std::min(std::max(blind_w, 0), led_w);
328 cairo_rectangle(c, led_x + val_x, led_y, blind_w, led_h);
329 cairo_rectangle( c, led_x + led_w - hold_x, led_y, hold_x, led_h);
330 }
331 } else {
332 // darken normally
333 float draw = log10(1 + value * 9);
334 if( vu->mode == VU_MONOCHROME_REVERSE )
335 cairo_rectangle( c, led_x, led_y, draw * led_w, led_h);
336 else if( vu->mode == VU_STANDARD_CENTER ) {
337 int val_x = round((1 - draw) / 2.f * (led_w + led_m)); // add last led_m removed earlier
338 cairo_rectangle(c, led_x, led_y, val_x, led_h);
339 cairo_rectangle(c, led_x + led_w - val_x, led_y, val_x, led_h);
340 } else
341 cairo_rectangle( c, led_x + draw * led_w, led_y, led_w * (1 - draw), led_h);
342 }
343 cairo_fill( c );
344
345 if (vu->vumeter_position)
346 {
347 char str[32];
348 if((vu->value > vu->disp_value and vu->mode != VU_MONOCHROME_REVERSE)
349 or (vu->value < vu->disp_value and vu->mode == VU_MONOCHROME_REVERSE))
350 vu->disp_value = vu->value;
351 if (vu->disp_value < 1.0 / 32768.0)
352 snprintf(str, sizeof(str), "-inf");
353 else
354 snprintf(str, sizeof(str), "%0.2f", dsp::amp2dB(vu->disp_value));
355 // draw value as number
356 cairo_text_extents(c, str, &extents);
357 cairo_move_to(c, text_x + (text_w - extents.width) / 2.0, text_y);
358 GtkStateType state;
359 if(vu->disp_value > 1.f and vu->mode != VU_MONOCHROME_REVERSE)
360 state = GTK_STATE_ACTIVE;
361 else
362 state = GTK_STATE_NORMAL;
363 get_fg_color(widget, &state, &r, &g, &b);
364 cairo_set_source_rgba (c, r, g, b, 1);
365 cairo_show_text(c, str);
366 cairo_fill(c);
367 }
368 cairo_destroy(c);
369 //gtk_paint_shadow(widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN, NULL, widget, NULL, ox - 2, oy - 2, sx + 4, sy + 4);
370 //printf("exposed %p %d+%d\n", widget->window, widget->allocation.x, widget->allocation.y);
371
372 return TRUE;
373 }
374
375 static void
calf_vumeter_size_request(GtkWidget * widget,GtkRequisition * requisition)376 calf_vumeter_size_request (GtkWidget *widget,
377 GtkRequisition *requisition)
378 {
379 g_assert(CALF_IS_VUMETER(widget));
380 CalfVUMeter *self = CALF_VUMETER(widget);
381 requisition->width = self->vumeter_width;
382 requisition->height = self->vumeter_height;
383 }
384
385 static void
calf_vumeter_unrealize(GtkWidget * widget,CalfVUMeter * vu)386 calf_vumeter_unrealize (GtkWidget *widget, CalfVUMeter *vu)
387 {
388 if( vu->cache_surface )
389 cairo_surface_destroy( vu->cache_surface );
390 vu->cache_surface = NULL;
391 if( vu->cache_overlay )
392 cairo_surface_destroy( vu->cache_overlay );
393 vu->cache_overlay = NULL;
394 }
395
396 static void
calf_vumeter_size_allocate(GtkWidget * widget,GtkAllocation * allocation)397 calf_vumeter_size_allocate (GtkWidget *widget,
398 GtkAllocation *allocation)
399 {
400 g_assert(CALF_IS_VUMETER(widget));
401 CalfVUMeter *vu = CALF_VUMETER(widget);
402
403 GtkWidgetClass *parent_class = (GtkWidgetClass *) g_type_class_peek_parent( CALF_VUMETER_GET_CLASS( vu ) );
404
405 parent_class->size_allocate( widget, allocation );
406
407 calf_vumeter_unrealize(widget, vu);
408 }
409
410 static void
calf_vumeter_class_init(CalfVUMeterClass * klass)411 calf_vumeter_class_init (CalfVUMeterClass *klass)
412 {
413 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
414 widget_class->expose_event = calf_vumeter_expose;
415 widget_class->size_request = calf_vumeter_size_request;
416 widget_class->size_allocate = calf_vumeter_size_allocate;
417 gtk_widget_class_install_style_property(
418 widget_class, g_param_spec_float("border-radius", "Border Radius", "Generate round edges",
419 0, 24, 4, GParamFlags(G_PARAM_READWRITE)));
420 gtk_widget_class_install_style_property(
421 widget_class, g_param_spec_float("bevel", "Bevel", "Bevel the object",
422 -2, 2, 0.2, GParamFlags(G_PARAM_READWRITE)));
423 gtk_widget_class_install_style_property(
424 widget_class, g_param_spec_float("glass", "Glass", "Glass effect on top",
425 0, 1, 1, GParamFlags(G_PARAM_READWRITE)));
426 }
427
428 static void
calf_vumeter_init(CalfVUMeter * self)429 calf_vumeter_init (CalfVUMeter *self)
430 {
431 GtkWidget *widget = GTK_WIDGET(self);
432 //GTK_WIDGET_SET_FLAGS (widget, GTK_NO_WINDOW);
433 widget->requisition.width = self->vumeter_width;
434 widget->requisition.height = self->vumeter_height;
435 self->cache_surface = NULL;
436 self->falling = false;
437 self->holding = false;
438 self->meter_width = 0;
439 self->disp_value = 0.f;
440 self->value = 0.f;
441 gtk_widget_set_has_window(widget, FALSE);
442 g_signal_connect(GTK_OBJECT(widget), "unrealize", G_CALLBACK(calf_vumeter_unrealize), (gpointer)self);
443 }
444
445 GtkWidget *
calf_vumeter_new()446 calf_vumeter_new()
447 {
448 return GTK_WIDGET( g_object_new (CALF_TYPE_VUMETER, NULL ));
449 }
450
451 GType
calf_vumeter_get_type(void)452 calf_vumeter_get_type (void)
453 {
454 static GType type = 0;
455 if (!type) {
456 static const GTypeInfo type_info = {
457 sizeof(CalfVUMeterClass),
458 NULL, /* base_init */
459 NULL, /* base_finalize */
460 (GClassInitFunc)calf_vumeter_class_init,
461 NULL, /* class_finalize */
462 NULL, /* class_data */
463 sizeof(CalfVUMeter),
464 0, /* n_preallocs */
465 (GInstanceInitFunc)calf_vumeter_init
466 };
467
468 GTypeInfo *type_info_copy = new GTypeInfo(type_info);
469
470 for (int i = 0; ; i++) {
471 const char *name = "CalfVUMeter";
472 //char *name = g_strdup_printf("CalfVUMeter%u%d", ((unsigned int)(intptr_t)calf_vumeter_class_init) >> 16, i);
473 if (g_type_from_name(name)) {
474 //free(name);
475 continue;
476 }
477 type = g_type_register_static( GTK_TYPE_DRAWING_AREA,
478 name,
479 type_info_copy,
480 (GTypeFlags)0);
481 //free(name);
482 break;
483 }
484 }
485 return type;
486 }
487
calf_vumeter_set_value(CalfVUMeter * meter,float value)488 extern void calf_vumeter_set_value(CalfVUMeter *meter, float value)
489 {
490 if (value != meter->value or meter->holding or meter->falling)
491 {
492 meter->value = value;
493 gtk_widget_queue_draw(GTK_WIDGET(meter));
494 }
495 }
496
calf_vumeter_get_value(CalfVUMeter * meter)497 extern float calf_vumeter_get_value(CalfVUMeter *meter)
498 {
499 return meter->value;
500 }
501
calf_vumeter_set_mode(CalfVUMeter * meter,CalfVUMeterMode mode)502 extern void calf_vumeter_set_mode(CalfVUMeter *meter, CalfVUMeterMode mode)
503 {
504 if (mode != meter->mode)
505 {
506 meter->mode = mode;
507 if(mode == VU_MONOCHROME_REVERSE) {
508 meter->value = 1.f;
509 meter->last_value = 1.f;
510 } else {
511 meter->value = 0.f;
512 meter->last_value = 0.f;
513 }
514 meter->vumeter_falloff = 0.f;
515 meter->last_falloff = (long)0;
516 meter->last_hold = (long)0;
517 gtk_widget_queue_draw(GTK_WIDGET(meter));
518 }
519 }
520
calf_vumeter_get_mode(CalfVUMeter * meter)521 extern CalfVUMeterMode calf_vumeter_get_mode(CalfVUMeter *meter)
522 {
523 return meter->mode;
524 }
525
calf_vumeter_set_falloff(CalfVUMeter * meter,float value)526 extern void calf_vumeter_set_falloff(CalfVUMeter *meter, float value)
527 {
528 if (value != meter->vumeter_falloff)
529 {
530 meter->vumeter_falloff = value;
531 gtk_widget_queue_draw(GTK_WIDGET(meter));
532 }
533 }
534
calf_vumeter_get_falloff(CalfVUMeter * meter)535 extern float calf_vumeter_get_falloff(CalfVUMeter *meter)
536 {
537 return meter->vumeter_falloff;
538 }
539
calf_vumeter_set_hold(CalfVUMeter * meter,float value)540 extern void calf_vumeter_set_hold(CalfVUMeter *meter, float value)
541 {
542 if (value != meter->vumeter_hold)
543 {
544 meter->vumeter_hold = value;
545 gtk_widget_queue_draw(GTK_WIDGET(meter));
546 }
547 }
548
calf_vumeter_get_hold(CalfVUMeter * meter)549 extern float calf_vumeter_get_hold(CalfVUMeter *meter)
550 {
551 return meter->vumeter_hold;
552 }
553
calf_vumeter_set_width(CalfVUMeter * meter,int value)554 extern void calf_vumeter_set_width(CalfVUMeter *meter, int value)
555 {
556 if (value != meter->vumeter_width)
557 {
558 meter->vumeter_width = value;
559 gtk_widget_queue_draw(GTK_WIDGET(meter));
560 }
561 }
562
calf_vumeter_get_width(CalfVUMeter * meter)563 extern int calf_vumeter_get_width(CalfVUMeter *meter)
564 {
565 return meter->vumeter_width;
566 }
567
calf_vumeter_set_height(CalfVUMeter * meter,int value)568 extern void calf_vumeter_set_height(CalfVUMeter *meter, int value)
569 {
570 if (value != meter->vumeter_height)
571 {
572 meter->vumeter_height = value;
573 gtk_widget_queue_draw(GTK_WIDGET(meter));
574 }
575 }
576
calf_vumeter_get_height(CalfVUMeter * meter)577 extern int calf_vumeter_get_height(CalfVUMeter *meter)
578 {
579 return meter->vumeter_height;
580 }
calf_vumeter_set_position(CalfVUMeter * meter,int value)581 extern void calf_vumeter_set_position(CalfVUMeter *meter, int value)
582 {
583 if (value != meter->vumeter_height)
584 {
585 meter->vumeter_position = value;
586 gtk_widget_queue_draw(GTK_WIDGET(meter));
587 }
588 }
589
calf_vumeter_get_position(CalfVUMeter * meter)590 extern int calf_vumeter_get_position(CalfVUMeter *meter)
591 {
592 return meter->vumeter_position;
593 }
594