1 
2 #include "lv2/lv2plug.in/ns/lv2core/lv2.h"
3 #include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
4 
5 // xwidgets.h includes xputty.h and all defined widgets from Xputty
6 #include "xwidgets.h"
7 
8 #include "gx_mbdelay.h"
9 
10 /*---------------------------------------------------------------------
11 -----------------------------------------------------------------------
12                 define controller numbers
13 -----------------------------------------------------------------------
14 ----------------------------------------------------------------------*/
15 
16 #define CONTROLS 15
17 
18 /*---------------------------------------------------------------------
19 -----------------------------------------------------------------------
20                 the main LV2 handle->XWindow
21 -----------------------------------------------------------------------
22 ----------------------------------------------------------------------*/
23 
24 
25 // main window struct
26 typedef struct {
27     void *parentXwindow;
28     Xputty main;
29     Widget_t *win;
30     Widget_t *widget[CONTROLS+1];
31     Widget_t *meter_widget[5];
32     Adjustment_t *adj[3];
33     cairo_surface_t *screw;
34     int block_event;
35     float db_zero;
36 
37     void *controller;
38     LV2UI_Write_Function write_function;
39     LV2UI_Resize* resize;
40 } X11_UI;
41 
42 // setup a color theme
set_my_theme(Xputty * main)43 static void set_my_theme(Xputty *main) {
44     main->color_scheme->normal = (Colors) {
45          /* cairo    / r  / g  / b  / a  /  */
46         /*fg */       { 0.68, 0.44, 0.00, 1.00},
47         /*bg */       { 0.1, 0.1, 0.1, 1.0},
48         /*base */     { 0.1, 0.1, 0.1, 1.0},
49         /*text */     { 0.85, 0.52, 0.00, 1.00},
50         /*shadow */   { 0.85, 0.52, 0.00, 0.2},
51         /*frame */    { 0.0, 0.0, 0.0, 1.0},
52         /*light */    { 0.1, 0.1, 0.2, 1.0}
53     };
54 
55     main->color_scheme->prelight = (Colors) {
56         /*fg */       { 1.0, 1.0, 1.0, 1.0},
57         /*bg */       { 0.25, 0.25, 0.25, 1.0},
58         /*base */     { 0.2, 0.2, 0.3, 1.0},
59         /*text */     { 0.7, 0.7, 0.7, 1.0},
60         /*shadow */   { 0.1, 0.1, 0.1, 0.4},
61         /*frame */    { 0.3, 0.3, 0.3, 1.0},
62         /*light */    { 0.3, 0.3, 0.3, 1.0}
63     };
64 
65     main->color_scheme->selected = (Colors) {
66         /*fg */       { 0.9, 0.9, 0.9, 1.0},
67         /*bg */       { 0.2, 0.2, 0.2, 1.0},
68         /*base */     { 0.1, 0.1, 0.1, 1.0},
69         /*text */     { 1.0, 1.0, 1.0, 1.0},
70         /*shadow */   { 0.18, 0.18, 0.18, 0.2},
71         /*frame */    { 0.18, 0.18, 0.18, 1.0},
72         /*light */    { 0.18, 0.18, 0.28, 1.0}
73     };
74 
75     main->color_scheme->active = (Colors) {
76          /* cairo    / r  / g  / b  / a  /  */
77         /*fg */       { 0.68, 0.44, 0.00, 1.00},
78         /*bg */       { 0.1, 0.1, 0.1, 1.0},
79         /*base */     { 0.1, 0.1, 0.1, 1.0},
80         /*text */     { 0.85, 0.52, 0.00, 1.00},
81         /*shadow */   { 0.85, 0.52, 0.00, 0.2},
82         /*frame */    { 0.0, 0.0, 0.0, 1.0},
83         /*light */    { 0.1, 0.1, 0.2, 1.0}
84     };
85 }
86 
87 // draw the window
draw_window(void * w_,void * user_data)88 static void draw_window(void *w_, void* user_data) {
89     Widget_t *w = (Widget_t*)w_;
90     X11_UI* ui = (X11_UI*)w->parent_struct;
91     set_pattern(w,&w->app->color_scheme->selected,&w->app->color_scheme->normal,BACKGROUND_);
92     cairo_paint (w->crb);
93     set_pattern(w,&w->app->color_scheme->normal,&w->app->color_scheme->selected,BACKGROUND_);
94     cairo_rectangle (w->crb,4,4,w->width-8,w->height-8);
95     cairo_set_line_width(w->crb,4);
96     cairo_stroke(w->crb);
97 
98     cairo_set_source_surface (w->crb, ui->screw,5,5);
99     cairo_paint (w->crb);
100     cairo_set_source_surface (w->crb, ui->screw,5,w->height-37);
101     cairo_paint (w->crb);
102     cairo_set_source_surface (w->crb, ui->screw,w->width-37,w->height-37);
103     cairo_paint (w->crb);
104     cairo_set_source_surface (w->crb, ui->screw,w->width-37,5);
105     cairo_paint (w->crb);
106     cairo_new_path (w->crb);
107 
108     cairo_text_extents_t extents;
109     use_text_color_scheme(w, get_color_state(w));
110     float font_size = min(20.0,((w->height/2.2 < (w->width*0.5)/3) ? w->height/2.2 : (w->width*0.5)/3));
111     cairo_set_font_size (w->crb, font_size);
112     cairo_text_extents(w->crb,w->label , &extents);
113     double tw = extents.width/2.0;
114 
115     widget_set_scale(w);
116     cairo_move_to (w->crb, 305-tw, 310 );
117     cairo_show_text(w->crb, w->label);
118     cairo_new_path (w->crb);
119     cairo_scale (w->crb, 0.95, 0.95);
120     cairo_set_source_surface (w->crb, w->image,510,10);
121     cairo_paint (w->crb);
122     cairo_scale (w->crb, 1.05, 1.05);
123     widget_reset_scale(w);
124 }
125 
126 // draw the slider handle
rounded_rectangle(cairo_t * cr,float x,float y,float w,float h)127 static void rounded_rectangle(cairo_t *cr,float x, float y, float w, float h) {
128     float r = h*0.55;
129 
130     cairo_move_to(cr,x+r,y);
131     cairo_line_to(cr,x+w-r,y);
132     cairo_curve_to(cr,x+w,y,x+w,y,x+w,y+r);
133     cairo_line_to(cr,x+w,y+h-r);
134     cairo_curve_to(cr,x+w,y+h,x+w,y+h,x+w-r,y+h);
135     cairo_line_to(cr,x+r,y+h);
136     cairo_curve_to(cr,x,y+h,x,y+h,x,y+h-r);
137     cairo_line_to(cr,x,y+r);
138     cairo_curve_to(cr,x,y,x,y,x+r,y);
139 }
140 
141 // draw the slider
draw_my_hslider(void * w_,void * user_data)142 static void draw_my_hslider(void *w_, void* user_data) {
143     Widget_t *w = (Widget_t*)w_;
144     X11_UI* ui = (X11_UI*)w->parent_struct;
145 
146     int width = w->width-2;
147     int height = w->height-2;
148     float center = (float)height/2;
149 
150     float sliderstate1 = adj_get_state(w->adj);
151     float sliderstate2 = adj_get_state(ui->adj[0]);
152     float sliderstate3 = adj_get_state(ui->adj[1]);
153     float sliderstate4 = adj_get_state(ui->adj[2]);
154     float sliderstate = 0.0;
155     Color_state s1 = NORMAL_;
156     Color_state s2 = NORMAL_;
157     Color_state s3 = NORMAL_;
158     Color_state s4 = NORMAL_;
159 
160     if (w->state>0.0 && w->state<4.0 && w->adj_x) {
161         if (w->adj_x == w->adj) {
162             sliderstate = sliderstate1;
163             s1 = PRELIGHT_;
164         } else if (w->adj_x == ui->adj[0]) {
165             sliderstate = sliderstate2;
166             s2 = PRELIGHT_;
167         } else if (w->adj_x == ui->adj[1]) {
168             sliderstate = sliderstate3;
169             s3 = PRELIGHT_;
170         } else if (w->adj_x == ui->adj[2]) {
171             sliderstate = sliderstate4;
172             s4 = PRELIGHT_;
173         }
174     }
175     cairo_pattern_t* pat;
176 
177     pat = cairo_pattern_create_linear (0, 0, 0, height);
178     cairo_pattern_add_color_stop_rgba (pat, 1,  0.25, 0.25, 0.25, 1.0);
179     cairo_pattern_add_color_stop_rgba (pat, 0.75,  0.2, 0.2, 0.2, 1.0);
180     cairo_pattern_add_color_stop_rgba (pat, 0.5,  0.15, 0.15, 0.15, 1.0);
181     cairo_pattern_add_color_stop_rgba (pat, 0.25,  0.1, 0.1, 0.1, 1.0);
182     cairo_pattern_add_color_stop_rgba (pat, 0,  0.05, 0.05, 0.05, 1.0);
183 
184 
185     cairo_set_source (w->crb, pat);
186     rounded_rectangle(w->crb, 0.0, 0.0,width,height);
187     cairo_set_line_width(w->crb,2);
188     cairo_stroke(w->crb);
189     cairo_pattern_destroy (pat);
190     pat = NULL;
191 
192     use_text_color_scheme(w, get_color_state(w));
193     cairo_move_to (w->crb, center, center);
194     cairo_line_to(w->crb,width-center,center);
195     cairo_set_line_width(w->crb,center/10);
196     cairo_stroke(w->crb);
197 
198     pat = cairo_pattern_create_linear (0, 0, 0, height);
199     cairo_pattern_add_color_stop_rgba (pat, 0,  0.25, 0.25, 0.25, 1.0);
200     cairo_pattern_add_color_stop_rgba (pat, 0.25,  0.2, 0.2, 0.2, 1.0);
201     cairo_pattern_add_color_stop_rgba (pat, 0.5,  0.15, 0.15, 0.15, 1.0);
202     cairo_pattern_add_color_stop_rgba (pat, 0.75,  0.1, 0.1, 0.1, 1.0);
203     cairo_pattern_add_color_stop_rgba (pat, 1,  0.05, 0.05, 0.05, 1.0);
204 
205     cairo_set_source (w->crb, pat);
206     rounded_rectangle(w->crb, (width-height)*sliderstate1,0,height, height);
207     cairo_fill_preserve (w->crb);
208     cairo_set_source_rgb (w->crb, 0.1, 0.1, 0.1);
209     cairo_set_line_width(w->crb,2);
210     cairo_stroke(w->crb);
211     cairo_new_path (w->crb);
212     cairo_set_source (w->crb, pat);
213     rounded_rectangle(w->crb, (width-height)*sliderstate2,0,height, height);
214     cairo_fill_preserve (w->crb);
215     cairo_set_source_rgb (w->crb, 0.1, 0.1, 0.1);
216     cairo_stroke(w->crb);
217     cairo_new_path (w->crb);
218     cairo_set_source (w->crb, pat);
219     rounded_rectangle(w->crb, (width-height)*sliderstate3,0,height, height);
220     cairo_fill_preserve (w->crb);
221     cairo_set_source_rgb (w->crb, 0.1, 0.1, 0.1);
222     cairo_stroke(w->crb);
223     cairo_new_path (w->crb);
224     cairo_set_source (w->crb, pat);
225     rounded_rectangle(w->crb, (width-height)*sliderstate4,0,height, height);
226     cairo_fill_preserve (w->crb);
227     cairo_set_source_rgb (w->crb, 0.1, 0.1, 0.1);
228     cairo_stroke(w->crb);
229     cairo_new_path (w->crb);
230     cairo_pattern_destroy (pat);
231     pat = NULL;
232 
233     use_text_color_scheme(w, s1);
234     cairo_set_line_width(w->crb,2);
235     cairo_move_to (w->crb,((width-height)*sliderstate1)+center, 2.0);
236     cairo_line_to(w->crb,((width-height)*sliderstate1)+center,height-4.0);
237     cairo_stroke(w->crb);
238     use_text_color_scheme(w, s2);
239     cairo_move_to (w->crb,((width-height)*sliderstate2)+center, 2.0);
240     cairo_line_to(w->crb,((width-height)*sliderstate2)+center,height-4.0);
241     cairo_stroke(w->crb);
242     use_text_color_scheme(w, s3);
243     cairo_move_to (w->crb,((width-height)*sliderstate3)+center, 2.0);
244     cairo_line_to(w->crb,((width-height)*sliderstate3)+center,height-4.0);
245     cairo_stroke(w->crb);
246     use_text_color_scheme(w, s4);
247     cairo_move_to (w->crb,((width-height)*sliderstate4)+center, 2.0);
248     cairo_line_to(w->crb,((width-height)*sliderstate4)+center,height-4.0);
249     cairo_stroke(w->crb);
250 
251     /** show value on the slider**/
252     if (w->state>0.0 && w->state<4.0 && w->adj_x) {
253         use_fg_color_scheme(w, PRELIGHT_);
254         cairo_text_extents_t extents;
255         char s[64];
256         char l[64];
257         snprintf(l,63,"%s ", w->label);
258         const char* format[] = {"%.1f", "%.2f", "%.3f"};
259         snprintf(s, 63, format[2-1], pow(10.0,w->adj_x->value));
260         strcat(l,s);
261         cairo_set_font_size (w->crb, min(11.0,height));
262         cairo_text_extents(w->crb, l, &extents);
263         cairo_move_to (w->crb, min(width-extents.width ,(width-height)*sliderstate), height);
264         cairo_show_text(w->crb, l);
265         cairo_new_path (w->crb);
266     }
267 }
268 
269 // draw the knobs
draw_my_knob(void * w_,void * user_data)270 static void draw_my_knob(void *w_, void* user_data) {
271     Widget_t *w = (Widget_t*)w_;
272     int width = w->width-2;
273     int height = w->height-2;
274 
275     const double scale_zero = 20 * (M_PI/180); // defines "dead zone" for knobs
276     int arc_offset = 2;
277     int knob_x = 0;
278     int knob_y = 0;
279 
280     int grow = (width > height) ? height:width;
281     knob_x = grow-1;
282     knob_y = grow-1;
283     /** get values for the knob **/
284 
285     int knobx = (grow - knob_x) * 0.5;
286     int knobx1 = grow* 0.5;
287 
288     int knoby = (grow - knob_y) * 0.5;
289     int knoby1 = grow * 0.5;
290 
291     double knobstate = adj_get_state(w->adj_y);
292     double angle = scale_zero + knobstate * 2 * (M_PI - scale_zero);
293 
294     double pointer_off =knob_x/3.5;
295     double radius = min(knob_x-pointer_off, knob_y-pointer_off) / 2;
296     double lengh_x = (knobx+radius+pointer_off/2) - radius * sin(angle);
297     double lengh_y = (knoby+radius+pointer_off/2) + radius * cos(angle);
298     double radius_x = (knobx+radius+pointer_off/2) - radius/ 1.18 * sin(angle);
299     double radius_y = (knoby+radius+pointer_off/2) + radius/ 1.18 * cos(angle);
300     cairo_pattern_t* pat;
301     cairo_new_path (w->crb);
302 
303     pat = cairo_pattern_create_linear (0, 0, 0, knob_y);
304     cairo_pattern_add_color_stop_rgba (pat, 1,  0.25, 0.25, 0.25, 1.0);
305     cairo_pattern_add_color_stop_rgba (pat, 0.75,  0.2, 0.2, 0.2, 1.0);
306     cairo_pattern_add_color_stop_rgba (pat, 0.5,  0.15, 0.15, 0.15, 1.0);
307     cairo_pattern_add_color_stop_rgba (pat, 0.25,  0.1, 0.1, 0.1, 1.0);
308     cairo_pattern_add_color_stop_rgba (pat, 0,  0.05, 0.05, 0.05, 1.0);
309 
310     cairo_scale (w->crb, 0.95, 1.05);
311     cairo_arc(w->crb,knobx1+arc_offset/2, knoby1-arc_offset, knob_x/2.2, 0, 2 * M_PI );
312     cairo_set_source (w->crb, pat);
313     cairo_fill_preserve (w->crb);
314     cairo_set_source_rgb (w->crb, 0.1, 0.1, 0.1);
315     cairo_set_line_width(w->crb,1);
316     cairo_stroke(w->crb);
317     cairo_scale (w->crb, 1.05, 0.95);
318     cairo_new_path (w->crb);
319     cairo_pattern_destroy (pat);
320     pat = NULL;
321 
322     pat = cairo_pattern_create_linear (0, 0, 0, knob_y);
323     cairo_pattern_add_color_stop_rgba (pat, 0,  0.25, 0.25, 0.25, 1.0);
324     cairo_pattern_add_color_stop_rgba (pat, 0.25,  0.2, 0.2, 0.2, 1.0);
325     cairo_pattern_add_color_stop_rgba (pat, 0.5,  0.15, 0.15, 0.15, 1.0);
326     cairo_pattern_add_color_stop_rgba (pat, 0.75,  0.1, 0.1, 0.1, 1.0);
327     cairo_pattern_add_color_stop_rgba (pat, 1,  0.05, 0.05, 0.05, 1.0);
328 
329     cairo_arc(w->crb,knobx1, knoby1, knob_x/2.6, 0, 2 * M_PI );
330     cairo_set_source (w->crb, pat);
331     cairo_fill_preserve (w->crb);
332     cairo_set_source_rgb (w->crb, 0.1, 0.1, 0.1);
333     cairo_set_line_width(w->crb,1);
334     cairo_stroke(w->crb);
335     cairo_new_path (w->crb);
336     cairo_pattern_destroy (pat);
337 
338     use_text_color_scheme(w, get_color_state(w));
339 
340     /** create a rotating pointer on the kob**/
341     cairo_set_line_cap(w->crb, CAIRO_LINE_CAP_ROUND);
342     cairo_set_line_join(w->crb, CAIRO_LINE_JOIN_BEVEL);
343     cairo_move_to(w->crb, radius_x, radius_y);
344     cairo_line_to(w->crb,lengh_x,lengh_y);
345     cairo_set_line_width(w->crb,3);
346     cairo_stroke(w->crb);
347     cairo_new_path (w->crb);
348 
349     cairo_text_extents_t extents;
350     /** show value on the kob**/
351     if (w->state>0.0 && w->state<4.0) {
352         char s[64];
353         const char* format[] = {"%.1f", "%.2f", "%.3f"};
354         snprintf(s, 63, format[2-1], w->adj_y->value);
355         cairo_set_font_size (w->crb, min(11.0,knobx1/3));
356        cairo_text_extents(w->crb, s, &extents);
357         cairo_move_to (w->crb, knobx1-extents.width/2, knoby1+extents.height/2);
358         cairo_show_text(w->crb, s);
359         cairo_new_path (w->crb);
360     }
361 
362     /** show label below the knob**/
363     float font_size = min(12.0,((height/2.2 < (width*0.6)/3) ? height/2.2 : (width*0.6)/3));
364     cairo_set_font_size (w->crb, font_size);
365     cairo_text_extents(w->crb,w->label , &extents);
366 
367     cairo_move_to (w->crb, knobx1-extents.width/2, height );
368     cairo_show_text(w->crb, w->label);
369     cairo_new_path (w->crb);
370 }
371 
372 // if controller value changed send notify to host
value_changed(void * w_,void * user_data)373 static void value_changed(void *w_, void* user_data) {
374     Widget_t *w = (Widget_t*)w_;
375     X11_UI* ui = (X11_UI*)w->parent_struct;
376     if (ui->block_event != w->data)
377         ui->write_function(ui->controller,w->data,sizeof(float),0,&w->adj->value);
378     ui->block_event = -1;
379 }
380 
381 // shortcut to create knobs with portindex binding
add_my_knob(Widget_t * w,PortIndex index,const char * label,X11_UI * ui,int x,int y,int width,int height)382 Widget_t* add_my_knob(Widget_t *w, PortIndex index, const char * label,
383                                 X11_UI* ui, int x, int y, int width, int height) {
384     w = add_knob(ui->win, label, x, y, width, height);
385     w->func.expose_callback = draw_my_knob;
386     w->parent_struct = ui;
387     w->data = index;
388     w->func.value_changed_callback = value_changed;
389     return w;
390 }
391 
392 // check that bands didn't overlap
check_multi_controller(X11_UI * ui,uint32_t port_index,float value)393 static void check_multi_controller(X11_UI* ui, uint32_t port_index, float value) {
394     float v = log10f(value);
395     switch ((PortIndex)port_index)
396         {
397         case CROSSOVER_B1_B2:
398             check_value_changed(ui->widget[15]->adj, &v);
399             adj_set_value(ui->adj[0], max(adj_get_value(ui->adj[0]), v+0.1));
400         break;
401         case CROSSOVER_B2_B3:
402             adj_set_value(ui->widget[15]->adj, min(adj_get_value(ui->widget[15]->adj), v-0.1));
403             check_value_changed(ui->adj[0], &v);
404             adj_set_value(ui->adj[1], max(adj_get_value(ui->adj[1]), v+0.1));
405         break;
406         case CROSSOVER_B3_B4:
407             adj_set_value(ui->adj[0], min(adj_get_value(ui->adj[0]), v-0.1));
408             check_value_changed(ui->adj[1], &v);
409             adj_set_value(ui->adj[2], max(adj_get_value(ui->adj[2]), v+0.1));
410         break;
411         case CROSSOVER_B4_B5:
412             adj_set_value(ui->adj[1], min(adj_get_value(ui->adj[1]), v-0.1));
413             check_value_changed(ui->adj[2], &v);
414         break;
415         default:
416         break;
417     }
418 }
419 
420 // if adjustment value changed send notify to host
slider_value_changed(void * w_,void * user_data)421 static void slider_value_changed(void *w_, void* user_data) {
422     Widget_t *w = (Widget_t*)w_;
423     X11_UI* ui = (X11_UI*)w->parent_struct;
424     uint32_t port_index = 0;
425     float value = 0.0;
426     if (w->adj_x == w->adj) {
427         port_index = CROSSOVER_B1_B2;
428         value = adj_get_value(w->adj);
429     } else if (w->adj_x == ui->adj[0]) {
430         port_index = CROSSOVER_B2_B3;
431         value = adj_get_value(ui->adj[0]);
432     } else if (w->adj_x == ui->adj[1]) {
433         port_index = CROSSOVER_B3_B4;
434         value = adj_get_value(ui->adj[1]);
435     } else if (w->adj_x == ui->adj[2]) {
436         port_index = CROSSOVER_B4_B5;
437         value = adj_get_value(ui->adj[2]);
438     }
439     if (port_index) {
440         float v = pow(10,value);
441         check_multi_controller(ui,port_index, v);
442         if (ui->block_event != (int)port_index)
443             ui->write_function(ui->controller,port_index,sizeof(float),0,&v);
444         ui->block_event = -1;
445     }
446 }
447 
448 // redraw slider when mouse button released
my_slider_released(void * w_,void * button_,void * user_data)449 static void my_slider_released(void *w_, void* button_, void* user_data) {
450     Widget_t *w = (Widget_t*)w_;
451     expose_widget(w);
452 }
453 
454 // set active adjustment based on mouse position
my_slider_pressed(void * w_,void * button_,void * user_data)455 static void my_slider_pressed(void *w_, void* button_, void* user_data) {
456     Widget_t *w = (Widget_t*)w_;
457     X11_UI* ui = (X11_UI*)w->parent_struct;
458     float x = float(w->pos_x)/float(w->width-w->height);
459 
460     float sliderstate1 = adj_get_state(w->adj);
461     float sliderstate2 = adj_get_state(ui->adj[0]);
462     float sliderstate3 = adj_get_state(ui->adj[1]);
463     float sliderstate4 = adj_get_state(ui->adj[2]);
464 
465     if (x < sliderstate1+0.04 && x >sliderstate1) {
466         w->adj_x = w->adj;
467         w->label = "Band 1<|>2 ";
468     }
469     else if (x < sliderstate2+0.04 && x >sliderstate2) {
470         w->adj_x = ui->adj[0];
471         w->label = "Band 2<|>3 ";
472     }
473     else if (x < sliderstate3+0.04 && x >sliderstate3) {
474         w->adj_x = ui->adj[1];
475         w->label = "Band 3<|>4 ";
476     }
477     else if (x < sliderstate4+0.04 && x >sliderstate4) {
478         w->adj_x = ui->adj[2];
479         w->label = "Band 4<|>5 ";
480     } else {
481         w->adj_x = NULL;
482         w->label = " ";
483     }
484     adj_set_start_value(w);
485 
486     expose_widget(w);
487 }
488 
489 // shortcut to create multi adjustment slider with portindex binding
add_my_slider(Widget_t * w,PortIndex index,const char * label,X11_UI * ui,int x,int y,int width,int height)490 Widget_t* add_my_slider(Widget_t *w, PortIndex index, const char * label,
491                                 X11_UI* ui, int x, int y, int width, int height) {
492     w = create_widget(ui->win->app, ui->win, x, y, width, height);
493     w->label = label;
494     w->adj = add_adjustment(w,1.3, 1.3, 1.3, 4.3, 0.001, CL_CONTINUOS);
495     adj_set_scale(w->adj, 2.0);
496     ui->adj[0] = add_adjustment(w,1.3, 1.3, 1.3, 4.3, 0.001, CL_CONTINUOS);
497     adj_set_scale(ui->adj[0], 2.0);
498     ui->adj[1] = add_adjustment(w,1.3, 1.3, 1.3, 4.3, 0.001, CL_CONTINUOS);
499     adj_set_scale(ui->adj[1], 2.0);
500     ui->adj[2] = add_adjustment(w,1.3, 1.3, 1.3, 4.3, 0.001, CL_CONTINUOS);
501     adj_set_scale(ui->adj[2], 2.0);
502     w->scale.gravity = ASPECT;
503     w->func.expose_callback = draw_my_hslider;
504     w->func.enter_callback = transparent_draw;
505     w->func.leave_callback = transparent_draw;
506     w->func.button_press_callback = my_slider_pressed;
507     w->func.button_release_callback = my_slider_released;
508     w->parent_struct = ui;
509     w->data = index;
510     w->func.value_changed_callback = slider_value_changed;
511     return w;
512 }
513 
514 // init the xwindow and return the LV2UI handle
instantiate(const LV2UI_Descriptor * descriptor,const char * plugin_uri,const char * bundle_path,LV2UI_Write_Function write_function,LV2UI_Controller controller,LV2UI_Widget * widget,const LV2_Feature * const * features)515 static LV2UI_Handle instantiate(const LV2UI_Descriptor * descriptor,
516             const char * plugin_uri, const char * bundle_path,
517             LV2UI_Write_Function write_function,
518             LV2UI_Controller controller, LV2UI_Widget * widget,
519             const LV2_Feature * const * features) {
520 
521     X11_UI* ui = (X11_UI*)malloc(sizeof(X11_UI));
522 
523     if (!ui) {
524         fprintf(stderr,"ERROR: failed to instantiate plugin with URI %s\n", plugin_uri);
525         return NULL;
526     }
527 
528     ui->parentXwindow = 0;
529     LV2UI_Resize* resize = NULL;
530     ui->block_event = -1;
531     ui->db_zero = 20.*log10(0.0000003); // -130db
532 
533     int i = 0;
534     for (; features[i]; ++i) {
535         if (!strcmp(features[i]->URI, LV2_UI__parent)) {
536             ui->parentXwindow = features[i]->data;
537         } else if (!strcmp(features[i]->URI, LV2_UI__resize)) {
538             resize = (LV2UI_Resize*)features[i]->data;
539         }
540     }
541 
542     if (ui->parentXwindow == NULL)  {
543         fprintf(stderr, "ERROR: Failed to open parentXwindow for %s\n", plugin_uri);
544         free(ui);
545         return NULL;
546     }
547     // init Xputty
548     main_init(&ui->main);
549     set_my_theme(&ui->main);
550     // create the toplevel Window on the parentXwindow provided by the host
551     ui->win = create_window(&ui->main, (Window)ui->parentXwindow, 0, 0, 610, 320);
552     ui->win->parent_struct = ui;
553     ui->win->label = "GxMultiBandDelay";
554     widget_get_png(ui->win, LDVAR(guitarix_orange_png));
555     ui->screw = surface_get_png(ui->win, ui->screw, LDVAR(screw_png));
556     // connect the expose func
557     ui->win->func.expose_callback = draw_window;
558 
559     int iw=0;
560     int w_pos = 60;
561     int port = (PortIndex) V1;
562     for (;iw<5;iw++) {
563         ui->meter_widget[iw] = add_vmeter(ui->win, "Meter", false, w_pos, 40, 20, 210);
564         ui->meter_widget[iw]->parent_struct = ui;
565         ui->meter_widget[iw]->data = port;
566         port +=1;
567         w_pos +=100;
568     }
569 
570     iw=0;
571     w_pos = 85;
572     port = (PortIndex) DELAY1;
573     for (;iw<5;iw++) {
574         ui->widget[iw] = add_my_knob(ui->widget[iw], (PortIndex)port,"delay", ui,w_pos, 30, 60, 70);
575         set_adjustment(ui->widget[iw]->adj,30.0, 30.0, 24.0, 360.0, 1.0, CL_CONTINUOS);
576         //adj_set_scale(ui->widget[iw]->adj, 2.0);
577         port +=1;
578         w_pos +=100;
579     }
580 
581     w_pos = 85;
582     port = (PortIndex) FEEDBACK1;
583     for (;iw<10;iw++) {
584         ui->widget[iw] = add_my_knob(ui->widget[iw], (PortIndex)port,"Feedback", ui,w_pos, 105, 60, 70);
585         set_adjustment(ui->widget[iw]->adj,50.0, 50.0, 1.0, 100.0, 1.0, CL_CONTINUOS);
586         //adj_set_scale(ui->widget[iw]->adj, 2.0);
587         port +=1;
588         w_pos +=100;
589     }
590 
591     w_pos = 85;
592     port = (PortIndex) GAIN1;
593     for (;iw<15;iw++) {
594         ui->widget[iw] = add_my_knob(ui->widget[iw], (PortIndex)port,"Gain", ui,w_pos, 180, 60, 70);
595         set_adjustment(ui->widget[iw]->adj,1.0, 1.0, -40.0, 2.0, 0.5, CL_CONTINUOS);
596         //adj_set_scale(ui->widget[iw]->adj, 2.0);
597         port +=1;
598         w_pos +=100;
599     }
600 
601     ui->widget[15] = add_my_slider(ui->widget[15], CROSSOVER_B1_B2,"Crossover ",ui, 60,270, 480, 20);
602 
603     // map all widgets into the toplevel Widget_t
604     widget_show_all(ui->win);
605     // set the widget pointer to the X11 Window from the toplevel Widget_t
606     *widget = (void*)ui->win->widget;
607     // request to resize the parentXwindow to the size of the toplevel Widget_t
608     if (resize){
609         ui->resize = resize;
610         resize->ui_resize(resize->handle, 610, 320);
611     }
612     // store pointer to the host controller
613     ui->controller = controller;
614     // store pointer to the host write function
615     ui->write_function = write_function;
616 
617     return (LV2UI_Handle)ui;
618 }
619 
620 // map power to db for meter widgets
set_meter_value(X11_UI * ui,Widget_t * w,float value)621 static void set_meter_value(X11_UI* ui, Widget_t*w, float value) {
622     float new_val = power2db(w,20.*log10(max(ui->db_zero,value)));
623     check_value_changed(w->adj,&new_val);
624 }
625 
626 // cleanup after usage
cleanup(LV2UI_Handle handle)627 static void cleanup(LV2UI_Handle handle) {
628     X11_UI* ui = (X11_UI*)handle;
629     cairo_surface_destroy(ui->screw);
630     delete_adjustment(ui->adj[0]);
631     delete_adjustment(ui->adj[1]);
632     delete_adjustment(ui->adj[2]);
633     ui->widget[15]->adj_x = NULL;
634     // Xputty free all memory used
635     main_quit(&ui->main);
636     free(ui);
637 }
638 
639 /*---------------------------------------------------------------------
640 -----------------------------------------------------------------------
641                         LV2 interface
642 -----------------------------------------------------------------------
643 ----------------------------------------------------------------------*/
644 
645 // port value change message from host
port_event(LV2UI_Handle handle,uint32_t port_index,uint32_t buffer_size,uint32_t format,const void * buffer)646 static void port_event(LV2UI_Handle handle, uint32_t port_index,
647                         uint32_t buffer_size, uint32_t format,
648                         const void * buffer) {
649     X11_UI* ui = (X11_UI*)handle;
650     float value = *(float*)buffer;
651     int i=0;
652     for (;i<CONTROLS;i++) {
653         if (port_index == (uint32_t)ui->widget[i]->data) {
654             // prevent event loop between host and plugin
655             ui->block_event = (int)port_index;
656             // Xputty check if the new value differs from the old one
657             // and set new one, when needed
658             check_value_changed(ui->widget[i]->adj, &value);
659         }
660     }
661     if (port_index == V1) set_meter_value(ui,ui->meter_widget[0],value);
662     else if (port_index == V2) set_meter_value(ui,ui->meter_widget[1],value);
663     else if (port_index == V3) set_meter_value(ui,ui->meter_widget[2],value);
664     else if (port_index == V4) set_meter_value(ui,ui->meter_widget[3],value);
665     else if (port_index == V5) set_meter_value(ui,ui->meter_widget[4],value);
666     if (port_index >= CROSSOVER_B1_B2 && port_index <= CROSSOVER_B4_B5) {
667         check_multi_controller(ui, port_index, value);
668         ui->block_event = (int)port_index;
669     }
670 }
671 
672 // LV2 idle interface to host
ui_idle(LV2UI_Handle handle)673 static int ui_idle(LV2UI_Handle handle) {
674     X11_UI* ui = (X11_UI*)handle;
675     // Xputty event loop setup to run one cycle when called
676     run_embedded(&ui->main);
677     return 0;
678 }
679 
680 // LV2 resize interface to host
ui_resize(LV2UI_Feature_Handle handle,int w,int h)681 static int ui_resize(LV2UI_Feature_Handle handle, int w, int h) {
682     X11_UI* ui = (X11_UI*)handle;
683     // Xputty sends configure event to the toplevel widget to resize itself
684     if (ui) send_configure_event(ui->win,0, 0, w, h);
685     return 0;
686 }
687 
688 // connect idle and resize functions to host
extension_data(const char * uri)689 static const void* extension_data(const char* uri) {
690     static const LV2UI_Idle_Interface idle = { ui_idle };
691     static const LV2UI_Resize resize = { 0 ,ui_resize };
692     if (!strcmp(uri, LV2_UI__idleInterface)) {
693         return &idle;
694     }
695     if (!strcmp(uri, LV2_UI__resize)) {
696         return &resize;
697     }
698     return NULL;
699 }
700 
701 static const LV2UI_Descriptor descriptor = {
702     GXPLUGIN_UI_URI,
703     instantiate,
704     cleanup,
705     port_event,
706     extension_data
707 };
708 
709 
710 
711 extern "C"
712 LV2_SYMBOL_EXPORT
lv2ui_descriptor(uint32_t index)713 const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) {
714     switch (index) {
715         case 0:
716             return &descriptor;
717         default:
718         return NULL;
719     }
720 }
721 
722