2 terminatorX - realtime audio scratching software
3 Copyright (C) 1999-2020 Alexander König
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 Description: This contains the implementation of the tx_flash_flash widget.
29 #include "tX_global.h"
38 #endif /* __cplusplus */
40 #define MAX_VALUE 1.0f
42 #define RED_BORDER 0.8f
44 #define TX_FLASH_DEFAULT_SIZE_X 25
45 #define TX_FLASH_DEFAULT_SIZE_Y 30
52 #define MAX_MAX_CYCLES 30;
55 static void gtk_tx_flash_class_init (GtkTxFlashClass *);
56 static void gtk_tx_flash_init (GtkTxFlash *tx_flash);
57 GtkWidget* gtk_tx_flash_new ();
58 static void gtk_tx_flash_destroy (GtkWidget *widget);
59 static void gtk_tx_flash_realize (GtkWidget *widget);
60 static void gtk_tx_flash_get_preferred_width (GtkWidget *widget, gint *minimal_height, gint *natural_height);
61 static void gtk_tx_flash_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height);
63 static void gtk_tx_flash_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
64 static gboolean gtk_tx_flash_draw (GtkWidget *widget, cairo_t *cairo);
68 static GtkWidgetClass *parent_class = NULL;
70 GType gtk_tx_flash_get_type ()
72 static GType tx_flash_type = 0;
75 static const GTypeInfo tx_flash_info = {
76 sizeof (GtkTxFlashClass),
79 (GClassInitFunc) gtk_tx_flash_class_init,
84 (GInstanceInitFunc) gtk_tx_flash_init,
87 tx_flash_type = g_type_register_static(GTK_TYPE_WIDGET, "GtkTxFlash", &tx_flash_info, 0);
93 static void gtk_tx_flash_class_init (GtkTxFlashClass *gclass)
95 GtkWidgetClass *widget_class;
97 widget_class = (GtkWidgetClass*) gclass;
99 parent_class = (GtkWidgetClass*) g_type_class_peek (gtk_widget_get_type ());
101 widget_class->destroy = gtk_tx_flash_destroy;
103 widget_class->realize = gtk_tx_flash_realize;
104 widget_class->draw = gtk_tx_flash_draw;
106 widget_class->get_preferred_height = gtk_tx_flash_get_preferred_height;
107 widget_class->get_preferred_width = gtk_tx_flash_get_preferred_width;
109 widget_class->size_allocate = gtk_tx_flash_size_allocate;
123 void mk_half(double s, GdkRGBA *a, GdkRGBA *b, GdkRGBA *c)
125 c->red=a->red-(a->red-b->red)*s;
126 c->green=a->green-(a->green-b->green)*s;
127 c->blue=a->blue-(a->blue-b->blue)*s;
131 void gtk_tx_flash_update_colors(GtkTxFlash *tx)
133 gdk_rgba_parse(&tx->colors[COL_BG], globals.vu_meter_bg);
134 tx->colors[COL_BG].alpha = 1.0;
135 gdk_rgba_parse(&tx->colors[COL_LOUD], globals.vu_meter_loud);
136 tx->colors[COL_LOUD].alpha = 1.0;
137 gdk_rgba_parse(&tx->colors[COL_NORM], globals.vu_meter_normal);
138 tx->colors[COL_NORM].alpha = 1.0;
139 mk_half(globals.vu_meter_border_intensity, &tx->colors[COL_BG], &tx->colors[COL_LOUD], &tx->colors[COL_LOUD_HALF]);
140 mk_half(globals.vu_meter_border_intensity, &tx->colors[COL_BG], &tx->colors[COL_NORM], &tx->colors[COL_NORM_HALF]);
143 static void gtk_tx_flash_init (GtkTxFlash *tx_flash)
145 tx_flash->surface = NULL;
147 gtk_tx_flash_update_colors(tx_flash);
150 GtkWidget* gtk_tx_flash_new ()
152 GtkTxFlash *tx_flash;
153 tx_flash = (GtkTxFlash *)g_object_new(gtk_tx_flash_get_type (), NULL);
155 // tX_msg("creating a new flash: %08x\n", tx_flash);
156 return GTK_WIDGET (tx_flash);
159 static void gtk_tx_flash_destroy (GtkWidget *widget)
161 g_return_if_fail (widget != NULL);
162 g_return_if_fail (GTK_IS_TX_FLASH (widget));
164 if (GTK_WIDGET_CLASS (parent_class)->destroy)
165 (*GTK_WIDGET_CLASS (parent_class)->destroy) (widget);
168 static void gtk_tx_flash_realize (GtkWidget *widget)
170 GtkTxFlash *tx_flash;
171 GdkWindowAttr attributes;
172 gint attributes_mask;
174 g_return_if_fail (widget != NULL);
175 g_return_if_fail (GTK_IS_TX_FLASH (widget));
177 tx_flash=GTK_TX_FLASH(widget);
179 gtk_widget_set_realized(widget, TRUE);
180 GtkAllocation allocation;
181 gtk_widget_get_allocation(widget, &allocation);
183 attributes.x = allocation.x;
184 attributes.y = allocation.y;
185 attributes.width = allocation.width;
186 attributes.height = allocation.height;
187 attributes.wclass = GDK_INPUT_OUTPUT;
188 attributes.window_type = GDK_WINDOW_CHILD;
189 attributes.event_mask = gtk_widget_get_events (widget) |
191 attributes.visual = gtk_widget_get_visual (widget);
192 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
194 gtk_widget_set_window(widget, gdk_window_new (gtk_widget_get_parent_window(widget), &attributes, attributes_mask));
196 gdk_window_set_user_data (gtk_widget_get_window(widget), widget);
198 if (tx_flash->surface) {
199 cairo_surface_destroy (tx_flash->surface);
202 tx_flash->surface = gdk_window_create_similar_surface (gtk_widget_get_window(widget), CAIRO_CONTENT_COLOR, allocation.width, allocation.height);
205 static void gtk_tx_flash_get_preferred_width (GtkWidget *widget, gint *minimal_width, gint *natural_width)
207 *minimal_width = *natural_width = TX_FLASH_DEFAULT_SIZE_X;
210 static void gtk_tx_flash_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height)
212 *minimal_height = *natural_height = TX_FLASH_DEFAULT_SIZE_Y;
216 static void gtk_tx_flash_prepare(GtkWidget *widget)
218 GtkTxFlash *tx_flash;
220 g_return_if_fail (widget != NULL);
221 g_return_if_fail (GTK_IS_TX_FLASH (widget));
223 tx_flash=GTK_TX_FLASH(widget);
225 GtkAllocation allocation;
226 gtk_widget_get_allocation(widget, &allocation);
228 tx_flash->levels=(allocation.height-(2*DY))/DLEVEL;
229 tx_flash->channel[0].last_level=0;
230 tx_flash->channel[1].last_level=0;
231 tx_flash->channel[0].max=0;
232 tx_flash->channel[1].max=0;
233 tx_flash->level_value=MAX_VALUE/(f_prec) tx_flash->levels;
234 tx_flash->red_level=(RED_BORDER/tx_flash->level_value);
236 tx_flash->channel[0].x1=DMINIX+S_MINIX+2;
237 tx_flash->channel[1].x2=allocation.width-tx_flash->channel[0].x1;
239 if (allocation.width%2>0) {
241 tx_flash->center_expand=0;
242 tx_flash->channel[0].x2=allocation.width/2-1;
245 tx_flash->center_expand=1;
246 tx_flash->channel[0].x2=allocation.width/2-2;
248 tx_flash->channel[1].x1=allocation.width/2+2;
250 //tX_msg("flash: width %i: left %i, right %i", widget->allocation.width, tx_flash->channel[0].x2-tx_flash->channel[0].x1, tx_flash->channel[1].x2-tx_flash->channel[1].x1);
253 static void gtk_tx_flash_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
255 g_return_if_fail (widget != NULL);
256 g_return_if_fail (GTK_IS_TX_FLASH (widget));
257 g_return_if_fail (allocation != NULL);
259 gtk_widget_set_allocation(widget, allocation);
261 gtk_tx_flash_prepare(widget);
263 if (gtk_widget_get_realized (widget)) {
264 gdk_window_move_resize (gtk_widget_get_window(widget),
265 allocation->x, allocation->y,
266 allocation->width, allocation->height);
270 static void gtk_tx_flash_paint_yourself(GtkWidget *widget, cairo_t *cr)
272 GtkTxFlash *tx_flash;
273 GtkAllocation allocation;
275 gint i, x11, x12,x21, x22, y, middle;
278 tx_flash = GTK_TX_FLASH (widget);
279 gtk_widget_get_allocation(widget, &allocation);
281 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
282 cairo_set_source_surface (cr, tx_flash->surface, 0, 0);
284 gdk_cairo_set_source_rgba (cr, &tx_flash->colors[COL_BG]);
285 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
288 cairo_set_line_width(cr,1);
289 gdk_cairo_set_source_rgba (cr, &tx_flash->colors[COL_NORM]);
292 x21=allocation.width-1-x12;
293 middle=allocation.width/2;
295 for (i=0, y=allocation.height-DY; i<=tx_flash->levels; y-=DLEVEL, i++) {
298 } else if (i==tx_flash->red_level-1) {
300 } else if (i==tx_flash->red_level) {
302 gdk_cairo_set_source_rgba (cr, &tx_flash->colors[COL_LOUD_HALF]);
303 } else if (i==tx_flash->levels) {
315 cairo_move_to (cr, x11, y);
316 cairo_line_to (cr, x12+1, y);
318 cairo_move_to (cr, x21, y);
319 cairo_line_to (cr, x22+1, y);
321 if (tx_flash->center_expand) {
322 cairo_move_to (cr, middle-1, y);
323 cairo_line_to (cr, middle+1, y);
325 cairo_move_to (cr, middle, y);
326 cairo_line_to (cr, middle+1, y);
332 static gboolean gtk_tx_flash_draw(GtkWidget *widget, cairo_t *cr)
334 g_return_val_if_fail (widget != NULL, FALSE);
335 g_return_val_if_fail (GTK_IS_TX_FLASH (widget), FALSE);
337 gtk_tx_flash_prepare(widget);
338 gtk_tx_flash_paint_yourself(widget, cr);
344 static void gtk_tx_flash_set_channel_level(GtkTxFlash *tx_flash, f_prec new_value, struct flash_channel *channel);
346 void gtk_tx_flash_set_level(GtkWidget *widget, f_prec left_channel, f_prec right_channel)
348 GtkTxFlash *tx_flash;
350 g_return_if_fail (widget != NULL);
351 g_return_if_fail (GTK_IS_TX_FLASH (widget));
353 tx_flash = GTK_TX_FLASH (widget);
355 gtk_tx_flash_set_channel_level(tx_flash, left_channel, &tx_flash->channel[0]);
356 gtk_tx_flash_set_channel_level(tx_flash, right_channel, &tx_flash->channel[1]);
359 static void gtk_tx_flash_set_channel_level(GtkTxFlash *tx_flash, f_prec new_value, struct flash_channel *channel)
361 GtkWidget *widget=GTK_WIDGET(tx_flash);
362 GtkAllocation allocation;
368 new_level=(int) (new_value/tx_flash->level_value);
369 gtk_widget_get_allocation(widget, &allocation);
371 cr = gdk_cairo_create (gtk_widget_get_window(widget));
372 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
373 cairo_set_line_width(cr,1);
374 cairo_set_source_surface (cr, tx_flash->surface, 0, 0);
376 gdk_cairo_set_source_rgba (cr, &tx_flash->colors[COL_BG]);
378 // tX_msg("setting level: %5d for widget %08x channel %08x\n", new_level, tx_flash, channel);
380 if (new_level>tx_flash->levels)
381 new_level=tx_flash->levels;
383 if (new_level>channel->max) {
384 channel->max=new_level;
385 tx_flash->max_cycles=MAX_MAX_CYCLES;
387 tx_flash->max_cycles--;
390 if (tx_flash->max_cycles <= 0) {
391 y=allocation.height-(DY+(channel->max)*DLEVEL);
392 gdk_cairo_set_source_rgba (cr, &tx_flash->colors[COL_BG]);
393 cairo_move_to (cr, channel->x1, y);
394 cairo_line_to (cr, channel->x2, y);
397 if (channel->max>0) {
400 if (channel->max>tx_flash->red_level) {
401 gdk_cairo_set_source_rgba (cr, &tx_flash->colors[COL_LOUD]);
403 gdk_cairo_set_source_rgba (cr, &tx_flash->colors[COL_NORM]);
406 cairo_move_to (cr, channel->x1, y);
407 cairo_line_to (cr, channel->x2, y);
412 if (new_level==channel->last_level)
415 if (new_level<channel->last_level) {
416 new_level=channel->last_level*globals.flash_response;
419 if (new_level>channel->last_level) {
420 gdk_cairo_set_source_rgba (cr, &tx_flash->colors[COL_NORM]);
422 for (i=channel->last_level, y=allocation.height-(DY+channel->last_level*DLEVEL); i<=new_level; y-=DLEVEL, i++) {
424 if (i>=tx_flash->red_level) {
425 gdk_cairo_set_source_rgba (cr, &tx_flash->colors[COL_LOUD]);
429 cairo_move_to (cr, channel->x1, y);
430 cairo_line_to (cr, channel->x2, y);
434 gdk_cairo_set_source_rgba (cr, &tx_flash->colors[COL_BG]);
436 if (channel->last_level==channel->max) {
437 i=channel->last_level-1;
439 i=channel->last_level;
442 for (y=allocation.height-(DY+i*DLEVEL); i>new_level; y+=DLEVEL, i--) {
443 cairo_move_to (cr, channel->x1, y);
444 cairo_line_to (cr, channel->x2, y);
448 channel->last_level=new_level;
454 gtk_tx_flash_clear (GtkWidget *widget)
456 GtkTxFlash *tx_flash;
458 tx_flash = GTK_TX_FLASH (widget);
460 tx_flash->channel[0].max=0;
461 tx_flash->channel[1].max=0;
462 tx_flash->channel[0].last_level=0;
463 tx_flash->channel[1].last_level=0;
464 tx_flash->max_cycles=0;
466 cairo_t *cr = gdk_cairo_create (gtk_widget_get_window(widget));
467 gtk_tx_flash_paint_yourself(widget, cr);
473 #endif /* __cplusplus */