1 /*
2 
3     This widget provides peak meters
4 
5     (c) Fraser Stuart 2009
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     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
23 #include "stdlib.h"
24 #include "string.h"
25 #include "widgets.h"
26 #include "meter-peak.h"
27 
28 
29 static void 	inv_meter_class_init(InvMeterClass *klass);
30 static void 	inv_meter_init(InvMeter *meter);
31 static void 	inv_meter_size_request(GtkWidget *widget, GtkRequisition *requisition);
32 static void 	inv_meter_size_allocate(GtkWidget *widget, GtkAllocation *allocation);
33 static void 	inv_meter_realize(GtkWidget *widget);
34 static gboolean inv_meter_expose(GtkWidget *widget,GdkEventExpose *event);
35 static void 	inv_meter_paint(GtkWidget *widget, gint drawmode);
36 static void	inv_meter_destroy(GtkObject *object);
37 static void	inv_meter_colour_tozero(GtkWidget *widget, gint bypass, gint pos, gint on, struct colour *led);
38 static void	inv_meter_colour_fromzero(GtkWidget *widget, gint bypass, gint pos, gint on, struct colour *led);
39 static void	inv_meter_colour_bigtozero(GtkWidget *widget, gint bypass, gint pos, gint on, struct colour *led);
40 
41 
42 GtkType
inv_meter_get_type(void)43 inv_meter_get_type(void)
44 {
45 	static GType inv_meter_type = 0;
46 	char *name;
47 	int i;
48 
49 
50 	if (!inv_meter_type)
51 	{
52 		static const GTypeInfo type_info = {
53 			sizeof(InvMeterClass),
54 			NULL, /* base_init */
55 			NULL, /* base_finalize */
56 			(GClassInitFunc)inv_meter_class_init,
57 			NULL, /* class_finalize */
58 			NULL, /* class_data */
59 			sizeof(InvMeter),
60 			0,    /* n_preallocs */
61 			(GInstanceInitFunc)inv_meter_init
62 		};
63 		for (i = 0; ; i++) {
64 			name = g_strdup_printf("InvMeter-%p-%d",inv_meter_class_init, i);
65 			if (g_type_from_name(name)) {
66 				free(name);
67 				continue;
68 			}
69 			inv_meter_type = g_type_register_static(GTK_TYPE_WIDGET,name,&type_info,(GTypeFlags)0);
70 			free(name);
71 			break;
72 		}
73 	}
74 	return inv_meter_type;
75 }
76 
77 void
inv_meter_set_bypass(InvMeter * meter,gint num)78 inv_meter_set_bypass(InvMeter *meter, gint num)
79 {
80 	if(meter->bypass != num) {
81 		meter->bypass = num;
82 		switch(meter->mode) {
83 			case INV_METER_DRAW_MODE_TOZERO:
84 				meter->LdB=-90;
85 				meter->RdB=-90;
86 				break;
87 			case INV_METER_DRAW_MODE_FROMZERO:
88 				meter->LdB=0;
89 				meter->RdB=0;
90 				break;
91 		}
92 	}
93 }
94 
95 void
inv_meter_set_channels(InvMeter * meter,gint num)96 inv_meter_set_channels(InvMeter *meter, gint num)
97 {
98 	meter->channels = num;
99 }
100 
101 void
inv_meter_set_mode(InvMeter * meter,gint num)102 inv_meter_set_mode(InvMeter *meter, gint num)
103 {
104 	meter->mode = num;
105 }
106 
107 void
inv_meter_set_LdB(InvMeter * meter,float num)108 inv_meter_set_LdB(InvMeter *meter, float num)
109 {
110 	meter->LdB = num;
111 	if(GTK_WIDGET_REALIZED(meter))
112 		inv_meter_paint(GTK_WIDGET(meter),INV_METER_DRAW_L);
113 }
114 
115 void
inv_meter_set_RdB(InvMeter * meter,float num)116 inv_meter_set_RdB(InvMeter *meter, float num)
117 {
118 	meter->RdB = num;
119 	if(GTK_WIDGET_REALIZED(meter))
120 		inv_meter_paint(GTK_WIDGET(meter),INV_METER_DRAW_R);
121 }
122 
123 
inv_meter_new()124 GtkWidget * inv_meter_new()
125 {
126 	return GTK_WIDGET(gtk_type_new(inv_meter_get_type()));
127 }
128 
129 
130 static void
inv_meter_class_init(InvMeterClass * klass)131 inv_meter_class_init(InvMeterClass *klass)
132 {
133 	GtkWidgetClass *widget_class;
134 	GtkObjectClass *object_class;
135 
136 
137 	widget_class = (GtkWidgetClass *) klass;
138 	object_class = (GtkObjectClass *) klass;
139 
140 	widget_class->realize = inv_meter_realize;
141 	widget_class->size_request = inv_meter_size_request;
142 	widget_class->size_allocate = inv_meter_size_allocate;
143 	widget_class->expose_event = inv_meter_expose;
144 
145 	object_class->destroy = inv_meter_destroy;
146 }
147 
148 
149 static void
inv_meter_init(InvMeter * meter)150 inv_meter_init(InvMeter *meter)
151 {
152 	meter->bypass = INV_PLUGIN_ACTIVE;
153 	meter->mode=INV_METER_DRAW_MODE_TOZERO;
154 	meter->channels = 1;
155 	meter->LdB = -90;
156 	meter->RdB = -90;
157 	meter->lastLpos = 1;
158 	meter->lastRpos = 1;
159 
160 
161 	meter->mOff60.R =0.1;	meter->mOff60.G =0.1;	meter->mOff60.B =0.4;
162 	meter->mOn60.R  =-0.1;	meter->mOn60.G  =-0.1;	meter->mOn60.B  =0.6;
163 
164 	meter->mOff12.R =0.2; 	meter->mOff12.G =0.3;	meter->mOff12.B =0.4;
165 	meter->mOn12.R  =-0.1;	meter->mOn12.G  =0.3;	meter->mOn12.B  =0.6;
166 
167 	meter->mOff6.R =0.2; 	meter->mOff6.G =0.4;	meter->mOff6.B =0.2;
168 	meter->mOn6.R  =0.1;	meter->mOn6.G  =0.6;	meter->mOn6.B  =-0.1;
169 
170 	meter->mOff0.R  =0.5;	meter->mOff0.G  =0.5;	meter->mOff0.B  =0.0;
171 	meter->mOn0.R   =0.5;	meter->mOn0.G   =0.5;	meter->mOn0.B   =0.0;
172 
173 	meter->overOff.R=0.4;	meter->overOff.G=0.2;	meter->overOff.B=0.0;
174 	meter->overOn.R =0.6;	meter->overOn.G =0.0;	meter->overOn.B =0.0;
175 
176 	meter->label_font_size=0;
177 	meter->scale_font_size=0;
178 
179 	gtk_widget_set_tooltip_markup(GTK_WIDGET(meter),"<span size=\"8000\">Peak Meter.</span>");
180 
181 }
182 
183 
184 static void
inv_meter_size_request(GtkWidget * widget,GtkRequisition * requisition)185 inv_meter_size_request(GtkWidget *widget,
186     GtkRequisition *requisition)
187 {
188 	g_return_if_fail(widget != NULL);
189 	g_return_if_fail(INV_IS_METER(widget));
190 	g_return_if_fail(requisition != NULL);
191 	switch(INV_METER(widget)->mode) {
192 		case INV_METER_DRAW_MODE_TOZERO:
193 		case INV_METER_DRAW_MODE_FROMZERO:
194 			requisition->width = 149;
195 			requisition->height = 37;
196 			break;
197 		case INV_METER_DRAW_MODE_BIGTOZERO:
198 			requisition->width = 308;
199 			requisition->height = 37;
200 			break;
201 	}
202 
203 }
204 
205 
206 static void
inv_meter_size_allocate(GtkWidget * widget,GtkAllocation * allocation)207 inv_meter_size_allocate(GtkWidget *widget,
208     GtkAllocation *allocation)
209 {
210 	g_return_if_fail(widget != NULL);
211 	g_return_if_fail(INV_IS_METER(widget));
212 	g_return_if_fail(allocation != NULL);
213 
214 	widget->allocation = *allocation;
215 
216 	if (GTK_WIDGET_REALIZED(widget)) {
217 		gdk_window_move_resize(
218 		   widget->window,
219 		   allocation->x, allocation->y,
220 		   allocation->width, allocation->height
221 		);
222 	}
223 }
224 
225 
226 static void
inv_meter_realize(GtkWidget * widget)227 inv_meter_realize(GtkWidget *widget)
228 {
229 	GdkWindowAttr attributes;
230 	guint attributes_mask;
231 
232 	g_return_if_fail(widget != NULL);
233 	g_return_if_fail(INV_IS_METER(widget));
234 
235 	GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
236 
237 	attributes.window_type = GDK_WINDOW_CHILD;
238 	attributes.x = widget->allocation.x;
239 	attributes.y = widget->allocation.y;
240 
241 	switch(INV_METER(widget)->mode) {
242 		case INV_METER_DRAW_MODE_TOZERO:
243 		case INV_METER_DRAW_MODE_FROMZERO:
244 			attributes.width = 149;
245 			attributes.height = 37;
246 			break;
247 		case INV_METER_DRAW_MODE_BIGTOZERO:
248 			attributes.width = 308;
249 			attributes.height = 37;
250 			break;
251 	}
252 
253 	attributes.wclass = GDK_INPUT_OUTPUT;
254 	attributes.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK;
255 
256 	attributes_mask = GDK_WA_X | GDK_WA_Y;
257 
258 	widget->window = gdk_window_new(
259 	  gtk_widget_get_parent_window (widget),
260 	  & attributes, attributes_mask
261 	);
262 
263 	gdk_window_set_user_data(widget->window, widget);
264 
265 	widget->style = gtk_style_attach(widget->style, widget->window);
266 	gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
267 }
268 
269 
270 static gboolean
inv_meter_expose(GtkWidget * widget,GdkEventExpose * event)271 inv_meter_expose(GtkWidget *widget, GdkEventExpose *event)
272 {
273 	g_return_val_if_fail(widget != NULL, FALSE);
274 	g_return_val_if_fail(INV_IS_METER(widget), FALSE);
275 	g_return_val_if_fail(event != NULL, FALSE);
276 
277 	inv_meter_paint(widget,INV_METER_DRAW_ALL);
278 
279 	return FALSE;
280 }
281 
282 
283 static void
inv_meter_paint(GtkWidget * widget,gint drawmode)284 inv_meter_paint(GtkWidget *widget, gint drawmode)
285 {
286 	gint 		bypass;
287 	gint 		mode;
288 	gint 		channels;
289 	gint 		Lpos=0;
290 	gint 		Rpos=0;
291 	gint 		lastLpos;
292 	gint 		lastRpos;
293 
294 	cairo_t 	*cr;
295 	gint 		Lon,Ron,min,max,i;
296 	struct colour	led;
297 	GtkStyle	*style;
298 	char 		label[10];
299 	cairo_text_extents_t extents;
300 
301 	style = gtk_widget_get_style(widget);
302 	bypass = INV_METER(widget)->bypass;
303 	mode = INV_METER(widget)->mode;
304 	channels = INV_METER(widget)->channels;
305 
306 	switch(mode) {
307 		case INV_METER_DRAW_MODE_TOZERO:
308 			Lpos = bypass==INV_PLUGIN_ACTIVE ? (gint)(INV_METER(widget)->LdB+60.51) : 0 ;  /* -60 to +6 db step 1db  = 67 points*/
309 			Rpos = bypass==INV_PLUGIN_ACTIVE ? (gint)(INV_METER(widget)->RdB+60.51) : 0 ;
310 			break;
311 		case INV_METER_DRAW_MODE_FROMZERO:
312 			Lpos = bypass==INV_PLUGIN_ACTIVE ? (gint)(2*(INV_METER(widget)->LdB)+71.51): 72 ; /* -35.5 to 0 db step 0.5db = 71 points */
313 			Rpos = bypass==INV_PLUGIN_ACTIVE ? (gint)(2*(INV_METER(widget)->RdB)+71.51): 72 ;
314 			break;
315 		case INV_METER_DRAW_MODE_BIGTOZERO:
316 			Lpos = bypass==INV_PLUGIN_ACTIVE ? (gint)(2*(INV_METER(widget)->LdB)+120.51) : 0 ;  /* -60 to +12 db step 0.5db  = 145 points*/
317 			Rpos = bypass==INV_PLUGIN_ACTIVE ? (gint)(2*(INV_METER(widget)->RdB)+120.51) : 0 ;
318 			break;
319 	}
320 
321 
322 	lastLpos = INV_METER(widget)->lastLpos;
323 	lastRpos = INV_METER(widget)->lastRpos;
324 
325 	cr = gdk_cairo_create(widget->window);
326 
327 	if(INV_METER(widget)->label_font_size==0) {
328 		INV_METER(widget)->label_font_size=inv_choose_font_size(cr,"sans-serif",CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_NORMAL,99.0,6.1,"0");
329 	}
330 	if(INV_METER(widget)->scale_font_size==0) {
331 		INV_METER(widget)->scale_font_size=inv_choose_font_size(cr,"sans-serif",CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_NORMAL,99.0,6.1,"0");
332 	}
333 
334 
335 	switch(drawmode) {
336 		case INV_METER_DRAW_ALL:
337 
338 			gdk_cairo_set_source_color(cr,&style->bg[GTK_STATE_NORMAL]);
339 			cairo_paint(cr);
340 			switch(mode) {
341 				case INV_METER_DRAW_MODE_TOZERO:
342 				case INV_METER_DRAW_MODE_FROMZERO:
343 					cairo_set_source_rgb(cr, 0, 0, 0);
344 					cairo_rectangle(cr, 0, 0, 149, 24);
345 					cairo_fill(cr);
346 
347 					cairo_new_path(cr);
348 
349 					cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
350 					cairo_set_antialias (cr,CAIRO_ANTIALIAS_NONE);
351 					cairo_set_line_width(cr,1);
352 
353 					gdk_cairo_set_source_color(cr,&style->dark[GTK_STATE_NORMAL]);
354 					cairo_move_to(cr, 0, 23);
355 					cairo_line_to(cr, 0, 0);
356 					cairo_line_to(cr, 148, 0);
357 					cairo_stroke(cr);
358 
359 					gdk_cairo_set_source_color(cr,&style->light[GTK_STATE_NORMAL]);
360 					cairo_move_to(cr, 0, 23);
361 					cairo_line_to(cr, 148, 23);
362 					cairo_line_to(cr, 148, 0);
363 					cairo_stroke(cr);
364 					break;
365 				case INV_METER_DRAW_MODE_BIGTOZERO:
366 					cairo_set_source_rgb(cr, 0, 0, 0);
367 					cairo_rectangle(cr, 0, 0, 303, 24);
368 					cairo_fill(cr);
369 
370 					cairo_new_path(cr);
371 
372 					cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
373 					cairo_set_antialias (cr,CAIRO_ANTIALIAS_NONE);
374 					cairo_set_line_width(cr,1);
375 
376 					gdk_cairo_set_source_color(cr,&style->dark[GTK_STATE_NORMAL]);
377 					cairo_move_to(cr, 0, 23);
378 					cairo_line_to(cr, 0, 0);
379 					cairo_line_to(cr, 302, 0);
380 					cairo_stroke(cr);
381 
382 					gdk_cairo_set_source_color(cr,&style->light[GTK_STATE_NORMAL]);
383 					cairo_move_to(cr, 0, 23);
384 					cairo_line_to(cr, 302, 23);
385 					cairo_line_to(cr, 302, 0);
386 					cairo_stroke(cr);
387 					break;
388 			}
389 
390 
391 			cairo_set_antialias (cr,CAIRO_ANTIALIAS_DEFAULT);
392 			cairo_new_path(cr);
393 
394 			cairo_select_font_face(cr,"sans-serif",CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_NORMAL);
395 			cairo_set_font_size(cr,INV_METER(widget)->scale_font_size);
396 
397 			switch(mode) {
398 				case INV_METER_DRAW_MODE_TOZERO:
399 					for(i=0;i<=5;i++) {
400 						if(inv_choose_light_dark(&style->bg[GTK_STATE_NORMAL],&style->light[GTK_STATE_NORMAL],&style->dark[GTK_STATE_NORMAL])==1) {
401 							gdk_cairo_set_source_color(cr,&style->light[GTK_STATE_NORMAL]);
402 						} else {
403 							gdk_cairo_set_source_color(cr,&style->dark[GTK_STATE_NORMAL]);
404 						}
405 						cairo_rectangle(cr, 10+(i*24), 25, 1, 2);
406 						cairo_fill(cr);
407 
408 						if(bypass==INV_PLUGIN_BYPASS) {
409 							gdk_cairo_set_source_color(cr,&style->fg[GTK_STATE_INSENSITIVE]);
410 						} else {
411 							gdk_cairo_set_source_color(cr,&style->fg[GTK_STATE_NORMAL]);
412 						}
413 						sprintf(label,"%i",(12*i)-60);
414 						cairo_text_extents (cr,label,&extents);
415 						cairo_move_to(cr,10+(i*24)-(extents.width/2),35);
416 						cairo_show_text(cr,label);
417 					}
418 					break;
419 
420 				case INV_METER_DRAW_MODE_FROMZERO:
421 					for(i=0;i<=5;i++) {
422 						if(inv_choose_light_dark(&style->bg[GTK_STATE_NORMAL],&style->light[GTK_STATE_NORMAL],&style->dark[GTK_STATE_NORMAL])==1) {
423 							gdk_cairo_set_source_color(cr,&style->light[GTK_STATE_NORMAL]);
424 						} else {
425 							gdk_cairo_set_source_color(cr,&style->dark[GTK_STATE_NORMAL]);
426 						}
427 						cairo_rectangle(cr, 24+(i*24), 25, 1, 2);
428 						cairo_fill(cr);
429 
430 						if(bypass==INV_PLUGIN_BYPASS) {
431 							gdk_cairo_set_source_color(cr,&style->fg[GTK_STATE_INSENSITIVE]);
432 						} else {
433 							gdk_cairo_set_source_color(cr,&style->fg[GTK_STATE_NORMAL]);
434 						}
435 						sprintf(label,"%i",30-(6*i));
436 						cairo_text_extents (cr,label,&extents);
437 						cairo_move_to(cr,24+(i*24)-(extents.width/2),35);
438 						cairo_show_text(cr,label);
439 					}
440 					break;
441 				case INV_METER_DRAW_MODE_BIGTOZERO:
442 					for(i=0;i<=12;i++) {
443 						if(inv_choose_light_dark(&style->bg[GTK_STATE_NORMAL],&style->light[GTK_STATE_NORMAL],&style->dark[GTK_STATE_NORMAL])==1) {
444 							gdk_cairo_set_source_color(cr,&style->light[GTK_STATE_NORMAL]);
445 						} else {
446 							gdk_cairo_set_source_color(cr,&style->dark[GTK_STATE_NORMAL]);
447 						}
448 						cairo_rectangle(cr, 10+(i*24), 25, 1, 2);
449 						cairo_fill(cr);
450 
451 						if(bypass==INV_PLUGIN_BYPASS) {
452 							gdk_cairo_set_source_color(cr,&style->fg[GTK_STATE_INSENSITIVE]);
453 						} else {
454 							gdk_cairo_set_source_color(cr,&style->fg[GTK_STATE_NORMAL]);
455 						}
456 						if(i>10) {
457 							sprintf(label,"+%i",(6*i)-60);
458 						} else {
459 							sprintf(label,"%i",(6*i)-60);
460 						}
461 						cairo_text_extents (cr,label,&extents);
462 						cairo_move_to(cr,10+(i*24)-(extents.width/2),35);
463 						cairo_show_text(cr,label);
464 					}
465 					break;
466 			}
467 
468 			if(bypass==INV_PLUGIN_BYPASS) {
469 				cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
470 			} else {
471 				cairo_set_source_rgb(cr, 1, 1, 1);
472 			}
473 			cairo_select_font_face(cr,"sans-serif",CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_NORMAL);
474 			cairo_set_font_size(cr,INV_METER(widget)->label_font_size);
475 
476 			switch(mode) {
477 				case INV_METER_DRAW_MODE_TOZERO:
478 					switch(channels)
479 					{
480 						case 1:
481 							cairo_move_to(cr,3,15);
482 							cairo_show_text(cr,"M");
483 							break;
484 						case 2:
485 							cairo_move_to(cr,3,10);
486 							cairo_show_text(cr,"L");
487 							cairo_move_to(cr,3,20);
488 							cairo_show_text(cr,"R");
489 							break;
490 					}
491 
492 					for ( i = 1; i <= 67; i++)
493 					{
494 						switch(channels)
495 						{
496 							case 1:
497 								Lon = i <= Lpos ? 1 : 0;
498 
499 								inv_meter_colour_tozero(widget, bypass, i, Lon, &led);
500 								cairo_set_source_rgb(cr, led.R, led.G, led.B);
501 								cairo_rectangle(cr, 10+(i*2), 3, 1, 18);
502 								cairo_fill(cr);
503 								break;
504 							case 2:
505 								Lon = i <= Lpos ? 1 : 0;
506 								Ron = i <= Rpos ? 1 : 0;
507 
508 								inv_meter_colour_tozero(widget, bypass, i, Lon, &led);
509 								cairo_set_source_rgb(cr, led.R, led.G, led.B);
510 								cairo_rectangle(cr, 10+(i*2), 3, 1, 8);
511 								cairo_fill(cr);
512 
513 								inv_meter_colour_tozero(widget, bypass, i, Ron, &led);
514 								cairo_set_source_rgb(cr, led.R, led.G, led.B);
515 								cairo_rectangle(cr, 10+(i*2), 13, 1, 8);
516 								cairo_fill(cr);
517 								break;
518 						}
519 					}
520 					break;
521 
522 				case INV_METER_DRAW_MODE_FROMZERO:
523 					for ( i = 1; i <= 71; i++)
524 					{
525 						switch(channels)
526 						{
527 							case 1:
528 								Lon = i > Lpos ? 1 : 0;
529 
530 								inv_meter_colour_fromzero(widget, bypass, i, Lon, &led);
531 								cairo_set_source_rgb(cr, led.R, led.G, led.B);
532 								cairo_rectangle(cr, 2+(i*2), 3, 1, 18);
533 								cairo_fill(cr);
534 								break;
535 							case 2:
536 								Lon = i > Lpos ? 1 : 0;
537 								Ron = i > Rpos ? 1 : 0;
538 
539 								inv_meter_colour_fromzero(widget, bypass, i, Lon, &led);
540 								cairo_set_source_rgb(cr, led.R, led.G, led.B);
541 								cairo_rectangle(cr, 2+(i*2), 3, 1, 8);
542 								cairo_fill(cr);
543 
544 								inv_meter_colour_fromzero(widget, bypass, i, Ron, &led);
545 								cairo_set_source_rgb(cr, led.R, led.G, led.B);
546 								cairo_rectangle(cr, 2+(i*2), 13, 1, 8);
547 								cairo_fill(cr);
548 								break;
549 						}
550 					}
551 					break;
552 				case INV_METER_DRAW_MODE_BIGTOZERO:
553 					switch(channels)
554 					{
555 						case 1:
556 							cairo_move_to(cr,3,15);
557 							cairo_show_text(cr,"M");
558 							break;
559 						case 2:
560 							cairo_move_to(cr,3,10);
561 							cairo_show_text(cr,"L");
562 							cairo_move_to(cr,3,20);
563 							cairo_show_text(cr,"R");
564 							break;
565 					}
566 
567 					for ( i = 1; i <= 144; i++)
568 					{
569 						switch(channels)
570 						{
571 							case 1:
572 								Lon = i <= Lpos ? 1 : 0;
573 
574 								inv_meter_colour_bigtozero(widget, bypass, i, Lon, &led);
575 								cairo_set_source_rgb(cr, led.R, led.G, led.B);
576 								cairo_rectangle(cr, 10+(i*2), 3, 1, 18);
577 								cairo_fill(cr);
578 								break;
579 							case 2:
580 								Lon = i <= Lpos ? 1 : 0;
581 								Ron = i <= Rpos ? 1 : 0;
582 
583 								inv_meter_colour_bigtozero(widget, bypass, i, Lon, &led);
584 								cairo_set_source_rgb(cr, led.R, led.G, led.B);
585 								cairo_rectangle(cr, 10+(i*2), 3, 1, 8);
586 								cairo_fill(cr);
587 
588 								inv_meter_colour_bigtozero(widget, bypass, i, Ron, &led);
589 								cairo_set_source_rgb(cr, led.R, led.G, led.B);
590 								cairo_rectangle(cr, 10+(i*2), 13, 1, 8);
591 								cairo_fill(cr);
592 								break;
593 						}
594 					}
595 					break;
596 			}
597 			INV_METER(widget)->lastLpos = Lpos;
598 			INV_METER(widget)->lastRpos = Rpos;
599 			break;
600 
601 		case INV_METER_DRAW_L:
602 			switch(mode) {
603 				case INV_METER_DRAW_MODE_TOZERO:
604 					min = lastLpos < Lpos ? lastLpos : Lpos;
605 					max = lastLpos > Lpos ? lastLpos : Lpos;
606 					if(min<1) min=1;
607 					if(max<1) max=1;
608 					if(min>67) min=67;
609 					if(max>67) max=67;
610 					if(min != max || max == 1 ) {
611 						for ( i = min ; i <= max; i++)
612 						{
613 							Lon = i <= Lpos ? 1 : 0;
614 							inv_meter_colour_tozero(widget, bypass, i, Lon, &led);
615 							cairo_set_source_rgb(cr, led.R, led.G, led.B);
616 							switch(channels)
617 							{
618 								case 1:
619 									cairo_rectangle(cr, 10+(i*2), 3, 1, 18);
620 									break;
621 								case 2:
622 									cairo_rectangle(cr, 10+(i*2), 3, 1, 8);
623 									break;
624 							}
625 							cairo_fill(cr);
626 						}
627 					}
628 					break;
629 				case INV_METER_DRAW_MODE_FROMZERO:
630 					min = lastLpos < Lpos ? lastLpos : Lpos;
631 					max = lastLpos > Lpos ? lastLpos : Lpos;
632 					if(min<1) min=1;
633 					if(max<1) max=1;
634 					if(min>71) min=71;
635 					if(max>71) max=71;
636 					if(min != max || max == 1 ) {
637 						for ( i = min ; i <= max; i++)
638 						{
639 							Lon = i > Lpos ? 1 : 0;
640 							inv_meter_colour_fromzero(widget, bypass, i, Lon, &led);
641 							cairo_set_source_rgb(cr, led.R, led.G, led.B);
642 							switch(channels)
643 							{
644 								case 1:
645 									cairo_rectangle(cr, 2+(i*2), 3, 1, 18);
646 									break;
647 								case 2:
648 									cairo_rectangle(cr, 2+(i*2), 3, 1, 8);
649 									break;
650 							}
651 							cairo_fill(cr);
652 						}
653 					}
654 					break;
655 				case INV_METER_DRAW_MODE_BIGTOZERO:
656 					min = lastLpos < Lpos ? lastLpos : Lpos;
657 					max = lastLpos > Lpos ? lastLpos : Lpos;
658 					if(min<1) min=1;
659 					if(max<1) max=1;
660 					if(min>144) min=144;
661 					if(max>144) max=144;
662 					if(min != max || max == 1 ) {
663 						for ( i = min ; i <= max; i++)
664 						{
665 							Lon = i <= Lpos ? 1 : 0;
666 							inv_meter_colour_bigtozero(widget, bypass, i, Lon, &led);
667 							cairo_set_source_rgb(cr, led.R, led.G, led.B);
668 							switch(channels)
669 							{
670 								case 1:
671 									cairo_rectangle(cr, 10+(i*2), 3, 1, 18);
672 									break;
673 								case 2:
674 									cairo_rectangle(cr, 10+(i*2), 3, 1, 8);
675 									break;
676 							}
677 							cairo_fill(cr);
678 						}
679 					}
680 					break;
681 			}
682 			INV_METER(widget)->lastLpos = Lpos;
683 			break;
684 
685 		case INV_METER_DRAW_R:
686 			switch(mode) {
687 				case INV_METER_DRAW_MODE_TOZERO:
688 					min = lastRpos < Rpos ? lastRpos : Rpos;
689 					max = lastRpos > Rpos ? lastRpos : Rpos;
690 					if(min<1) min=1;
691 					if(max<1) max=1;
692 					if(min>67) min=67;
693 					if(max>67) max=67;
694 					if(min != max || max == 1 ) {
695 						for ( i = min ; i <= max; i++)
696 						{
697 							Ron = i <= Rpos ? 1 : 0;
698 							inv_meter_colour_tozero(widget, bypass, i, Ron, &led);
699 							cairo_set_source_rgb(cr, led.R, led.G, led.B);
700 							cairo_rectangle(cr, 10+(i*2), 13, 1, 8);
701 							cairo_fill(cr);
702 						}
703 					}
704 					break;
705 				case INV_METER_DRAW_MODE_FROMZERO:
706 					min = lastRpos < Rpos ? lastRpos : Rpos;
707 					max = lastRpos > Rpos ? lastRpos : Rpos;
708 					if(min<1) min=1;
709 					if(max<1) max=1;
710 					if(min>71) min=71;
711 					if(max>71) max=71;
712 					if(min != max || max == 1 ) {
713 						for ( i = min ; i <= max; i++)
714 						{
715 							Ron = i > Rpos ? 1 : 0;
716 							inv_meter_colour_fromzero(widget, bypass, i, Ron, &led);
717 							cairo_set_source_rgb(cr, led.R, led.G, led.B);
718 							cairo_rectangle(cr, 2+(i*2), 13, 1, 8);
719 							cairo_fill(cr);
720 						}
721 					}
722 					break;
723 				case INV_METER_DRAW_MODE_BIGTOZERO:
724 					min = lastRpos < Rpos ? lastRpos : Rpos;
725 					max = lastRpos > Rpos ? lastRpos : Rpos;
726 					if(min<1) min=1;
727 					if(max<1) max=1;
728 					if(min>144) min=144;
729 					if(max>144) max=144;
730 					if(min != max || max == 1 ) {
731 						for ( i = min ; i <= max; i++)
732 						{
733 							Ron = i <= Rpos ? 1 : 0;
734 							inv_meter_colour_bigtozero(widget, bypass, i, Ron, &led);
735 							cairo_set_source_rgb(cr, led.R, led.G, led.B);
736 							cairo_rectangle(cr, 10+(i*2), 13, 1, 8);
737 							cairo_fill(cr);
738 						}
739 					}
740 					break;
741 			}
742 			INV_METER(widget)->lastRpos = Rpos;
743 			break;
744 
745 	}
746   	cairo_destroy(cr);
747 }
748 
749 
750 static void
inv_meter_destroy(GtkObject * object)751 inv_meter_destroy(GtkObject *object)
752 {
753 	InvMeter *meter;
754 	InvMeterClass *klass;
755 
756 	g_return_if_fail(object != NULL);
757 	g_return_if_fail(INV_IS_METER(object));
758 
759 	meter = INV_METER(object);
760 
761 	klass = gtk_type_class(gtk_widget_get_type());
762 
763 	if (GTK_OBJECT_CLASS(klass)->destroy) {
764 		(* GTK_OBJECT_CLASS(klass)->destroy) (object);
765 	}
766 }
767 
768 static void
inv_meter_colour_tozero(GtkWidget * widget,gint bypass,gint pos,gint on,struct colour * led)769 inv_meter_colour_tozero(GtkWidget *widget, gint bypass, gint pos, gint on, struct colour *led)
770 {
771 	float r1,r2;
772 	struct colour mOff60  = INV_METER(widget)->mOff60;
773 	struct colour mOn60   = INV_METER(widget)->mOn60;
774 	struct colour mOff12  = INV_METER(widget)->mOff12;
775 	struct colour mOn12   = INV_METER(widget)->mOn12;
776 	struct colour mOff6   = INV_METER(widget)->mOff6;
777 	struct colour mOn6    = INV_METER(widget)->mOn6;
778 	struct colour mOff0   = INV_METER(widget)->mOff0;
779 	struct colour mOn0    = INV_METER(widget)->mOn0;
780 	struct colour overOff = INV_METER(widget)->overOff;
781 	struct colour overOn  = INV_METER(widget)->overOn;
782 /*
783 	66 =  +6dB
784 	60 =   0dB
785 	51 =  -9dB
786 	42 = -18dB
787 */
788 	if(pos < 42)
789 	{
790 		r1=(42.0-(float)pos)/42.0;
791 		r2=(float)pos/42.0;
792 		led->R=(r1 * mOff60.R + (r2 * mOff12.R))  + (on * ((r1 * mOn60.R) + (r2 * mOn12.R))) ;
793 		led->G=(r1 * mOff60.G + (r2 * mOff12.G))  + (on * ((r1 * mOn60.G) + (r2 * mOn12.G))) ;
794 		led->B=(r1 * mOff60.B + (r2 * mOff12.B))  + (on * ((r1 * mOn60.B) + (r2 * mOn12.B))) ;
795 	}
796 
797 	else if (pos < 51)
798 	{
799 		r1=(51.0-(float)pos)/9.0;
800 		r2=((float)pos-42.0)/9.0;
801 		led->R=(r1 * mOff12.R + (r2 * mOff6.R))  + (on * ((r1 * mOn12.R) + (r2 * mOn6.R))) ;
802 		led->G=(r1 * mOff12.G + (r2 * mOff6.G))  + (on * ((r1 * mOn12.G) + (r2 * mOn6.G))) ;
803 		led->B=(r1 * mOff12.B + (r2 * mOff6.B))  + (on * ((r1 * mOn12.B) + (r2 * mOn6.B))) ;
804 	}
805 
806 	else if (pos < 60)
807 	{
808 		r1=(60.0-(float)pos)/9.0;
809 		r2=((float)pos-51.0)/9.0;
810 		led->R=(r1 * mOff6.R + (r2 * mOff0.R))  + (on * ((r1 * mOn6.R) + (r2 * mOn0.R))) ;
811 		led->G=(r1 * mOff6.G + (r2 * mOff0.G))  + (on * ((r1 * mOn6.G) + (r2 * mOn0.G))) ;
812 		led->B=(r1 * mOff6.B + (r2 * mOff0.B))  + (on * ((r1 * mOn6.B) + (r2 * mOn0.B))) ;
813 	}
814 	else
815 	{
816 		led->R=overOff.R + (on * overOn.R) ;
817 		led->G=overOff.G + (on * overOn.G) ;
818 		led->B=overOff.B + (on * overOn.B) ;
819 	}
820 
821 	if(bypass==INV_PLUGIN_BYPASS) {
822 		led->R=(led->R+led->G+led->B)/3;
823 		led->G=led->R;
824 		led->B=led->R;
825 	}
826 }
827 
828 static void
inv_meter_colour_fromzero(GtkWidget * widget,gint bypass,gint pos,gint on,struct colour * led)829 inv_meter_colour_fromzero(GtkWidget *widget, gint bypass, gint pos, gint on,  struct colour *led)
830 {
831 	float r1,r2;
832 	struct colour mOff60  = INV_METER(widget)->mOff60;
833 	struct colour mOn60   = INV_METER(widget)->mOn60;
834 	struct colour mOff12  = INV_METER(widget)->mOff12;
835 	struct colour mOn12   = INV_METER(widget)->mOn12;
836 	struct colour mOff6   = INV_METER(widget)->mOff6;
837 	struct colour mOn6    = INV_METER(widget)->mOn6;
838 	struct colour mOff0   = INV_METER(widget)->mOff0;
839 	struct colour mOn0    = INV_METER(widget)->mOn0;
840 	struct colour overOff = INV_METER(widget)->overOff;
841 	struct colour overOn  = INV_METER(widget)->overOn;
842 /*
843 	72 =   0dB
844 	60 =  -6dB
845 	48 = -12dB
846 	24 = -18dB
847 */
848 	if(pos < 24)
849 	{
850 		r1=(24.0-(float)pos)/24.0;
851 		r2=(float)pos/24.0;
852 		led->R=(r1 * overOff.R + (r2 * mOff0.R))  + (on * ((r1 * overOn.R) + (r2 * mOn0.R))) ;
853 		led->G=(r1 * overOff.G + (r2 * mOff0.G))  + (on * ((r1 * overOn.G) + (r2 * mOn0.G))) ;
854 		led->B=(r1 * overOff.B + (r2 * mOff0.B))  + (on * ((r1 * overOn.B) + (r2 * mOn0.B))) ;
855 	}
856 
857 	else if (pos < 48)
858 	{
859 		r1=(48.0-(float)pos)/24.0;
860 		r2=((float)pos-24.0)/24.0;
861 		led->R=(r1 * mOff0.R + (r2 * mOff6.R))  + (on * ((r1 * mOn0.R) + (r2 * mOn6.R))) ;
862 		led->G=(r1 * mOff0.G + (r2 * mOff6.G))  + (on * ((r1 * mOn0.G) + (r2 * mOn6.G))) ;
863 		led->B=(r1 * mOff0.B + (r2 * mOff6.B))  + (on * ((r1 * mOn0.B) + (r2 * mOn6.B))) ;
864 	}
865 
866 	else if (pos < 60)
867 	{
868 		r1=(60.0-(float)pos)/12.0;
869 		r2=((float)pos-48.0)/12.0;
870 		led->R=(r1 * mOff6.R + (r2 * mOff12.R))  + (on * ((r1 * mOn6.R) + (r2 * mOn12.R))) ;
871 		led->G=(r1 * mOff6.G + (r2 * mOff12.G))  + (on * ((r1 * mOn6.G) + (r2 * mOn12.G))) ;
872 		led->B=(r1 * mOff6.B + (r2 * mOff12.B))  + (on * ((r1 * mOn6.B) + (r2 * mOn12.B))) ;
873 	}
874 	else if (pos < 72)
875 	{
876 		r1=(72.0-(float)pos)/12.0;
877 		r2=((float)pos-60.0)/12.0;
878 		led->R=(r1 * mOff12.R + (r2 * mOff60.R))  + (on * ((r1 * mOn12.R) + (r2 * mOn60.R))) ;
879 		led->G=(r1 * mOff12.G + (r2 * mOff60.G))  + (on * ((r1 * mOn12.G) + (r2 * mOn60.G))) ;
880 		led->B=(r1 * mOff12.B + (r2 * mOff60.B))  + (on * ((r1 * mOn12.B) + (r2 * mOn60.B))) ;
881 	}
882 	else
883 	{
884 		led->R=mOff60.R  + (on * mOn60.R) ;
885 		led->G=mOff60.G  + (on * mOn60.G) ;
886 		led->B=mOff60.B  + (on * mOn60.B) ;
887 	}
888 	if(bypass==INV_PLUGIN_BYPASS) {
889 		led->R=(led->R+led->G+led->B)/3;
890 		led->G=led->R;
891 		led->B=led->R;
892 	}
893 }
894 
895 static void
inv_meter_colour_bigtozero(GtkWidget * widget,gint bypass,gint pos,gint on,struct colour * led)896 inv_meter_colour_bigtozero(GtkWidget *widget, gint bypass, gint pos, gint on, struct colour *led)
897 {
898 	float r1,r2;
899 	struct colour mOff60  = INV_METER(widget)->mOff60;
900 	struct colour mOn60   = INV_METER(widget)->mOn60;
901 	struct colour mOff12  = INV_METER(widget)->mOff12;
902 	struct colour mOn12   = INV_METER(widget)->mOn12;
903 	struct colour mOff6   = INV_METER(widget)->mOff6;
904 	struct colour mOn6    = INV_METER(widget)->mOn6;
905 	struct colour mOff0   = INV_METER(widget)->mOff0;
906 	struct colour mOn0    = INV_METER(widget)->mOn0;
907 	struct colour overOff = INV_METER(widget)->overOff;
908 	struct colour overOn  = INV_METER(widget)->overOn;
909 /*
910 	144 = +12dB
911 	120 =   0dB
912 	102 =  -9dB
913 	84  = -18dB
914 */
915 	if(pos < 84)
916 	{
917 		r1=(84.0-(float)pos)/84.0;
918 		r2=(float)pos/84.0;
919 		led->R=(r1 * mOff60.R + (r2 * mOff12.R))  + (on * ((r1 * mOn60.R) + (r2 * mOn12.R))) ;
920 		led->G=(r1 * mOff60.G + (r2 * mOff12.G))  + (on * ((r1 * mOn60.G) + (r2 * mOn12.G))) ;
921 		led->B=(r1 * mOff60.B + (r2 * mOff12.B))  + (on * ((r1 * mOn60.B) + (r2 * mOn12.B))) ;
922 	}
923 
924 	else if (pos < 102)
925 	{
926 		r1=(102.0-(float)pos)/18.0;
927 		r2=((float)pos-84.0)/18.0;
928 		led->R=(r1 * mOff12.R + (r2 * mOff6.R))  + (on * ((r1 * mOn12.R) + (r2 * mOn6.R))) ;
929 		led->G=(r1 * mOff12.G + (r2 * mOff6.G))  + (on * ((r1 * mOn12.G) + (r2 * mOn6.G))) ;
930 		led->B=(r1 * mOff12.B + (r2 * mOff6.B))  + (on * ((r1 * mOn12.B) + (r2 * mOn6.B))) ;
931 	}
932 
933 	else if (pos < 120)
934 	{
935 		r1=(120.0-(float)pos)/18.0;
936 		r2=((float)pos-102.0)/18.0;
937 		led->R=(r1 * mOff6.R + (r2 * mOff0.R))  + (on * ((r1 * mOn6.R) + (r2 * mOn0.R))) ;
938 		led->G=(r1 * mOff6.G + (r2 * mOff0.G))  + (on * ((r1 * mOn6.G) + (r2 * mOn0.G))) ;
939 		led->B=(r1 * mOff6.B + (r2 * mOff0.B))  + (on * ((r1 * mOn6.B) + (r2 * mOn0.B))) ;
940 	}
941 	else
942 	{
943 		led->R=overOff.R + (on * overOn.R) ;
944 		led->G=overOff.G + (on * overOn.G) ;
945 		led->B=overOff.B + (on * overOn.B) ;
946 	}
947 
948 	if(bypass==INV_PLUGIN_BYPASS) {
949 		led->R=(led->R+led->G+led->B)/3;
950 		led->G=led->R;
951 		led->B=led->R;
952 	}
953 }
954 
955