1 /* Mixer+Trigger
2 *
3 * Copyright (C) 2013 Robin Gareus <robin@gareus.org>
4 *
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, or (at your option)
8 * any later version.
9 *
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.
14 *
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/>.
17 */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <math.h>
22
23 #include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
24 #include "src/mixtri.h"
25
26 #define MIX_WIDTH 80
27 #define MIX_HEIGHT 40
28 #define MIX_RADIUS 10
29 #define MIX_CX 39.5
30 #define MIX_CY 16.5
31
32 typedef struct {
33 LV2UI_Write_Function write;
34 LV2UI_Controller controller;
35
36 RobWidget *hbox, *ctable;
37
38 RobTkLbl *lbl_in[4];
39 RobTkLbl *lbl_out[3];
40 RobTkLbl *label[9];
41 RobTkDial *dial_in[4];
42 RobTkDial *dial_mix[12];
43 RobTkSpin *spb_delay_in[4];
44 RobTkSpin *spb_delay_out[3];
45 RobTkCBtn *btn_hpfilt_in[4];
46 RobTkCBtn *btn_mute_in[4];
47 RobTkRBtn *btn_trig_src[4];
48 RobTkSelect *sel_trig_mode;
49
50 RobTkLbl *lbl_trig[4];
51 RobTkSelect *sel_trig_edge;
52 RobTkSpin *spb_trigger_tme[2];
53 RobTkSpin *spb_trigger_lvl[2];
54 RobTkDarea *drawing_area;
55 RobTkCBtn *btn_show_doc;
56
57 bool disable_signals;
58
59 PangoFontDescription *font[2];
60
61 cairo_surface_t* routeT;
62 cairo_surface_t* routeC;
63 cairo_surface_t* routeM;
64 cairo_surface_t* routeE;
65 cairo_surface_t* routeI;
66 cairo_surface_t* delayI;
67 cairo_surface_t* delayO;
68
69 } MixTriUI;
70
create_faceplate(MixTriUI * ui)71 static void create_faceplate(MixTriUI *ui) {
72 cairo_t* cr;
73 float xlp, ylp;
74 PangoFontDescription *font = pango_font_description_from_string("Sans 8px");
75
76 #define AMPLABEL(V, O, T, X) \
77 { \
78 float ang = (-.75 * M_PI) + (1.5 * M_PI) * ((V) + (O)) / (T); \
79 xlp = X + .5 + sinf (ang) * (MIX_RADIUS + 3.0); \
80 ylp = MIX_CY + .5 - cosf (ang) * (MIX_RADIUS + 3.0); \
81 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); \
82 CairoSetSouerceRGBA(c_wht); \
83 cairo_set_line_width(cr, 1.5); \
84 cairo_move_to(cr, rint(xlp)-.5, rint(ylp)-.5); \
85 cairo_close_path(cr); \
86 cairo_stroke(cr); \
87 xlp = X + .5 + sinf (ang) * (MIX_RADIUS + 9.5); \
88 ylp = MIX_CY + .5 - cosf (ang) * (MIX_RADIUS + 9.5); \
89 }
90
91 #define COMMONRROUTE(SF, TOP, RIGHT) \
92 SF = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, MIX_WIDTH, MIX_HEIGHT); \
93 cr = cairo_create (SF); \
94 cairo_set_source_rgba (cr, .3, .3, .4, 1.0); \
95 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); \
96 cairo_rectangle (cr, 0, 0, MIX_WIDTH, MIX_HEIGHT); \
97 cairo_fill (cr); \
98 cairo_set_operator (cr, CAIRO_OPERATOR_OVER); \
99 CairoSetSouerceRGBA(c_g60); \
100 cairo_set_line_width(cr, 1.0); \
101 cairo_move_to(cr, 0, MIX_CY); \
102 cairo_line_to(cr, RIGHT, MIX_CY); \
103 cairo_stroke(cr); \
104 CairoSetSouerceRGBA(c_blk); \
105 cairo_move_to(cr, MIX_CX, TOP); \
106 cairo_line_to(cr, MIX_CX, MIX_HEIGHT); \
107 cairo_stroke(cr); \
108 cairo_move_to(cr, MIX_CX-3, MIX_HEIGHT-6.5); \
109 cairo_line_to(cr, MIX_CX+3, MIX_HEIGHT-6.5); \
110 cairo_line_to(cr, MIX_CX, MIX_HEIGHT-0.5); \
111 cairo_close_path(cr); \
112 cairo_fill(cr); \
113 AMPLABEL(-20, 20., 40., MIX_CX); write_text_full(cr, "-20", font, xlp, ylp, 0, 2, c_wht); \
114 AMPLABEL( 20, 20., 40., MIX_CX); write_text_full(cr, "+20", font, xlp, ylp, 0, 2, c_wht); \
115 AMPLABEL( 0, 20., 40., MIX_CX); \
116 AMPLABEL(-12, 20., 40., MIX_CX); \
117 AMPLABEL( -6, 20., 40., MIX_CX); \
118 AMPLABEL( 0, 20., 40., MIX_CX); \
119 AMPLABEL( 6, 20., 40., MIX_CX); \
120 AMPLABEL( 12, 20., 40., MIX_CX); \
121 cairo_destroy (cr);
122
123 COMMONRROUTE(ui->routeM, 0, MIX_WIDTH);
124 COMMONRROUTE(ui->routeE, 0, MIX_CX);
125 COMMONRROUTE(ui->routeT, MIX_CY, MIX_WIDTH);
126 COMMONRROUTE(ui->routeC, MIX_CY, MIX_CX);
127
128
129 const double dashed[] = {2.5};
130 #define DASHEDROUTE(SF) \
131 cr = cairo_create (SF); \
132 CairoSetSouerceRGBA(c_g60); \
133 cairo_set_line_width(cr, 1.0); \
134 cairo_set_dash(cr, dashed, 1, 0); \
135 cairo_move_to(cr, MIX_CX, MIX_CY); \
136 cairo_line_to(cr, MIX_WIDTH, MIX_CY); \
137 cairo_stroke(cr); \
138 cairo_move_to(cr, MIX_WIDTH-15.5, MIX_CY-3.5); \
139 cairo_line_to(cr, MIX_WIDTH-15.5, MIX_CY+3.5); \
140 cairo_line_to(cr, MIX_WIDTH-9.5, MIX_CY); \
141 cairo_close_path(cr); \
142 cairo_fill(cr); \
143 cairo_destroy (cr);
144
145 DASHEDROUTE(ui->routeE)
146 DASHEDROUTE(ui->routeC)
147
148 ui->routeI = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 60, MIX_HEIGHT);
149 cr = cairo_create (ui->routeI);
150 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
151 cairo_rectangle (cr, 0, 0, 2, MIX_HEIGHT);
152 cairo_set_source_rgba (cr, .0, .0, .0, .0);
153 cairo_fill (cr);
154 cairo_rectangle (cr, 2, 0, MIX_WIDTH-2, MIX_HEIGHT);
155 cairo_set_source_rgba (cr, .3, .4, .3, 1.0);
156 cairo_fill (cr);
157 CairoSetSouerceRGBA(c_g60);
158 cairo_set_line_width(cr, 1.0);
159 cairo_move_to(cr, 0, MIX_CY);
160 cairo_line_to(cr, 60, MIX_CY);
161 cairo_stroke(cr);
162
163 cairo_move_to(cr, 6.5, MIX_CY-3.5);
164 cairo_line_to(cr, 6.5, MIX_CY+3.5);
165 cairo_line_to(cr, 12.5, MIX_CY);
166 cairo_close_path(cr);
167 cairo_move_to(cr, 60-7.5, MIX_CY-3.5);
168 cairo_line_to(cr, 60-7.5, MIX_CY+3.5);
169 cairo_line_to(cr, 60-1.5, MIX_CY);
170 cairo_close_path(cr);
171 cairo_fill(cr);
172
173 AMPLABEL( 0, 60., 80., 30.5); write_text_full(cr, " 0dB", font, xlp, ylp, 0, 2, c_wht);
174 AMPLABEL( 20, 60., 80., 30.5); write_text_full(cr, "+20", font, xlp, ylp, 0, 2, c_wht);
175 AMPLABEL(-60, 60., 80., 30.5); write_text_full(cr, "-60", font, xlp, ylp, 0, 2, c_wht);
176 AMPLABEL(-50, 60., 80., 30.5);
177 AMPLABEL(-40, 60., 80., 30.5);
178 AMPLABEL(-30, 60., 80., 30.5);
179 AMPLABEL(-20, 60., 80., 30.5);
180 AMPLABEL(-10, 60., 80., 30.5);
181 AMPLABEL( 10, 60., 80., 30.5);
182 AMPLABEL( 20, 60., 80., 30.5);
183 pango_font_description_free(font);
184
185 ui->delayO = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, MIX_WIDTH, GSP_HEIGHT);
186 cr = cairo_create (ui->delayO);
187 cairo_set_source_rgba (cr, .3, .2, .4, 1.0);
188 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
189 cairo_rectangle (cr, 0, 0, MIX_WIDTH, GSP_HEIGHT);
190 cairo_fill (cr);
191 cairo_set_line_width(cr, 1.0);
192 CairoSetSouerceRGBA(c_blk);
193 cairo_move_to(cr, MIX_CX, 0);
194 cairo_line_to(cr, MIX_CX, GSP_HEIGHT);
195 cairo_stroke(cr);
196 cairo_move_to(cr, MIX_CX-3, GSP_HEIGHT-6.5);
197 cairo_line_to(cr, MIX_CX+3, GSP_HEIGHT-6.5);
198 cairo_line_to(cr, MIX_CX, GSP_HEIGHT-0.5);
199 cairo_close_path(cr);
200 cairo_fill(cr);
201 cairo_destroy (cr);
202
203 ui->delayI = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, MIX_WIDTH, GSP_HEIGHT);
204 cr = cairo_create (ui->delayI);
205 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
206 cairo_set_source_rgba (cr, .0, .0, .0, .0);
207 cairo_rectangle (cr, 0, 0, MIX_WIDTH, GSP_HEIGHT);
208 cairo_fill (cr);
209 cairo_set_source_rgba (cr, .4, .3, .3, 1.0);
210 cairo_rectangle (cr, 0, 0, MIX_WIDTH-4, GSP_HEIGHT);
211 cairo_fill (cr);
212 cairo_set_line_width(cr, 1.0);
213 CairoSetSouerceRGBA(c_g60);
214 cairo_set_line_width(cr, 1.0);
215 cairo_move_to(cr, 0, GSP_CY);
216 cairo_line_to(cr, MIX_WIDTH-3, GSP_CY);
217 cairo_stroke(cr);
218 cairo_destroy (cr);
219
220 }
221
annotation_txt(MixTriUI * ui,RobTkDial * d,cairo_t * cr,const char * txt)222 static void annotation_txt(MixTriUI *ui, RobTkDial * d, cairo_t *cr, const char *txt) {
223 int tw, th;
224 cairo_save(cr);
225 PangoLayout * pl = pango_cairo_create_layout(cr);
226 pango_layout_set_font_description(pl, ui->font[0]);
227 pango_layout_set_text(pl, txt, -1);
228 pango_layout_get_pixel_size(pl, &tw, &th);
229 cairo_translate (cr, d->w_cx, d->w_height);
230 cairo_translate (cr, -tw/2.0 - 0.5, -th);
231 cairo_set_source_rgba (cr, .0, .0, .0, .7);
232 rounded_rectangle(cr, -1, -1, tw+3, th+1, 3);
233 cairo_fill(cr);
234 CairoSetSouerceRGBA(c_wht);
235 pango_cairo_show_layout(cr, pl);
236 g_object_unref(pl);
237 cairo_restore(cr);
238 cairo_new_path(cr);
239 }
240
dial_annotation_val(RobTkDial * d,cairo_t * cr,void * data)241 static void dial_annotation_val(RobTkDial * d, cairo_t *cr, void *data) {
242 MixTriUI* ui = (MixTriUI*) (data);
243 char tmp[16];
244 switch(d->click_state) {
245 case 1:
246 snprintf(tmp, 16, "-\u221EdB");
247 break;
248 case 2:
249 snprintf(tmp, 16, "\u00D8%+4.1fdB", d->cur);
250 break;
251 default:
252 snprintf(tmp, 16, "%+4.1fdB", d->cur);
253 break;
254 }
255 annotation_txt(ui, d, cr, tmp);
256 }
257
dial_annotation_db(RobTkDial * d,cairo_t * cr,void * data)258 static void dial_annotation_db(RobTkDial * d, cairo_t *cr, void *data) {
259 MixTriUI* ui = (MixTriUI*) (data);
260 char tmp[16];
261 snprintf(tmp, 16, "%+4.1fdB", d->cur);
262 annotation_txt(ui, d, cr, tmp);
263 }
264
box_expose_event(RobWidget * rw,cairo_t * cr,cairo_rectangle_t * ev)265 static bool box_expose_event(RobWidget* rw, cairo_t* cr, cairo_rectangle_t *ev) {
266 if (rw->resized) {
267 cairo_rectangle_t event;
268 event.x = MAX(0, ev->x - rw->area.x);
269 event.y = MAX(0, ev->y - rw->area.y);
270 event.width = MIN(rw->area.x + rw->area.width , ev->x + ev->width) - MAX(ev->x, rw->area.x);
271 event.height = MIN(rw->area.y + rw->area.height, ev->y + ev->height) - MAX(ev->y, rw->area.y);
272 cairo_save(cr);
273 rcontainer_clear_bg(rw, cr, &event);
274
275 const float ytop = ((struct rob_table*)rw->self)->rows[0].acq_h;
276 float tx0 = 0, tc0 = 0, tc1 = 0;
277 for (uint32_t i = 0; i < 8; ++i) {
278 tx0 += ((struct rob_table*)rw->self)->cols[i].acq_w;
279 if (i == 0) tc0 = tx0;
280 if (i == 3) tc1 = tx0;
281 }
282 const float yof = ytop + MIX_CY;
283 const float twi = ((struct rob_table*)rw->self)->cols[8].acq_w;
284 const float tx1 = tx0 + twi / 2;
285
286 /* fixup in-delayline bg & channel mods */
287 cairo_set_source_rgba (cr, .4, .3, .3, 1.0);
288 cairo_rectangle (cr, tc0, ytop, tc1-tc0, 160);
289 cairo_fill(cr);
290
291 /* right end trigger background */
292 cairo_set_source_rgba (cr, .2, .3, .35, 1.0);
293 cairo_rectangle (cr, tx0, ytop, twi, 160+30);
294 cairo_fill(cr);
295
296 cairo_set_line_width(cr, 1.0);
297 CairoSetSouerceRGBA(c_g60);
298
299 for (uint32_t i = 0; i < 4; ++i) {
300 const float y0 = yof + i * MIX_HEIGHT;
301 cairo_move_to(cr, tc0, y0);
302 cairo_line_to(cr, tc1, y0);
303 cairo_stroke(cr);
304 }
305
306 const double dashed[] = {2.5};
307 cairo_set_dash(cr, dashed, 1, 4);
308 for (uint32_t i = 0; i < 4; ++i) {
309 const float y0 = yof + i * MIX_HEIGHT;
310 cairo_move_to(cr, tx0-2, y0);
311 cairo_line_to(cr, tx1, y0);
312 cairo_stroke(cr);
313 }
314 cairo_set_dash(cr, NULL, 0, 0);
315 CairoSetSouerceRGBA(c_blk);
316 for (uint32_t i = 0; i < 5; ++i) {
317 float y0 = yof + i * MIX_HEIGHT;
318 cairo_move_to(cr, tx1+.5, y0);
319 cairo_line_to(cr, tx1+.5, y0 + MIX_HEIGHT);
320 cairo_stroke(cr);
321
322 if (i == 4) y0 -= 10; // MIX_HEIGHT - GED_HEIGHT
323
324 cairo_move_to(cr, tx1+.5-3, y0+23-6.5);
325 cairo_line_to(cr, tx1+.5+3, y0+23-6.5);
326 cairo_line_to(cr, tx1+.5, y0+23-0.5);
327 cairo_close_path(cr);
328 cairo_fill(cr);
329 }
330 cairo_restore(cr);
331 }
332 return rcontainer_expose_event_no_clear(rw, cr, ev);
333 }
334
draw_arrow(cairo_t * cr,float x,float y,bool down)335 static void draw_arrow (cairo_t *cr, float x, float y, bool down) {
336 cairo_save(cr);
337 cairo_set_source_rgba (cr, .95, 1.0, .95, .8);
338 cairo_set_line_width(cr, 1.0);
339 cairo_move_to(cr, x+.5, y+.5);
340 if (down) {
341 cairo_line_to(cr, x+.5, y+12.5);
342 cairo_stroke(cr);
343 cairo_move_to(cr, x+.5, y+12.5);
344 cairo_line_to(cr, x+3.5, y+7.5);
345 cairo_line_to(cr, x-2.5, y+7.5);
346 cairo_close_path(cr);
347 cairo_fill(cr);
348 } else {
349 cairo_line_to(cr, x+.5, y-11.5);
350 cairo_stroke(cr);
351 cairo_move_to(cr, x+.5, y-11.5);
352 cairo_line_to(cr, x+3.5, y-6.5);
353 cairo_line_to(cr, x-2.5, y-6.5);
354 cairo_close_path(cr);
355 cairo_fill(cr);
356 }
357 cairo_restore(cr);
358 }
359
draw_cross(cairo_t * cr,float x,float y)360 static void draw_cross (cairo_t *cr, float x, float y) {
361 cairo_save(cr);
362 cairo_set_source_rgba (cr, .95, 1.0, .95, .8);
363 cairo_set_line_width(cr, 1.0);
364
365 cairo_move_to(cr, x-2.5, y-2.5);
366 cairo_line_to(cr, x+3.5, y+3.5);
367 cairo_stroke(cr);
368 cairo_move_to(cr, x+3.5, y-2.5);
369 cairo_line_to(cr, x-2.5, y+3.5);
370 cairo_stroke(cr);
371 cairo_restore(cr);
372 }
373
draw_timedelta(cairo_t * cr,float x,float y,float w,float dw)374 static void draw_timedelta (cairo_t *cr, float x, float y, float w, float dw) {
375 cairo_save(cr);
376 cairo_set_line_width(cr, 1.0);
377
378 if (dw > 0) {
379 cairo_set_source_rgba (cr, .95, 1.0, .95, .6);
380 cairo_rectangle(cr, x+w-dw+.5, y-2.5, dw*2, 6.0);
381 cairo_fill(cr);
382 }
383
384 cairo_set_source_rgba (cr, .95, 1.0, .95, .8);
385 cairo_move_to(cr, x+.5, y-2.5);
386 cairo_line_to(cr, x+.5, y+3.5);
387 cairo_stroke(cr);
388
389 cairo_move_to(cr, x+.5, y+.5);
390 cairo_line_to(cr, x+w+.5, y+.5);
391 cairo_stroke(cr);
392
393 cairo_move_to(cr, x+w+.5, y-1.5);
394 cairo_line_to(cr, x+w+.5, y+2.5);
395 cairo_stroke(cr);
396
397 cairo_restore(cr);
398 }
399
400 #define ANN_TEXT(txt) \
401 write_text_full(cr, txt, ui->font[1], 0, doc_h, 0, 6, c_wht);
402
draw_trigger_doc(cairo_t * cr,void * d)403 static void draw_trigger_doc (cairo_t *cr, void *d) {
404 MixTriUI* ui = (MixTriUI*) (d);
405 int mode = robtk_select_get_value(ui->sel_trig_mode);
406 int edge = robtk_select_get_value(ui->sel_trig_edge);
407
408 float c_bg[4];
409 get_color_from_theme(1, c_bg);
410
411 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
412 CairoSetSouerceRGBA(c_bg);
413 cairo_rectangle (cr, 0, 0, 150, 180);
414 cairo_fill(cr);
415
416 cairo_set_source_rgba (cr, .1, .1, .1, 1.0);
417 cairo_rectangle (cr, 5, 0, 140, 180);
418 cairo_fill(cr);
419
420 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
421
422 cairo_save(cr);
423 cairo_translate(cr, 10, 5);
424 const float doc_w = 130;
425 const float doc_h = 175;
426 const float doc_b = 100;
427 cairo_rectangle(cr, 0, 0, doc_w, doc_h);
428 cairo_clip(cr);
429
430 /* grid */
431
432 cairo_set_line_width(cr, 1.5);
433 cairo_set_source_rgba (cr, .4, .4, .4, 1.0);
434
435 const double dash[] = {1.5};
436 cairo_set_line_width(cr, 1.0);
437 cairo_set_dash(cr, dash, 1, 0);
438
439 switch (mode) {
440 case TRG_PASSTRHU :
441 break;
442 default:
443 for (uint32_t i = 5; i < doc_w; i+=10) {
444 cairo_move_to(cr, i+.5, 0);
445 cairo_line_to(cr, i+.5, doc_b);
446 cairo_stroke(cr);
447 }
448 for (uint32_t i = 5; i < doc_b; i+=10) {
449 cairo_move_to(cr, 0, i+.5);
450 cairo_line_to(cr, doc_w, i+.5);
451 cairo_stroke(cr);
452 }
453 break;
454 }
455
456 cairo_set_dash(cr, NULL, 0, 0);
457
458 /* waveform */
459
460 cairo_set_source_rgba (cr, 1.0, .0, .0, 1.0);
461
462 switch (mode) {
463 case TRG_EDGE :
464 case TRG_WINDOW_ENTER:
465 case TRG_WINDOW_LEAVE:
466 cairo_move_to(cr, 5, 60);
467 cairo_curve_to(cr, 15, 50, 20, 75, 25, 80);
468 cairo_curve_to(cr, 25, 80, 38, 90, 45, 70);
469 cairo_curve_to(cr, 45, 70, 60, 0, 87, 40);
470 cairo_curve_to(cr, 88, 40, 100, 75, 120, 25);
471 cairo_line_to(cr, 125, 8);
472 cairo_stroke(cr);
473 break;
474 case TRG_DROPIN:
475 case TRG_HYSTERESIS:
476 cairo_move_to(cr, 5, 20);
477 cairo_curve_to(cr, 18, 40, 22, 75, 30, 80);
478 cairo_curve_to(cr, 30, 80, 38, 90, 45, 70);
479 cairo_curve_to(cr, 45, 70, 60, 0, 87, 40);
480 cairo_curve_to(cr, 88, 40, 100, 75, 120, 25);
481 cairo_line_to(cr, 125, 8);
482 cairo_stroke(cr);
483 break;
484 case TRG_DROPOUT:
485 cairo_move_to(cr, 5.5, 75.5);
486 cairo_line_to(cr, 25.5, 75.5);
487 cairo_line_to(cr, 26.5, 25.5);
488 cairo_line_to(cr, 55.5, 25.5);
489 cairo_line_to(cr, 56.5, 75.5);
490 cairo_line_to(cr,125.5, 75.5);
491 cairo_stroke(cr);
492 break;
493 case TRG_RUNT:
494 cairo_move_to(cr, 5.5, 75.5);
495 cairo_line_to(cr, 15.5, 75.5);
496 cairo_line_to(cr, 16.5, 25.5);
497 cairo_line_to(cr, 35.5, 25.5);
498 cairo_line_to(cr, 36.5, 75.5);
499 cairo_line_to(cr, 55.5, 75.5);
500 cairo_line_to(cr, 56.5, 45.5);
501 cairo_line_to(cr, 75.5, 45.5);
502 cairo_line_to(cr, 76.5, 75.5);
503 cairo_line_to(cr, 95.5, 75.5);
504 cairo_line_to(cr, 96.5, 25.5);
505 cairo_line_to(cr,105.5, 25.5);
506 cairo_line_to(cr,106.5, 55.5);
507 cairo_line_to(cr,115.5, 55.5);
508 cairo_line_to(cr,116.5, 25.5);
509 cairo_line_to(cr,125.5, 25.5);
510 cairo_stroke(cr);
511 break;
512 case TRG_PULSEWIDTH:
513 case TRG_PULSETRAIN:
514 cairo_move_to(cr, 5.5, 25.5);
515 cairo_line_to(cr, 6.5, 75.5);
516 cairo_line_to(cr, 25.5, 75.5);
517 cairo_line_to(cr, 26.5, 25.5);
518 cairo_line_to(cr, 45.5, 25.5);
519 cairo_line_to(cr, 46.5, 75.5);
520 cairo_line_to(cr, 75.5, 75.5);
521 cairo_line_to(cr, 76.5, 25.5);
522 cairo_line_to(cr, 85.5, 25.5);
523 cairo_line_to(cr, 86.5, 75.5);
524 cairo_line_to(cr, 95.5, 75.5);
525 cairo_line_to(cr, 96.5, 25.5);
526 cairo_line_to(cr,115.5, 25.5);
527 cairo_line_to(cr,116.5, 75.5);
528 cairo_line_to(cr,125.5, 75.5);
529 cairo_stroke(cr);
530 break;
531 case TRG_LTC:
532 cairo_move_to(cr, 5.5, 75.5);
533 for (int i = 0; i < 70; i+=5) {
534 cairo_line_to(cr, i + 10.5, (i%10 != 0)? 25.5 : 75.5);
535 cairo_line_to(cr, i + 11.5, (i%10 == 0)? 25.5 : 75.5);
536 }
537 cairo_line_to(cr,85.5, 75.5);
538 cairo_line_to(cr,86.5, 25.5);
539 cairo_line_to(cr,90.5, 25.5);
540 cairo_line_to(cr,91.5, 75.5);
541 cairo_line_to(cr,95.5, 75.5);
542 cairo_line_to(cr,96.5, 25.5);
543 cairo_line_to(cr,105.5, 25.5);
544 cairo_line_to(cr,106.5, 75.5);
545 cairo_line_to(cr,115.5, 75.5);
546 cairo_line_to(cr,116.5, 25.5);
547 cairo_line_to(cr,120.5, 25.5);
548 cairo_line_to(cr,121.5, 75.5);
549 cairo_line_to(cr,125.5, 75.5);
550 cairo_line_to(cr,126.5, 25.5);
551 cairo_stroke(cr);
552 break;
553 case TRG_LPF:
554 cairo_move_to(cr, 5.5, 50);
555 {
556 float phase = 0;
557 for (uint32_t i = 1; i < 120; ++i) {
558 phase+=.05 + .4 * i / 120.0;
559 cairo_line_to(cr, i + 5.5, 50 + 40.0 * sinf(phase));
560 }
561 }
562 cairo_stroke(cr);
563 break;
564 case TRG_RMS:
565 cairo_move_to(cr, 5.5, 50);
566 for (uint32_t i = 1; i < 120; ++i) {
567 cairo_line_to(cr, i + 5.5, 50 + 40.0 * sinf(i * .2));
568 }
569 cairo_stroke(cr);
570 break;
571 case TRG_PASSTRHU:
572 default:
573 break;
574 }
575
576 /* settings & annotation */
577 switch (mode) {
578 case TRG_EDGE :
579 cairo_set_source_rgba (cr, .0, 1.0, .0, .8);
580 cairo_move_to(cr, 0, 40.5);
581 cairo_line_to(cr, doc_w, 40.5);
582 cairo_stroke(cr);
583 if (edge&1) {
584 draw_arrow(cr, 55, 70, false);
585 draw_arrow(cr, 112, 70, false);
586 }
587 if (edge&2) {
588 draw_arrow(cr, 85, 10, true);
589 }
590 ANN_TEXT("Signal Edge\n Signal passes 'Level 1'.");
591 break;
592 case TRG_PULSEWIDTH:
593 cairo_set_source_rgba (cr, .0, 1.0, .0, .8);
594 cairo_move_to(cr, 0, 40.5);
595 cairo_line_to(cr, doc_w, 40.5);
596 cairo_stroke(cr);
597
598 if (edge & 1) {
599 draw_cross(cr, 25, 40);
600 draw_cross(cr, 75, 40);
601 draw_cross(cr, 95, 40);
602 }
603
604 if (edge & 2) {
605 draw_cross(cr, 5, 40);
606 draw_cross(cr, 45, 40);
607 draw_cross(cr, 85, 40);
608 draw_cross(cr,115, 40);
609 }
610
611 switch (edge) {
612 case 1:
613 draw_timedelta(cr, 25, 90, 20, 5);
614 draw_timedelta(cr, 75, 90, 20, 5);
615 draw_arrow(cr,95, 20, false);
616 break;
617 case 2:
618 draw_timedelta(cr, 5, 80, 40, 5);
619 draw_timedelta(cr, 45, 90, 40, 5);
620 draw_arrow(cr, 45, 10, true);
621 draw_arrow(cr, 85, 10, true);
622 break;
623 case 3:
624 draw_timedelta(cr, 5, 80, 20, 5);
625 draw_timedelta(cr, 25, 90, 20, 5);
626 draw_timedelta(cr, 45, 80, 20, 5);
627 draw_timedelta(cr, 75, 90, 20, 5);
628 draw_timedelta(cr, 85, 90, 20, 5);
629 draw_timedelta(cr, 95, 80, 20, 5);
630
631 draw_arrow(cr, 25, 20, false);
632 draw_arrow(cr, 45, 10, true);
633 draw_arrow(cr,115, 10, true);
634 break;
635 }
636
637 ANN_TEXT("Pulse Width\n Last edge-trigger\n occurred between min\n and max (Time 1, 2) ago.");
638 break;
639 case TRG_PULSETRAIN:
640 cairo_set_source_rgba (cr, .0, 1.0, .0, .8);
641 cairo_move_to(cr, 0, 40.5);
642 cairo_line_to(cr, doc_w, 40.5);
643 cairo_stroke(cr);
644
645 if (edge & 1) {
646 draw_cross(cr, 25, 40);
647 draw_cross(cr, 75, 40);
648 draw_cross(cr, 95, 40);
649 }
650 if (edge & 2) {
651 draw_cross(cr, 5, 40);
652 draw_cross(cr, 45, 40);
653 draw_cross(cr, 85, 40);
654 draw_cross(cr,115, 40);
655 }
656
657 switch (edge) {
658 case 1:
659 draw_timedelta(cr, 25, 90, 20, 5);
660 draw_timedelta(cr, 75, 90, 20, 5);
661 draw_timedelta(cr, 95, 80, 20, 5);
662 draw_arrow(cr, 50, 20, false);
663 draw_arrow(cr,120, 20, false);
664 break;
665 case 2:
666 draw_timedelta(cr, 5, 80, 40, 5);
667 draw_timedelta(cr, 45, 90, 40, 5);
668 draw_timedelta(cr, 85, 80, 40, 5);
669 draw_arrow(cr,115, 10, true);
670 break;
671 case 3:
672 draw_timedelta(cr, 5, 80, 20, 5);
673 draw_timedelta(cr, 25, 90, 20, 5);
674 draw_timedelta(cr, 45, 80, 20, 5);
675 draw_timedelta(cr, 75, 90, 20, 5);
676
677 draw_arrow(cr, 70, 10, true);
678 draw_arrow(cr, 85, 20, false);
679 break;
680 }
681
682 ANN_TEXT("Pulse Train\n No edge-trigger for a\n given time (max, Time 2),\n or more than one trigger\n since a given time (min,\n Time 1).");
683 break;
684 case TRG_WINDOW_ENTER:
685 cairo_set_source_rgba (cr, .0, 1.0, .0, .8);
686 cairo_move_to(cr, 0, 35.5);
687 cairo_line_to(cr, doc_w, 35.5);
688 cairo_stroke(cr);
689 cairo_move_to(cr, 0, 45.5);
690 cairo_line_to(cr, doc_w, 45.5);
691 cairo_stroke(cr);
692
693
694 if (edge&1) {
695 cairo_set_source_rgba (cr, .0, 1.0, .0, .4);
696 cairo_rectangle(cr, 53, 35.5, 5, 10); cairo_fill(cr);
697 cairo_rectangle(cr, 108, 35.5, 7, 10); cairo_fill(cr);
698 draw_arrow(cr, 53, 70, false);
699 draw_arrow(cr,108, 70, false);
700 }
701 if (edge&2) {
702 cairo_set_source_rgba (cr, .0, 1.0, .0, .4);
703 cairo_rectangle(cr, 84, 35.5, 6, 10); cairo_fill(cr);
704 draw_arrow(cr, 84, 10, true);
705 }
706 ANN_TEXT("Enter Window\n Signal enters a given\n range (Level 1, 2).");
707 break;
708 case TRG_WINDOW_LEAVE:
709 cairo_set_source_rgba (cr, .0, 1.0, .0, .8);
710 cairo_move_to(cr, 0, 35.5);
711 cairo_line_to(cr, doc_w, 35.5);
712 cairo_stroke(cr);
713 cairo_move_to(cr, 0, 45.5);
714 cairo_line_to(cr, doc_w, 45.5);
715 cairo_stroke(cr);
716
717 cairo_set_source_rgba (cr, .0, 1.0, .0, .4);
718 if (edge&1) {
719 cairo_rectangle(cr, 53, 35.5, 5, 10); cairo_fill(cr);
720 cairo_rectangle(cr, 108, 35.5, 7, 10); cairo_fill(cr);
721 draw_arrow(cr, 58, 70, false);
722 draw_arrow(cr,115, 70, false);
723 }
724 if (edge&2) {
725 cairo_rectangle(cr, 84, 35.5, 6, 10); cairo_fill(cr);
726 draw_arrow(cr, 90, 10, true);
727 }
728
729 ANN_TEXT("Leave Window\n Signal leaves a given\n range (Level 1, 2).");
730 break;
731 case TRG_HYSTERESIS:
732 cairo_set_source_rgba (cr, .0, 1.0, .0, .8);
733 cairo_move_to(cr, 0, 35.5);
734 cairo_line_to(cr, doc_w, 35.5);
735 cairo_stroke(cr);
736 cairo_move_to(cr, 0, 65.5);
737 cairo_line_to(cr, doc_w, 65.5);
738 cairo_stroke(cr);
739 if (edge&1) {
740 draw_arrow(cr, 58, 80, false);
741 }
742 if (edge&2) {
743 draw_arrow(cr, 23, 10, true);
744 }
745 ANN_TEXT("Hysteresis\n Signal crosses both min\n and max (Level 1, 2) in\n the same direction\n without interruption.");
746 break;
747 case TRG_RUNT:
748 cairo_set_source_rgba (cr, .0, 1.0, .0, .8);
749 cairo_move_to(cr, 0, 40.5);
750 cairo_line_to(cr, doc_w, 40.5);
751 cairo_stroke(cr);
752 cairo_move_to(cr, 0, 60.5);
753 cairo_line_to(cr, doc_w, 60.5);
754 cairo_stroke(cr);
755 if (edge & 1) {
756 draw_arrow(cr, 75, 90, false);
757 }
758 if (edge & 2) {
759 draw_arrow(cr, 115, 10, true);
760 }
761 ANN_TEXT("Runt\n Fire if signal crosses 1st,\n but not 2nd threshold.");
762 break;
763 case TRG_DROPOUT:
764 cairo_set_source_rgba (cr, .0, 1.0, .0, .8);
765 cairo_move_to(cr, 0, 40.5);
766 cairo_line_to(cr, doc_w, 40.5);
767 cairo_stroke(cr);
768 cairo_move_to(cr, 0, 60.5);
769 cairo_line_to(cr, doc_w, 60.5);
770 cairo_stroke(cr);
771
772 cairo_set_source_rgba (cr, .0, 1.0, .0, .2);
773 cairo_set_line_width(cr, 4.0);
774 cairo_move_to(cr, 25.5, 40.5);
775 cairo_line_to(cr, 25.5, 60.5);
776 cairo_stroke(cr);
777 cairo_move_to(cr, 55.5, 40.5);
778 cairo_line_to(cr, 55.5, 60.5);
779 cairo_stroke(cr);
780
781 if (edge & 1) {
782 draw_cross(cr, 25, 50);
783 draw_timedelta(cr, 25, 80, 40, 0);
784 }
785 if (edge & 2) {
786 draw_cross(cr, 55, 50);
787 draw_timedelta(cr, 55, 90, 40, 0);
788 }
789 if (edge == 1) {
790 draw_arrow(cr, 65, 100, false);
791 } else {
792 draw_arrow(cr, 95, 10, true);
793 }
794
795 ANN_TEXT("Dropout\n Signal does not pass\n though a given range\n for at least 'Time 1'.");
796 break;
797 case TRG_DROPIN:
798 cairo_set_source_rgba (cr, .0, 1.0, .0, .8);
799 cairo_move_to(cr, 0, 65.5);
800 cairo_line_to(cr, doc_w, 65.5);
801 cairo_stroke(cr);
802 cairo_move_to(cr, 0, 25.5);
803 cairo_line_to(cr, doc_w, 25.5);
804 cairo_stroke(cr);
805
806 cairo_set_source_rgba (cr, .0, 1.0, .0, .2);
807 switch(edge) {
808 case 1:
809 cairo_rectangle(cr, 48, 25.5, 70, 40);
810 cairo_fill(cr);
811 draw_timedelta(cr, 47, 65, 40, 0);
812 draw_arrow(cr, 87, 90, false);
813 break;
814 case 2:
815 cairo_rectangle(cr, 8, 25.5, 15, 40);
816 cairo_fill(cr);
817 draw_timedelta(cr, 8, 65, 10, 0);
818 draw_arrow(cr, 18, 10, true);
819 break;
820 case 3:
821 cairo_rectangle(cr, 8, 25.5, 15, 40);
822 cairo_fill(cr);
823 cairo_rectangle(cr, 48, 25.5, 70, 40);
824 cairo_fill(cr);
825 draw_timedelta(cr, 47, 65, 10, 0);
826 draw_timedelta(cr, 8, 65, 10, 0);
827 draw_arrow(cr, 18, 10, true);
828 draw_arrow(cr, 57, 90, false);
829 break;
830 }
831
832 ANN_TEXT("Constrained\n Signal remains within a\n given range for at least\n 'Time 1'.");
833 break;
834 case TRG_RMS:
835 cairo_set_source_rgba (cr, .0, 0.5, 1.0, .8);
836 cairo_move_to(cr, 5.5, 50);
837 {
838 float ts_prev = 0;
839 for (uint32_t i = 1; i < 120; ++i) {
840 const float y0 = sinf(i * .2);
841 ts_prev += .02 * (y0 * y0 - ts_prev);
842 cairo_line_to(cr, i + 5.5, 50 - 40.0 * sqrtf(ts_prev));
843 }
844 }
845 cairo_stroke(cr);
846 ANN_TEXT("Calculate RMS\n time constant\n 'Time 1'");
847 break;
848 case TRG_LPF:
849 cairo_set_source_rgba (cr, .0, 0.5, 1.0, .8);
850 cairo_move_to(cr, 5.5, 50);
851 {
852 float ts_prev = 0;
853 float phase = 0;
854 for (uint32_t i = 1; i < 120; ++i) {
855 phase+=.05 + .4 * i / 120.0;
856 const float y0 = sinf(phase);
857 ts_prev += .1 * (y0 - ts_prev);
858 cairo_line_to(cr, i + 5.5, 50 + 50.0 * ts_prev);
859 }
860 }
861 cairo_stroke(cr);
862 ANN_TEXT("Low Pass Filter\n 1.0 / 'Time 1' Hz");
863 break;
864 case TRG_PASSTRHU:
865 ANN_TEXT("Signal Passthough");
866 break;
867 case TRG_LTC:
868 draw_arrow(cr, 95, 90, false);
869 ANN_TEXT("Linear Time Code\n LTC sync word.");
870 break;
871 default:
872 break;
873 }
874
875 cairo_restore(cr);
876 }
877
cb_show_doc(RobWidget * handle,void * d)878 static bool cb_show_doc (RobWidget* handle, void *d) {
879 MixTriUI* ui = (MixTriUI*) (d);
880 if (robtk_cbtn_get_active(ui->btn_show_doc)) {
881 robwidget_show(ui->drawing_area->rw, true);
882 } else {
883 robwidget_hide(ui->drawing_area->rw, true);
884 }
885 return TRUE;
886 }
887
888 /******************************************************************************
889 * UI callbacks
890 */
891
892 #define TRIGGERSENS(ED,L0,L1,T0,T1) \
893 robtk_select_set_sensitive(ui->sel_trig_edge, (ED)?true:false); \
894 robtk_spin_set_sensitive(ui->spb_trigger_lvl[0], (L0)?true:false); \
895 robtk_spin_set_sensitive(ui->spb_trigger_lvl[1], (L1)?true:false); \
896 robtk_spin_set_sensitive(ui->spb_trigger_tme[0], (T0)?true:false); \
897 robtk_spin_set_sensitive(ui->spb_trigger_tme[1], (T1)?true:false);
898
cb_set_trig_mode(RobWidget * handle,void * data)899 static bool cb_set_trig_mode (RobWidget* handle, void *data) {
900 MixTriUI* ui = (MixTriUI*) (data);
901 float mode = robtk_select_get_value(ui->sel_trig_mode);
902 switch ((int)mode) {
903 case TRG_PASSTRHU:
904 case TRG_LTC:
905 TRIGGERSENS(0,0,0,0,0);
906 break;
907 case TRG_PULSEWIDTH:
908 case TRG_PULSETRAIN:
909 TRIGGERSENS(1,1,0,1,1);
910 break;
911 case TRG_WINDOW_ENTER:
912 case TRG_WINDOW_LEAVE:
913 case TRG_RUNT:
914 TRIGGERSENS(1,1,1,0,0);
915 break;
916 case TRG_HYSTERESIS:
917 TRIGGERSENS(1,1,1,0,0);
918 break;
919 case TRG_DROPIN:
920 case TRG_DROPOUT:
921 TRIGGERSENS(1,1,1,1,0);
922 break;
923 case TRG_RMS:
924 case TRG_LPF:
925 TRIGGERSENS(0,0,0,1,0);
926 break;
927 case TRG_EDGE :
928 TRIGGERSENS(1,1,0,0,0);
929 break;
930 }
931 if (robtk_cbtn_get_active(ui->btn_show_doc)) {
932 robtk_darea_redraw(ui->drawing_area);
933 }
934 if (ui->disable_signals) return TRUE;
935 ui->write(ui->controller, MIXTRI_TRIG_MODE, sizeof(float), 0, (const void*) &mode);
936 return TRUE;
937 }
938
cb_set_trig_edge(RobWidget * handle,void * data)939 static bool cb_set_trig_edge (RobWidget* handle, void *data) {
940 MixTriUI* ui = (MixTriUI*) (data);
941 if (robtk_cbtn_get_active(ui->btn_show_doc)) {
942 robtk_darea_redraw(ui->drawing_area);
943 }
944 if (ui->disable_signals) return TRUE;
945 float mode = robtk_select_get_value(ui->sel_trig_edge);
946 ui->write(ui->controller, MIXTRI_TRIG_EDGE, sizeof(float), 0, (const void*) &mode);
947 return TRUE;
948 }
949
cb_set_trig_chn(RobWidget * handle,void * data)950 static bool cb_set_trig_chn (RobWidget* handle, void *data) {
951 MixTriUI* ui = (MixTriUI*) (data);
952 float chn = 0;
953 if (ui->disable_signals) return TRUE;
954 for (uint32_t i = 0; i < 4; ++i) {
955 if (robtk_rbtn_get_active(ui->btn_trig_src[i])) {
956 chn = i;
957 break;
958 }
959 }
960 ui->write(ui->controller, MIXTRI_TRIG_CHN, sizeof(float), 0, (const void*) &chn);
961 return TRUE;
962 }
963
cb_set_trig_values(RobWidget * handle,void * data)964 static bool cb_set_trig_values (RobWidget* handle, void *data) {
965 MixTriUI* ui = (MixTriUI*) (data);
966 float val0, val1;
967 if (ui->disable_signals) return TRUE;
968
969 val0 = robtk_spin_get_value(ui->spb_trigger_lvl[0]);
970 val1 = robtk_spin_get_value(ui->spb_trigger_lvl[1]);
971 if (val1 < val0) {
972 ui->disable_signals = true;
973 robtk_spin_set_value(ui->spb_trigger_lvl[1], val0);
974 val1 = val0;
975 }
976 ui->write(ui->controller, MIXTRI_TRIG_LVL1, sizeof(float), 0, (const void*) &val1);
977 ui->write(ui->controller, MIXTRI_TRIG_LVL0, sizeof(float), 0, (const void*) &val0);
978 val0 = robtk_spin_get_value(ui->spb_trigger_tme[0]);
979 val1 = robtk_spin_get_value(ui->spb_trigger_tme[1]);
980 if (val1 < val0) {
981 ui->disable_signals = true;
982 robtk_spin_set_value(ui->spb_trigger_tme[1], val0);
983 val1 = val0;
984 }
985 ui->write(ui->controller, MIXTRI_TRIG_TME1, sizeof(float), 0, (const void*) &val1);
986 ui->write(ui->controller, MIXTRI_TRIG_TME0, sizeof(float), 0, (const void*) &val0);
987 ui->disable_signals = false; // XXX
988 return TRUE;
989 }
990
cb_set_fm(RobWidget * handle,void * data)991 static bool cb_set_fm (RobWidget* handle, void *data) {
992 MixTriUI* ui = (MixTriUI*) (data);
993 if (ui->disable_signals) return TRUE;
994 for (uint32_t i = 0; i < 4; ++i) {
995 int v = 0; float val;
996 if (robtk_cbtn_get_active(ui->btn_mute_in[i])) v|=1;
997 if (robtk_cbtn_get_active(ui->btn_hpfilt_in[i])) v|=2;
998 val = v;
999 ui->write(ui->controller, MIXTRI_MOD_I_0 + i, sizeof(float), 0, (const void*) &val);
1000 }
1001 return TRUE;
1002 }
1003
cb_set_in(RobWidget * handle,void * data)1004 static bool cb_set_in (RobWidget* handle, void *data) {
1005 MixTriUI* ui = (MixTriUI*) (data);
1006 if (ui->disable_signals) return TRUE;
1007 for (uint32_t i = 0; i < 4; ++i) {
1008 float val = robtk_dial_get_value(ui->dial_in[i]);
1009 ui->write(ui->controller, MIXTRI_GAIN_I_0 + i, sizeof(float), 0, (const void*) &val);
1010 }
1011 return TRUE;
1012 }
1013
cb_set_mix(RobWidget * handle,void * data)1014 static bool cb_set_mix (RobWidget* handle, void *data) {
1015 MixTriUI* ui = (MixTriUI*) (data);
1016 if (ui->disable_signals) return TRUE;
1017 for (uint32_t i = 0; i < 12; ++i) {
1018 float val = pow(10, .05 * robtk_dial_get_value(ui->dial_mix[i]));
1019 switch(robtk_dial_get_state(ui->dial_mix[i])) {
1020 case 1:
1021 val = 0;
1022 break;
1023 case 2:
1024 val *= -1;
1025 break;
1026 default:
1027 break;
1028 }
1029 ui->write(ui->controller, MIXTRI_MIX_0_0 + i, sizeof(float), 0, (const void*) &val);
1030 }
1031 return TRUE;
1032 }
1033
cb_set_delay(RobWidget * handle,void * data)1034 static bool cb_set_delay (RobWidget* handle, void *data) {
1035 MixTriUI* ui = (MixTriUI*) (data);
1036 if (ui->disable_signals) return TRUE;
1037 for (uint32_t i = 0; i < 4; ++i) {
1038 float val = robtk_spin_get_value(ui->spb_delay_in[i]);
1039 ui->write(ui->controller, MIXTRI_DLY_I_0 + i, sizeof(float), 0, (const void*) &val);
1040 }
1041 for (uint32_t i = 0; i < 3; ++i) {
1042 float val = robtk_spin_get_value(ui->spb_delay_out[i]);
1043 ui->write(ui->controller, MIXTRI_DLY_O_0 + i, sizeof(float), 0, (const void*) &val);
1044 }
1045 return TRUE;
1046 }
1047
1048 /******************************************************************************
1049 * RobWidget
1050 */
1051
toplevel_mixtri(MixTriUI * ui)1052 static RobWidget *toplevel_mixtri(MixTriUI* ui)
1053 {
1054 ui->hbox = rob_hbox_new(FALSE, 2);
1055
1056 ui->font[0] = pango_font_description_from_string("Mono 10px");
1057 ui->font[1] = pango_font_description_from_string("Sans 9px");
1058 create_faceplate(ui);
1059
1060 ui->label[0] = robtk_lbl_new("Delay [spl]");
1061 ui->label[1] = robtk_lbl_new("Output Delay [spl] \u2192 ");
1062 ui->label[2] = robtk_lbl_new("Mixer Matrix [amp]");
1063 ui->label[3] = robtk_lbl_new("Channel mod.");
1064 ui->label[4] = robtk_lbl_new("Out Trigger");
1065 ui->label[5] = robtk_lbl_new("Gain");
1066 ui->label[6] = robtk_lbl_new("Trigger");
1067 // TODO use robtk_info()
1068 #ifdef MIXTRILV2
1069 ui->label[7] = robtk_lbl_new("x42 MixTri LV2 " VERSION);
1070 #else
1071 ui->label[7] = robtk_lbl_new("");
1072 #endif
1073 ui->label[8] = robtk_lbl_new("Trig. Settings");
1074
1075 robtk_lbl_set_alignment(ui->label[0], 0.5, 0.5);
1076 robtk_lbl_set_alignment(ui->label[1], 1.0, 0.25);
1077 robtk_lbl_set_alignment(ui->label[2], 0.5, 0.5);
1078 robtk_lbl_set_alignment(ui->label[3], 0.5, 0.5);
1079 robtk_lbl_set_alignment(ui->label[4], 0.5, 0.5);
1080 robtk_lbl_set_alignment(ui->label[5], 0.5, 0.5);
1081 robtk_lbl_set_alignment(ui->label[6], 0.5, 0.5);
1082 robtk_lbl_set_alignment(ui->label[7], 0.0, 0.5);
1083 robtk_lbl_set_alignment(ui->label[8], 0.5, 0.5);
1084
1085 robtk_lbl_set_color(ui->label[7], .6, .6, .6, 1.0);
1086
1087 ui->ctable = rob_table_new(/*rows*/7, /*cols*/ 9, FALSE);
1088 ui->ctable->expose_event = box_expose_event;
1089
1090 rob_table_attach(ui->ctable, robtk_lbl_widget(ui->label[0]),
1091 1, 2, 0, 1, 0, 0, RTK_EXANDF, RTK_SHRINK);
1092 rob_table_attach(ui->ctable, robtk_lbl_widget(ui->label[1]),
1093 2, 5, 5, 6, 0, 0, RTK_EXANDF, RTK_SHRINK);
1094 rob_table_attach(ui->ctable, robtk_lbl_widget(ui->label[2]),
1095 5, 8, 0, 1, 0, 0, RTK_EXANDF, RTK_SHRINK);
1096 rob_table_attach(ui->ctable, robtk_lbl_widget(ui->label[3]),
1097 2, 4, 0, 1, 0, 0, RTK_EXANDF, RTK_SHRINK);
1098 rob_table_attach(ui->ctable, robtk_lbl_widget(ui->label[4]),
1099 8, 9, 6, 7, 0, 0, RTK_EXANDF, RTK_SHRINK);
1100 rob_table_attach(ui->ctable, robtk_lbl_widget(ui->label[5]),
1101 4, 5, 0, 1, 0, 0, RTK_EXANDF, RTK_SHRINK);
1102 rob_table_attach(ui->ctable, robtk_lbl_widget(ui->label[6]),
1103 8, 9, 0, 1, 0, 0, RTK_EXANDF, RTK_SHRINK);
1104 rob_table_attach(ui->ctable, robtk_lbl_widget(ui->label[7]),
1105 0, 3, 6, 7, 0, 0, RTK_EXANDF, RTK_SHRINK);
1106 rob_table_attach(ui->ctable, robtk_lbl_widget(ui->label[8]),
1107 10, 12, 0, 1, 0, 0, RTK_EXANDF, RTK_SHRINK);
1108
1109
1110 for (uint32_t i = 0; i < 4; ++i) {
1111 ui->dial_in[i] = robtk_dial_new_with_size(-60.0, 20.0, .01,
1112 60, MIX_HEIGHT, 30.5, MIX_CY, MIX_RADIUS);
1113 robtk_dial_set_value(ui->dial_in[i], 0);
1114 robtk_dial_set_surface(ui->dial_in[i],ui->routeI);
1115 robtk_dial_set_default(ui->dial_in[i], 0);
1116 robtk_dial_set_callback(ui->dial_in[i], cb_set_in, ui);
1117 robtk_dial_annotation_callback(ui->dial_in[i], dial_annotation_db, ui);
1118 rob_table_attach(ui->ctable, robtk_dial_widget(ui->dial_in[i]),
1119 4, 5, i+1, i+2, 0, 0, RTK_EXANDF, RTK_SHRINK);
1120 }
1121
1122 for (uint32_t i = 0; i < 12; ++i) {
1123 ui->dial_mix[i] = robtk_dial_new_with_size(-20.0, 20.0, .01,
1124 MIX_WIDTH, MIX_HEIGHT, MIX_CX, MIX_CY, MIX_RADIUS);
1125 const int g = ((i%3) == (i/3)) ? 0 : 1;
1126 robtk_dial_enable_states(ui->dial_mix[i], 2);
1127 robtk_dial_set_state_color(ui->dial_mix[i], 1, .15, .15, .15, 1.0);
1128 robtk_dial_set_state_color(ui->dial_mix[i], 2, 1.0, .0, .0, .3);
1129 robtk_dial_set_default(ui->dial_mix[i], 0);
1130 robtk_dial_set_default_state(ui->dial_mix[i], g);
1131 robtk_dial_set_state(ui->dial_mix[i], g);
1132 robtk_dial_set_value(ui->dial_mix[i], 0);
1133 robtk_dial_set_callback(ui->dial_mix[i], cb_set_mix, ui);
1134 robtk_dial_annotation_callback(ui->dial_mix[i], dial_annotation_val, ui);
1135 rob_table_attach(ui->ctable, robtk_dial_widget(ui->dial_mix[i]),
1136 (i%3)+5, (i%3)+6, (i/3)+1, (i/3)+2,
1137 0, 0, RTK_EXANDF, RTK_SHRINK);
1138 }
1139
1140 for (uint32_t i = 0; i < 3; ++i) {
1141 robtk_dial_set_surface(ui->dial_mix[i], (i%3)==2 ? ui->routeC : ui->routeT);
1142 }
1143 for (uint32_t i = 3; i < 12; ++i) {
1144 robtk_dial_set_surface(ui->dial_mix[i], (i%3)==2 ? ui->routeE : ui->routeM);
1145 }
1146
1147 for (uint32_t i = 0; i < 4; ++i) {
1148 char tmp[16];
1149 snprintf(tmp, 16, "In %d ", i+1);
1150 ui->lbl_in[i] = robtk_lbl_new(tmp);
1151 robtk_lbl_set_alignment(ui->lbl_in[i], 0.0, 0.3);
1152 robtk_lbl_set_min_geometry(ui->lbl_in[i], 32, 0);
1153
1154 ui->btn_mute_in[i] = robtk_cbtn_new("Mute", GBT_LED_LEFT, false);
1155 ui->btn_hpfilt_in[i] = robtk_cbtn_new("HPF", GBT_LED_LEFT, false);
1156 robtk_cbtn_set_alignment(ui->btn_mute_in[i], .5, 0.25);
1157 robtk_cbtn_set_alignment(ui->btn_hpfilt_in[i], .5, 0.25);
1158 robtk_cbtn_set_color_on(ui->btn_hpfilt_in[i], .1, .2, .9);
1159 robtk_cbtn_set_color_off(ui->btn_hpfilt_in[i], .1, .1, .3);
1160 robtk_cbtn_set_callback(ui->btn_mute_in[i], cb_set_fm, ui);
1161 robtk_cbtn_set_callback(ui->btn_hpfilt_in[i], cb_set_fm, ui);
1162 rob_table_attach(ui->ctable, robtk_lbl_widget(ui->lbl_in[i]),
1163 0, 1, i+1, i+2, 0, 0, RTK_EXANDF, RTK_EXANDF);
1164 rob_table_attach(ui->ctable, robtk_cbtn_widget(ui->btn_mute_in[i]),
1165 2, 3, i+1, i+2, 0, 0, RTK_SHRINK, RTK_SHRINK);
1166 rob_table_attach(ui->ctable, robtk_cbtn_widget(ui->btn_hpfilt_in[i]),
1167 3, 4, i+1, i+2, 0, 0, RTK_SHRINK, RTK_SHRINK);
1168
1169 ui->spb_delay_in[i] = robtk_spin_new(0, MAXDELAY-1, 1);
1170 ui->spb_delay_in[i]->dial->displaymode = 3;
1171 robtk_lbl_set_text(ui->spb_delay_in[i]->lbl_r, "000000");
1172 robtk_spin_set_default(ui->spb_delay_in[i], 0);
1173 robtk_spin_set_value(ui->spb_delay_in[i], 0);
1174 robtk_spin_set_callback(ui->spb_delay_in[i], cb_set_delay, ui);
1175 robtk_spin_label_width(ui->spb_delay_in[i], -1, MIX_WIDTH - GSP_WIDTH - 8);
1176
1177 robtk_dial_set_surface(ui->spb_delay_in[i]->dial,ui->delayI);
1178 robtk_lbl_set_alignment(ui->spb_delay_in[i]->lbl_r, 0, 0.3);
1179 robtk_dial_set_alignment(ui->spb_delay_in[i]->dial, .5, 1.0);
1180 ui->spb_delay_in[i]->rw->yalign = .45;
1181
1182 rob_table_attach(ui->ctable, robtk_spin_widget(ui->spb_delay_in[i]),
1183 1, 2, i+1, i+2, 0, 0, RTK_EXANDF, RTK_SHRINK);
1184 }
1185
1186 for (uint32_t i = 0; i < 3; ++i) {
1187 char tmp[16];
1188 snprintf(tmp, 16, "Out %d", i+1);
1189 ui->lbl_out[i] = robtk_lbl_new(tmp);
1190 robtk_lbl_set_alignment(ui->lbl_out[i], 0.5, 0.5);
1191 rob_table_attach(ui->ctable, robtk_lbl_widget(ui->lbl_out[i]),
1192 5+i, 6+i, 6, 7, 0, 0, RTK_EXANDF, RTK_SHRINK);
1193
1194 ui->spb_delay_out[i] = robtk_spin_new(0, MAXDELAY-1, 1);
1195 ui->spb_delay_out[i]->dial->displaymode = 3;
1196 robtk_spin_set_callback(ui->spb_delay_out[i], cb_set_delay, ui);
1197 robtk_spin_set_default(ui->spb_delay_out[i], 0);
1198 robtk_spin_set_value(ui->spb_delay_out[i], 0);
1199 robtk_dial_set_surface(ui->spb_delay_out[i]->dial,ui->delayO);
1200 robtk_lbl_set_alignment(ui->spb_delay_out[i]->lbl_r, 0, 0.3);
1201 robtk_spin_label_width(ui->spb_delay_out[i], -1, MIX_WIDTH - GSP_WIDTH - 8);
1202 rob_table_attach(ui->ctable, robtk_spin_widget(ui->spb_delay_out[i]),
1203 i+5, i+6, 5, 6, 0, 0, RTK_EXANDF, RTK_SHRINK);
1204 }
1205
1206 ui->sel_trig_mode = robtk_select_new();
1207 robtk_select_set_alignment(ui->sel_trig_mode, .5, 0);
1208 ui->sel_trig_mode->t_width = MIX_WIDTH - 36;
1209 robtk_select_add_item(ui->sel_trig_mode, TRG_PASSTRHU, "-");
1210 robtk_select_add_item(ui->sel_trig_mode, TRG_EDGE, "Edge");
1211 robtk_select_add_item(ui->sel_trig_mode, TRG_WINDOW_ENTER, "Enter Window");
1212 robtk_select_add_item(ui->sel_trig_mode, TRG_WINDOW_LEAVE, "Leave Window");
1213 robtk_select_add_item(ui->sel_trig_mode, TRG_HYSTERESIS, "Hysteresis");
1214 robtk_select_add_item(ui->sel_trig_mode, TRG_DROPIN, "Constrained");
1215 robtk_select_add_item(ui->sel_trig_mode, TRG_DROPOUT, "Dropout");
1216 robtk_select_add_item(ui->sel_trig_mode, TRG_PULSEWIDTH, "Pulse Width");
1217 robtk_select_add_item(ui->sel_trig_mode, TRG_PULSETRAIN, "Pulse Train");
1218 robtk_select_add_item(ui->sel_trig_mode, TRG_RUNT, "Runt");
1219 robtk_select_add_item(ui->sel_trig_mode, TRG_LTC, "LTC");
1220 robtk_select_add_item(ui->sel_trig_mode, TRG_RMS, "RMS");
1221 robtk_select_add_item(ui->sel_trig_mode, TRG_LPF, "LPF");
1222 robtk_select_set_callback(ui->sel_trig_mode, cb_set_trig_mode, ui);
1223
1224 rob_table_attach(ui->ctable, robtk_select_widget(ui->sel_trig_mode),
1225 8, 9, 5, 6, 0, 0, RTK_SHRINK, RTK_SHRINK);
1226
1227 ui->btn_trig_src[0] = robtk_rbtn_new("", NULL);
1228 ui->btn_trig_src[1] = robtk_rbtn_new("", robtk_rbtn_group(ui->btn_trig_src[0]));
1229 ui->btn_trig_src[2] = robtk_rbtn_new("", robtk_rbtn_group(ui->btn_trig_src[0]));
1230 ui->btn_trig_src[3] = robtk_rbtn_new("", robtk_rbtn_group(ui->btn_trig_src[0]));
1231
1232 robtk_rbtn_set_active(ui->btn_trig_src[3], true);
1233
1234 for (uint32_t i = 0; i < 4; ++i) {
1235 ui->btn_trig_src[i]->cbtn->flat_button = FALSE;
1236 robtk_rbtn_set_callback(ui->btn_trig_src[i], cb_set_trig_chn, ui);
1237 robtk_rbtn_set_alignment(ui->btn_trig_src[i], .5, 0.25);
1238 rob_table_attach(ui->ctable, robtk_rbtn_widget(ui->btn_trig_src[i]),
1239 8, 9, i+1, i+2, 0, 0, RTK_EXPAND, RTK_SHRINK);
1240 }
1241
1242 #define TBLADD(WIDGET, C0, C1, R) \
1243 rob_table_attach(ui->ctable, WIDGET, \
1244 (C0), (C1), (R), (R)+1, 0, 0, RTK_EXANDF, RTK_SHRINK)
1245
1246 /* trigger settings */
1247 ui->lbl_trig[0] = robtk_lbl_new("Level 1: ");
1248 ui->lbl_trig[1] = robtk_lbl_new("Level 2: ");
1249 ui->lbl_trig[2] = robtk_lbl_new("Time 1: ");
1250 ui->lbl_trig[3] = robtk_lbl_new("Time 2: ");
1251
1252 for (uint32_t i = 0; i < 4; ++i) {
1253 robtk_lbl_set_alignment(ui->lbl_trig[i], 1.0, 0.5);
1254 TBLADD(robtk_lbl_widget(ui->lbl_trig[i]), 10, 11, 2+i);
1255 }
1256
1257 ui->sel_trig_edge = robtk_select_new();
1258 robtk_select_add_item(ui->sel_trig_edge, 1, "rising edge");
1259 robtk_select_add_item(ui->sel_trig_edge, 2, "falling edge");
1260 robtk_select_add_item(ui->sel_trig_edge, 3, "any edge");
1261 robtk_select_set_callback(ui->sel_trig_edge, cb_set_trig_edge, ui);
1262 TBLADD(robtk_select_widget(ui->sel_trig_edge), 10, 12, 1);
1263
1264 for (uint32_t i = 0; i < 2; ++i) {
1265 ui->spb_trigger_lvl[i] = robtk_spin_new(-1.f, 1.f, .01);
1266 robtk_spin_set_default(ui->spb_trigger_lvl[i], 0);
1267 robtk_spin_set_value(ui->spb_trigger_lvl[i], 0);
1268 robtk_spin_label_width(ui->spb_trigger_lvl[i], -1, 40); // XXX
1269 robtk_spin_set_alignment(ui->spb_trigger_lvl[i], 0, .5);
1270 robtk_spin_set_callback(ui->spb_trigger_lvl[i], cb_set_trig_values, ui);
1271 TBLADD(robtk_spin_widget(ui->spb_trigger_lvl[i]), 11, 12, 2+i);
1272
1273 ui->spb_trigger_tme[i] = robtk_spin_new(0, MAXDELAY-1, 1);
1274 ui->spb_trigger_tme[i]->dial->displaymode = 3;
1275 robtk_spin_set_default(ui->spb_trigger_tme[i], 0);
1276 robtk_spin_set_value(ui->spb_trigger_tme[i], 0);
1277 robtk_spin_label_width(ui->spb_trigger_tme[i], -1, 50); // XXX
1278 robtk_spin_set_alignment(ui->spb_trigger_tme[i], 0, .5);
1279 robtk_spin_set_callback(ui->spb_trigger_tme[i], cb_set_trig_values, ui);
1280 TBLADD(robtk_spin_widget(ui->spb_trigger_tme[i]), 11, 12, 4+i);
1281 }
1282
1283 ui->btn_show_doc = robtk_cbtn_new("Show Doc", GBT_LED_LEFT, true);
1284 robtk_cbtn_set_alignment(ui->btn_show_doc, 0, 0.5);
1285 robtk_cbtn_set_color_on(ui->btn_show_doc, .8, .8, .9);
1286 robtk_cbtn_set_color_off(ui->btn_show_doc, .1, .1, .3);
1287 robtk_cbtn_set_alignment(ui->btn_show_doc, .5, .5);
1288 robtk_cbtn_set_active(ui->btn_show_doc, false);
1289 robtk_cbtn_set_callback(ui->btn_show_doc, cb_show_doc, ui);
1290 rob_table_attach(ui->ctable, robtk_cbtn_widget(ui->btn_show_doc),
1291 10, 12, 6, 7, 0, 0, RTK_EXANDF, RTK_SHRINK);
1292
1293 ui->drawing_area = robtk_darea_new(150, 180, draw_trigger_doc, ui);
1294 robwidget_hide(ui->drawing_area->rw, false);
1295 rob_table_attach(ui->ctable, robtk_darea_widget(ui->drawing_area),
1296 12, 13, 1, 6, 0, 0, RTK_EXANDF, RTK_SHRINK);
1297
1298 robtk_select_set_active_item(ui->sel_trig_edge, 0);
1299 cb_set_trig_mode(NULL, ui);
1300
1301 rob_hbox_child_pack(ui->hbox, ui->ctable, FALSE, FALSE);
1302 return ui->hbox;
1303 #undef TBLADD
1304 }
1305
1306 /******************************************************************************
1307 * LV2
1308 */
1309
1310 static void
cleanup_mixtri(LV2UI_Handle handle)1311 cleanup_mixtri(LV2UI_Handle handle)
1312 {
1313 MixTriUI* ui = (MixTriUI*)handle;
1314
1315 for (uint32_t i = 0; i < 12; ++i) {
1316 robtk_dial_destroy(ui->dial_mix[i]);
1317 }
1318 for (uint32_t i = 0; i < 4; ++i) {
1319 robtk_dial_destroy(ui->dial_in[i]);
1320 robtk_spin_destroy(ui->spb_delay_in[i]);
1321 robtk_cbtn_destroy(ui->btn_hpfilt_in[i]);
1322 robtk_cbtn_destroy(ui->btn_mute_in[i]);
1323 robtk_lbl_destroy(ui->lbl_in[i]);
1324 robtk_rbtn_destroy(ui->btn_trig_src[i]);
1325 robtk_lbl_destroy(ui->lbl_trig[i]);
1326 }
1327 for (uint32_t i = 0; i < 3; ++i) {
1328 robtk_spin_destroy(ui->spb_delay_out[i]);
1329 robtk_lbl_destroy(ui->lbl_out[i]);
1330 }
1331 for (uint32_t i = 0; i < 9; ++i) {
1332 robtk_lbl_destroy(ui->label[i]);
1333 }
1334 for (uint32_t i = 0; i < 2; ++i) {
1335 robtk_spin_destroy(ui->spb_trigger_lvl[i]);
1336 robtk_spin_destroy(ui->spb_trigger_tme[i]);
1337 }
1338 robtk_select_destroy(ui->sel_trig_mode);
1339 robtk_select_destroy(ui->sel_trig_edge);
1340 cairo_surface_destroy(ui->routeT);
1341 cairo_surface_destroy(ui->routeC);
1342 cairo_surface_destroy(ui->routeE);
1343 cairo_surface_destroy(ui->routeM);
1344 cairo_surface_destroy(ui->routeI);
1345 cairo_surface_destroy(ui->delayI);
1346 cairo_surface_destroy(ui->delayO);
1347 pango_font_description_free(ui->font[0]);
1348 pango_font_description_free(ui->font[1]);
1349
1350 robtk_cbtn_destroy(ui->btn_show_doc);
1351 robtk_darea_destroy(ui->drawing_area);
1352
1353 rob_box_destroy(ui->ctable);
1354 rob_box_destroy(ui->hbox);
1355
1356 free(ui);
1357 }
1358
1359 static void
port_event_mixtri(LV2UI_Handle handle,uint32_t port,uint32_t buffer_size,uint32_t format,const void * buffer)1360 port_event_mixtri(
1361 LV2UI_Handle handle,
1362 uint32_t port,
1363 uint32_t buffer_size,
1364 uint32_t format,
1365 const void* buffer)
1366 {
1367 MixTriUI* ui = (MixTriUI*)handle;
1368
1369 if (format != 0) return;
1370 const float v = *(float *)buffer;
1371 const int vi = *(float *)buffer;
1372 if (port >= MIXTRI_MIX_0_0 && port <= MIXTRI_MIX_3_2) {
1373 const int d = port - MIXTRI_MIX_0_0;
1374 ui->disable_signals = true;
1375 if (v == 0) {
1376 robtk_dial_set_state(ui->dial_mix[d], 1);
1377 } else if (v < 0) {
1378 robtk_dial_set_state(ui->dial_mix[d], 2);
1379 robtk_dial_set_value(ui->dial_mix[d], 20 * log10f(-v));
1380 } else {
1381 robtk_dial_set_state(ui->dial_mix[d], 0);
1382 robtk_dial_set_value(ui->dial_mix[d], 20 * log10f(v));
1383 }
1384 ui->disable_signals = false;
1385 }
1386 else if (port >= MIXTRI_DLY_I_0 && port <= MIXTRI_DLY_I_3) {
1387 const int d = port - MIXTRI_DLY_I_0;
1388 ui->disable_signals = true;
1389 robtk_spin_set_value(ui->spb_delay_in[d], v);
1390 ui->disable_signals = false;
1391 }
1392 else if (port >= MIXTRI_DLY_O_0 && port <= MIXTRI_DLY_O_2) {
1393 const int d = port - MIXTRI_DLY_O_0;
1394 ui->disable_signals = true;
1395 robtk_spin_set_value(ui->spb_delay_out[d], v);
1396 ui->disable_signals = false;
1397 }
1398 else if (port >= MIXTRI_TRIG_CHN && port <= MIXTRI_TRIG_TME1) {
1399 ui->disable_signals = true;
1400 switch(port) {
1401 case MIXTRI_TRIG_CHN:
1402 if (vi >=0 && vi < 4) robtk_rbtn_set_active(ui->btn_trig_src[vi], true);
1403 break;
1404 case MIXTRI_TRIG_MODE:
1405 robtk_select_set_value(ui->sel_trig_mode, vi);
1406 break;
1407 case MIXTRI_TRIG_EDGE:
1408 robtk_select_set_value(ui->sel_trig_edge, vi);
1409 break;
1410 case MIXTRI_TRIG_LVL0:
1411 robtk_spin_set_value(ui->spb_trigger_lvl[0], v);
1412 break;
1413 case MIXTRI_TRIG_LVL1:
1414 robtk_spin_set_value(ui->spb_trigger_lvl[1], v);
1415 break;
1416 case MIXTRI_TRIG_TME0:
1417 robtk_spin_set_value(ui->spb_trigger_tme[0], v);
1418 break;
1419 case MIXTRI_TRIG_TME1:
1420 robtk_spin_set_value(ui->spb_trigger_tme[1], v);
1421 break;
1422 }
1423 ui->disable_signals = false;
1424 }
1425 }
1426
1427 #ifdef MIXTRILV2
1428
1429 #define RTK_URI MIXTRI_URI
1430 #define RTK_GUI "ui"
1431
1432 /**
1433 * standalone robtk GUI
1434 */
ui_disable(LV2UI_Handle handle)1435 static void ui_disable(LV2UI_Handle handle) { }
ui_enable(LV2UI_Handle handle)1436 static void ui_enable(LV2UI_Handle handle) { }
1437
1438 static LV2UI_Handle
instantiate(void * const ui_toplevel,const LV2UI_Descriptor * descriptor,const char * plugin_uri,const char * bundle_path,LV2UI_Write_Function write_function,LV2UI_Controller controller,RobWidget ** widget,const LV2_Feature * const * features)1439 instantiate(
1440 void* const ui_toplevel,
1441 const LV2UI_Descriptor* descriptor,
1442 const char* plugin_uri,
1443 const char* bundle_path,
1444 LV2UI_Write_Function write_function,
1445 LV2UI_Controller controller,
1446 RobWidget** widget,
1447 const LV2_Feature* const* features)
1448 {
1449 MixTriUI* ui = (MixTriUI*)calloc(1, sizeof(MixTriUI));
1450
1451 if (!ui) {
1452 fprintf(stderr, "MixTri.lv2 UI: out of memory\n");
1453 return NULL;
1454 }
1455
1456 *widget = NULL;
1457
1458 /* initialize private data structure */
1459 ui->write = write_function;
1460 ui->controller = controller;
1461
1462 *widget = toplevel_mixtri(ui);
1463 robwidget_make_toplevel(ui->hbox, ui_toplevel);
1464 ROBWIDGET_SETNAME(ui->hbox, "mixtri");
1465
1466 return ui;
1467 }
1468
1469 static enum LVGLResize
plugin_scale_mode(LV2UI_Handle handle)1470 plugin_scale_mode(LV2UI_Handle handle)
1471 {
1472 return LVGL_LAYOUT_TO_FIT;
1473 }
1474
1475 static void
cleanup(LV2UI_Handle handle)1476 cleanup(LV2UI_Handle handle)
1477 {
1478 cleanup_mixtri(handle);
1479 }
1480
1481 static void
port_event(LV2UI_Handle handle,uint32_t port,uint32_t buffer_size,uint32_t format,const void * buffer)1482 port_event(
1483 LV2UI_Handle handle,
1484 uint32_t port,
1485 uint32_t buffer_size,
1486 uint32_t format,
1487 const void* buffer)
1488 {
1489 port_event_mixtri(handle, port, buffer_size, format, buffer);
1490 }
1491
1492 static const void*
extension_data(const char * uri)1493 extension_data(const char* uri)
1494 {
1495 return NULL;
1496 }
1497 #endif
1498 /* vi:set ts=2 sts=2 sw=2: */
1499