1 /*
2 Copyright (C) 2011 Tom Szilagyi
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <math.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include <errno.h>
26
27 #include <gtk/gtk.h>
28
29 #include <lv2.h>
30 #include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
31 #include "lv2/lv2plug.in/ns/ext/instance-access/instance-access.h"
32
33 #include "ir.h"
34 #include "ir_utils.h"
35 #include "ir_meter.h"
36 #include "ir_modeind.h"
37 #include "ir_wavedisplay.h"
38
39 #define IR_UI_URI "http://tomszilagyi.github.io/plugins/lv2/ir/gui"
40
41 #define PAD 2
42
43 #define ADJ_PREDELAY 0
44 #define ADJ_ATTACK 1
45 #define ADJ_ATTACKTIME 2
46 #define ADJ_ENVELOPE 3
47 #define ADJ_LENGTH 4
48 #define ADJ_STRETCH 5
49 #define ADJ_STEREO_IN 6
50 #define ADJ_STEREO_IR 7
51 #define ADJ_DRY_GAIN 8
52 #define ADJ_WET_GAIN 9
53 #define N_ADJUSTMENTS 10
54
55 typedef struct {
56 int id;
57 gdouble def;
58 gdouble min;
59 gdouble max;
60 int log;
61 } adj_descr_t;
62
63 #define LIN 0
64 #define LOG 1
65 #define INVLOG 2
66
67 static adj_descr_t adj_descr_table[N_ADJUSTMENTS] = {
68 {ADJ_PREDELAY, 0.0, 0.0, 2000.0, INVLOG},
69 {ADJ_ATTACK, 0.0, 0.0, 100.0, LIN},
70 {ADJ_ATTACKTIME, 0.0, 0.0, 300.0, LIN},
71 {ADJ_ENVELOPE, 100.0, 0.0, 100.0, LIN},
72 {ADJ_LENGTH, 100.0, 0.0, 100.0, LIN},
73 {ADJ_STRETCH, 100.0, 50.0, 150.0, LIN},
74 {ADJ_STEREO_IN, 100.0, 0.0, 150.0, LIN},
75 {ADJ_STEREO_IR, 100.0, 0.0, 150.0, LIN},
76 {ADJ_DRY_GAIN, 0.0, -90.0, 6.0, LOG},
77 {ADJ_WET_GAIN, -6.0, -90.0, 6.0, LOG},
78 };
79
80 struct control {
81 LV2UI_Controller controller;
82 LV2UI_Write_Function write_function;
83
84 IR * ir;
85
86 float port_buffer[IR_N_PORTS];
87 GSList * port_event_q;
88 GtkWidget * vbox_top;
89 GtkWidget * hbox_waitplugin;
90
91 float predelay;
92 float attack;
93 float attacktime;
94 float envelope;
95 float length;
96 float stretch;
97 float stereo_ir;
98
99 GtkAdjustment * adj_predelay;
100 GtkAdjustment * adj_attack;
101 GtkAdjustment * adj_attacktime;
102 GtkAdjustment * adj_envelope;
103 GtkAdjustment * adj_length;
104 GtkAdjustment * adj_stretch;
105 GtkAdjustment * adj_stereo_in;
106 GtkAdjustment * adj_stereo_ir;
107 GtkAdjustment * adj_dry_gain;
108 GtkAdjustment * adj_wet_gain;
109
110 GtkWidget * scale_predelay;
111 GtkWidget * scale_attack;
112 GtkWidget * scale_attacktime;
113 GtkWidget * scale_envelope;
114 GtkWidget * scale_length;
115 GtkWidget * scale_stretch;
116 GtkWidget * scale_stereo_in;
117 GtkWidget * scale_stereo_ir;
118
119 GtkWidget * label_predelay;
120 GtkWidget * label_attack;
121 GtkWidget * label_envelope;
122 GtkWidget * label_length;
123 GtkWidget * label_stretch;
124 GtkWidget * label_stereo;
125 GtkWidget * label_dry_gain;
126 GtkWidget * label_wet_gain;
127
128 GtkWidget * toggle_reverse;
129 gulong toggle_reverse_cbid;
130 GtkWidget * toggle_agc_sw;
131 GtkWidget * toggle_dry_sw;
132 GtkWidget * toggle_wet_sw;
133
134 GtkWidget * meter_L_dry;
135 GtkWidget * meter_R_dry;
136 GtkWidget * meter_L_wet;
137 GtkWidget * meter_R_wet;
138
139 GtkWidget * chan_toggle[4];
140 gulong chan_toggle_cbid[4];
141 GtkWidget * log_toggle;
142 gulong log_toggle_cbid;
143 GtkWidget * wave_display;
144 GtkWidget * wave_annot_label;
145 int disp_chan;
146 GtkWidget * mode_ind;
147
148 GtkTreeModel * model_bookmarks; /* GtkTreeModelSortable on ir->store_bookmarks */
149 GtkListStore * store_files;
150 GtkWidget * tree_bookmarks;
151 GtkWidget * tree_files;
152 int bookmarks_realized;
153 int files_realized;
154
155 gulong files_sel_cbid;
156 gulong bookmarks_sel_cbid;
157 guint timeout_tag;
158 guint gui_load_timeout_tag;
159 guint reinit_timeout_tag;
160 guint waitplugin_timeout_tag;
161
162 int interrupt_threads;
163 GThread * gui_load_thread;
164 GThread * reinit_thread;
165
166 int key_pressed;
167 };
168
169 typedef struct {
170 uint32_t port_index;
171 float value;
172 } port_event_t;
173
174 static void reset_values(struct control * cp);
175
176 /* adjustments with linear or logarithmic scale */
177 #define LOG_SCALE_MIN 1.0
178 #define LOG_SCALE_MAX 2.0
179 #define INVLOG_SCALE_MIN 10.0
180 #define INVLOG_SCALE_MAX 100.0
181
182 static void adjustment_changed_cb(GtkAdjustment * adj, gpointer data);
183
184 /* return 1 if value has actually changed */
set_port_value(struct control * cp,int port_index,float value)185 static int set_port_value(struct control * cp, int port_index, float value) {
186 if (fabs(cp->port_buffer[port_index] - value) < 0.000001) {
187 return 0;
188 }
189 cp->port_buffer[port_index] = value;
190 return 1;
191 }
192
send_port_value_to_host(struct control * cp,int port_index,float value)193 static void send_port_value_to_host(struct control * cp, int port_index, float value) {
194 if (set_port_value(cp, port_index, value)) {
195 cp->write_function(cp->controller, port_index, sizeof(float),
196 0 /* default format */, &value);
197 }
198 }
199
get_adj_index(struct control * cp,GtkAdjustment * adj)200 static int get_adj_index(struct control * cp, GtkAdjustment * adj) {
201
202 if (adj == cp->adj_predelay) {
203 return ADJ_PREDELAY;
204 } else if (adj == cp->adj_attack) {
205 return ADJ_ATTACK;
206 } else if (adj == cp->adj_attacktime) {
207 return ADJ_ATTACKTIME;
208 } else if (adj == cp->adj_envelope) {
209 return ADJ_ENVELOPE;
210 } else if (adj == cp->adj_length) {
211 return ADJ_LENGTH;
212 } else if (adj == cp->adj_stretch) {
213 return ADJ_STRETCH;
214 } else if (adj == cp->adj_stereo_in) {
215 return ADJ_STEREO_IN;
216 } else if (adj == cp->adj_stereo_ir) {
217 return ADJ_STEREO_IR;
218 } else if (adj == cp->adj_dry_gain) {
219 return ADJ_DRY_GAIN;
220 } else if (adj == cp->adj_wet_gain) {
221 return ADJ_WET_GAIN;
222 }
223 return -1;
224 }
225
convert_scale_to_real(int idx,double scale)226 static double convert_scale_to_real(int idx, double scale) {
227 int log = adj_descr_table[idx].log;
228 double y;
229 double min = adj_descr_table[idx].min;
230 double max = adj_descr_table[idx].max;
231 double real = 0.0;
232 if (log == LIN) {
233 real = scale;
234 } else if (log == LOG) {
235 y = log10(scale);
236 real = min + (y - LOG_SCALE_MIN) / (LOG_SCALE_MAX - LOG_SCALE_MIN) * (max - min);
237 real = round(10.0 * real) / 10.0; /* one decimal digit */
238 } else if (log == INVLOG) {
239 y = exp10(scale);
240 real = min + (y - INVLOG_SCALE_MIN) / (INVLOG_SCALE_MAX - INVLOG_SCALE_MIN) * (max - min);
241 real = round(10.0 * real) / 10.0; /* one decimal digit */
242 }
243 return real;
244 }
245
convert_real_to_scale(int idx,double real)246 static double convert_real_to_scale(int idx, double real) {
247 int log = adj_descr_table[idx].log;
248 double min = adj_descr_table[idx].min;
249 double max = adj_descr_table[idx].max;
250 double scale = 0.0;
251 if (log == LIN) {
252 scale = real;
253 } else if (log == LOG) {
254 scale = (real - min) / (max - min) *
255 (LOG_SCALE_MAX - LOG_SCALE_MIN) + LOG_SCALE_MIN;
256 scale = exp10(scale);
257 } else if (log == INVLOG) {
258 scale = (real - min) / (max - min) *
259 (INVLOG_SCALE_MAX - INVLOG_SCALE_MIN) + INVLOG_SCALE_MIN;
260 scale = log10(scale);
261 }
262 return scale;
263 }
264
get_adjustment(struct control * cp,GtkAdjustment * adj)265 static double get_adjustment(struct control * cp, GtkAdjustment * adj) {
266 double y = gtk_adjustment_get_value(adj);
267 int idx = get_adj_index(cp, adj);
268 return convert_scale_to_real(idx, y);
269 }
270
set_adjustment(struct control * cp,GtkAdjustment * adj,double x)271 static void set_adjustment(struct control * cp, GtkAdjustment * adj, double x) {
272 int idx = get_adj_index(cp, adj);
273 gtk_adjustment_set_value(adj, convert_real_to_scale(idx, x));
274 }
275
create_adjustment(int idx,gpointer data)276 static GtkAdjustment * create_adjustment(int idx, gpointer data) {
277 GtkObject * adj = NULL;
278 gdouble def = adj_descr_table[idx].def;
279 gdouble min = adj_descr_table[idx].min;
280 gdouble max = adj_descr_table[idx].max;
281 int log = adj_descr_table[idx].log;
282 if ((log == LOG) || (log == INVLOG)) {
283 adj = gtk_adjustment_new(convert_real_to_scale(idx, def),
284 convert_real_to_scale(idx, min),
285 convert_real_to_scale(idx, max) + 1.0,
286 0.01, 1.0, 1.0);
287 } else {
288 adj = gtk_adjustment_new(def, min, max + 1.0, 0.1, 1.0, 1.0);
289 }
290 g_signal_connect(adj, "value_changed", G_CALLBACK(adjustment_changed_cb), data);
291 return (GtkAdjustment *)adj;
292 }
293
294
set_agc_label(struct control * cp)295 static void set_agc_label(struct control * cp) {
296 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cp->toggle_agc_sw))) {
297 char str[32];
298 snprintf(str, 32, "Autogain %+.1f dB", cp->ir->autogain_new);
299 gtk_button_set_label(GTK_BUTTON(cp->toggle_agc_sw), str);
300 } else {
301 gtk_button_set_label(GTK_BUTTON(cp->toggle_agc_sw), "Autogain off");
302 }
303 }
304
305 #define S1 "<span size=\"small\">"
306 #define S2 "</span>"
307 #define XS1 "<span size=\"x-small\">"
308 #define XS2 "</span>"
set_label(struct control * cp,int idx)309 static void set_label(struct control * cp, int idx) {
310
311 char str[1024];
312 GtkWidget * label = NULL;
313 float v;
314
315 switch (idx) {
316 case ADJ_PREDELAY:
317 label = cp->label_predelay;
318 v = get_adjustment(cp, cp->adj_predelay);
319 snprintf(str, 1024, S1 "<b>Predelay</b>" S2 "\n" XS1 "%0.1fms" XS2,
320 fabs(v)); /* kill the spurious negative zero */
321 break;
322 case ADJ_ATTACK:
323 case ADJ_ATTACKTIME:
324 label = cp->label_attack; /* spaces eliminate label-positioning problem */
325 snprintf(str, 1024, S1 "<b> Attack</b>" S2 "\n" XS1 "%0.0f%% %0.0fms" XS2,
326 get_adjustment(cp, cp->adj_attack),
327 get_adjustment(cp, cp->adj_attacktime));
328 break;
329 case ADJ_ENVELOPE:
330 label = cp->label_envelope;
331 snprintf(str, 1024, S1 "<b>Envelope</b>" S2 "\n" XS1 "%0.1f%%" XS2,
332 get_adjustment(cp, cp->adj_envelope));
333 break;
334 case ADJ_LENGTH:
335 label = cp->label_length;
336 snprintf(str, 1024, S1 "<b>Length</b>" S2 "\n" XS1"%0.1f%%" XS2,
337 get_adjustment(cp, cp->adj_length));
338 break;
339 case ADJ_STRETCH:
340 label = cp->label_stretch;
341 snprintf(str, 1024, S1 "<b>Stretch</b>" S2 "\n" XS1 "%0.1f%%" XS2,
342 get_adjustment(cp, cp->adj_stretch));
343 break;
344 case ADJ_STEREO_IN:
345 case ADJ_STEREO_IR:
346 label = cp->label_stereo;
347 snprintf(str, 1024, S1 "<b>Stereo in/IR</b>" S2 "\n" XS1 "%0.0f%% / %0.0f%%" XS2,
348 get_adjustment(cp, cp->adj_stereo_in),
349 get_adjustment(cp, cp->adj_stereo_ir));
350 break;
351 case ADJ_DRY_GAIN:
352 label = cp->label_dry_gain;
353 v = get_adjustment(cp, cp->adj_dry_gain);
354 if (v > 0.0) {
355 snprintf(str, 1024, S1 "%+0.1f dB" S2, v);
356 } else if (v == 0.0) {
357 snprintf(str, 1024, S1 "0.0 dB" S2);
358 } else if (v > -90.0) {
359 snprintf(str, 1024, S1 "%+0.1f dB" S2, v);
360 } else {
361 snprintf(str, 1024, S1 "mute" S2);
362 }
363 break;
364 case ADJ_WET_GAIN:
365 label = cp->label_wet_gain;
366 v = get_adjustment(cp, cp->adj_wet_gain);
367 if (v > 0.0) {
368 snprintf(str, 1024, S1 "%+0.1f dB" S2, v);
369 } else if (v == 0.0) {
370 snprintf(str, 1024, S1 "0.0 dB" S2);
371 } else if (v > -90.0) {
372 snprintf(str, 1024, S1 "%+0.1f dB" S2, v);
373 } else {
374 snprintf(str, 1024, S1 "mute" S2);
375 }
376 break;
377 }
378
379 gtk_label_set_markup(GTK_LABEL(label), str);
380 }
381
refresh_gui_on_load(struct control * cp)382 static void refresh_gui_on_load(struct control * cp) {
383 char str[1024];
384 const char * chn = (cp->ir->nchan > 1) ? "channels" : "channel";
385 float secs = (float)cp->ir->source_nfram / cp->ir->source_samplerate;
386 char * filename_esc = g_markup_escape_text(cp->ir->source_path, -1);
387 if (cp->ir->source_samplerate == (unsigned int)cp->ir->sample_rate) {
388 snprintf(str, 1024,
389 XS1 "<b>%s</b>" XS2 "\n"
390 S1 "%d %s, %d samples, %d Hz, %.3f seconds" S2,
391 filename_esc,
392 cp->ir->nchan, chn, cp->ir->source_nfram,
393 cp->ir->source_samplerate, secs);
394 } else {
395 snprintf(str, 1024,
396 XS1 "<b>%s</b>" XS2 "\n"
397 S1 "%d %s, %d samples, %d Hz (resampled to %d Hz), %.3f seconds" S2,
398 filename_esc,
399 cp->ir->nchan, chn, cp->ir->source_nfram,
400 cp->ir->source_samplerate, (int)cp->ir->sample_rate, secs);
401 }
402 free(filename_esc);
403 gtk_label_set_markup(GTK_LABEL(cp->wave_annot_label), str);
404
405 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cp->chan_toggle[0]), FALSE);
406 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cp->chan_toggle[0]), TRUE);
407 gtk_widget_set_sensitive(cp->chan_toggle[0], cp->ir->nchan > 1);
408 for (int i = 1; i < 4; i++) {
409 gtk_widget_set_sensitive(cp->chan_toggle[i], i < cp->ir->nchan);
410 }
411
412 set_agc_label(cp);
413 ir_modeind_set_channels(IR_MODEIND(cp->mode_ind), cp->ir->nchan);
414 }
415
gui_load_thread(gpointer data)416 static gpointer gui_load_thread(gpointer data) {
417 struct control * cp = (struct control*)data;
418 int r = cp->ir->resample_init(cp->ir);
419 if (r == 0) {
420 while (r == 0) {
421 r = cp->ir->resample_do(cp->ir);
422 if (cp->interrupt_threads) {
423 break;
424 }
425 }
426 cp->ir->resample_cleanup(cp->ir);
427 }
428 if (r >= 0) {
429 cp->ir->prepare_convdata(cp->ir);
430 cp->ir->init_conv(cp->ir);
431 }
432 cp->ir->reinit_running = 0;
433 return NULL;
434 }
435
gui_load_timeout_callback(gpointer data)436 static gint gui_load_timeout_callback(gpointer data) {
437 struct control * cp = (struct control*)data;
438 if (cp->ir->reinit_running) {
439 ir_wavedisplay_set_progress(IR_WAVEDISPLAY(cp->wave_display), cp->ir->src_progress);
440 return TRUE;
441 }
442 g_thread_join(cp->gui_load_thread);
443 cp->gui_load_thread = NULL;
444 ir_wavedisplay_set_progress(IR_WAVEDISPLAY(cp->wave_display), -1.0);
445 ir_wavedisplay_set_message(IR_WAVEDISPLAY(cp->wave_display), NULL);
446 refresh_gui_on_load(cp);
447 reset_values(cp);
448 cp->gui_load_timeout_tag = 0;
449 return FALSE;
450 }
451
gui_load_sndfile(struct control * cp,char * filename)452 static void gui_load_sndfile(struct control * cp, char * filename) {
453
454 if (cp->ir->reinit_running || cp->gui_load_thread) {
455 return;
456 }
457
458 if (cp->ir->source_path) {
459 free(cp->ir->source_path);
460 }
461 cp->ir->source_path = strdup(filename);
462 ir_wavedisplay_set_message(IR_WAVEDISPLAY(cp->wave_display), "Loading...");
463 ir_wavedisplay_set_progress(IR_WAVEDISPLAY(cp->wave_display), 0.0);
464 if (cp->ir->load_sndfile(cp->ir) < 0) {
465 fprintf(stderr, "IR: load_sndfile error\n");
466 ir_wavedisplay_set_message(IR_WAVEDISPLAY(cp->wave_display), NULL);
467 } else {
468 uint64_t hash = fhash(filename);
469 float value0, value1, value2;
470 ports_from_fhash(hash, &value0, &value1, &value2);
471 cp->write_function(cp->controller, IR_PORT_FHASH_0, sizeof(float),
472 0 /* default format */, &value0);
473 cp->write_function(cp->controller, IR_PORT_FHASH_1, sizeof(float),
474 0 /* default format */, &value1);
475 cp->write_function(cp->controller, IR_PORT_FHASH_2, sizeof(float),
476 0 /* default format */, &value2);
477
478 cp->ir->reinit_running = 1;
479 cp->gui_load_thread = g_thread_new("gui_load_thread", gui_load_thread, cp);
480 cp->gui_load_timeout_tag = g_timeout_add(100, gui_load_timeout_callback, cp);
481 }
482 }
483
browse_button_clicked(GtkWidget * w,gpointer data)484 static void browse_button_clicked(GtkWidget * w, gpointer data) {
485
486 struct control * cp = (struct control *)data;
487 GtkWidget * dialog;
488 if (cp->ir->reinit_running) {
489 return;
490 }
491 dialog = gtk_file_chooser_dialog_new("Open File",
492 NULL,
493 GTK_FILE_CHOOSER_ACTION_OPEN,
494 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
495 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
496 NULL);
497
498 GtkFileFilter * filter = gtk_file_filter_new();
499 gtk_file_filter_set_name(filter, "All files");
500 gtk_file_filter_add_pattern(filter, "*");
501 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
502
503 filter = gtk_file_filter_new();
504 gtk_file_filter_set_name(filter, "Soundfiles");
505 gtk_file_filter_add_pattern(filter, "*.wav");
506 gtk_file_filter_add_pattern(filter, "*.WAV");
507 gtk_file_filter_add_pattern(filter, "*.aiff");
508 gtk_file_filter_add_pattern(filter, "*.AIFF");
509 gtk_file_filter_add_pattern(filter, "*.au");
510 gtk_file_filter_add_pattern(filter, "*.AU");
511 gtk_file_filter_add_pattern(filter, "*.flac");
512 gtk_file_filter_add_pattern(filter, "*.FLAC");
513 gtk_file_filter_add_pattern(filter, "*.ogg");
514 gtk_file_filter_add_pattern(filter, "*.OGG");
515 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
516 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
517
518 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
519 char * filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog));
520 gui_load_sndfile(cp, filename);
521 char * dirname = g_path_get_dirname(filename);
522 load_files(cp->store_files, dirname);
523 GtkTreeSelection * select =
524 gtk_tree_view_get_selection(GTK_TREE_VIEW(cp->tree_bookmarks));
525 g_signal_handler_block(select, cp->bookmarks_sel_cbid);
526 select_entry(cp->model_bookmarks, select, dirname);
527 g_signal_handler_unblock(select, cp->bookmarks_sel_cbid);
528
529 select = gtk_tree_view_get_selection(GTK_TREE_VIEW(cp->tree_files));
530 g_signal_handler_block(select, cp->files_sel_cbid);
531 select_entry(GTK_TREE_MODEL(cp->store_files), select, filename);
532 g_signal_handler_unblock(select, cp->files_sel_cbid);
533 g_free(filename);
534 g_free(dirname);
535 }
536 gtk_widget_destroy(dialog);
537 }
538
key_pressed_cb(GtkWidget * widget,GdkEventKey * event,gpointer data)539 static int key_pressed_cb(GtkWidget * widget, GdkEventKey * event, gpointer data) {
540 struct control * cp = (struct control *)data;
541 if (cp->ir->reinit_running) {
542 return FALSE;
543 }
544 cp->key_pressed = 1;
545 return FALSE;
546 }
547
save_value(struct control * cp,int port,float value)548 static void save_value(struct control * cp, int port, float value) {
549 switch (port) {
550 case IR_PORT_PREDELAY: cp->predelay = value;
551 break;
552 case IR_PORT_ATTACK: cp->attack = value;
553 break;
554 case IR_PORT_ATTACKTIME: cp->attacktime = value;
555 break;
556 case IR_PORT_ENVELOPE: cp->envelope = value;
557 break;
558 case IR_PORT_LENGTH: cp->length = value;
559 break;
560 case IR_PORT_STRETCH: cp->stretch = value;
561 break;
562 case IR_PORT_STEREO_IR: cp->stereo_ir = value;
563 break;
564 }
565 }
566
reset_values(struct control * cp)567 static void reset_values(struct control * cp) {
568 set_adjustment(cp, cp->adj_predelay, cp->predelay);
569 set_adjustment(cp, cp->adj_attack, cp->attack);
570 set_adjustment(cp, cp->adj_attacktime, cp->attacktime);
571 set_adjustment(cp, cp->adj_envelope, cp->envelope);
572 set_adjustment(cp, cp->adj_length, cp->length);
573 set_adjustment(cp, cp->adj_stretch, cp->stretch);
574 set_adjustment(cp, cp->adj_stereo_ir, cp->stereo_ir);
575 }
576
reset_value(struct control * cp,GtkAdjustment * adj)577 static void reset_value(struct control * cp, GtkAdjustment * adj) {
578 if (adj == cp->adj_predelay) {
579 set_adjustment(cp, adj, cp->predelay);
580 } else if (adj == cp->adj_attack) {
581 set_adjustment(cp, adj, cp->attack);
582 } else if (adj == cp->adj_attacktime) {
583 set_adjustment(cp, adj, cp->attacktime);
584 } else if (adj == cp->adj_envelope) {
585 set_adjustment(cp, adj, cp->envelope);
586 } else if (adj == cp->adj_length) {
587 set_adjustment(cp, adj, cp->length);
588 } else if (adj == cp->adj_stretch) {
589 set_adjustment(cp, adj, cp->stretch);
590 } else if (adj == cp->adj_stereo_ir) {
591 set_adjustment(cp, adj, cp->stereo_ir);
592 }
593 }
594
key_released_cb(GtkWidget * widget,GdkEventKey * event,gpointer data)595 static int key_released_cb(GtkWidget * widget, GdkEventKey * event, gpointer data) {
596 struct control * cp = (struct control *)data;
597 GtkAdjustment * adj = NULL;
598 int port = 0;
599
600 cp->key_pressed = 0;
601 if (cp->ir->reinit_running) {
602 return FALSE;
603 }
604
605 if (widget == cp->scale_predelay) {
606 adj = cp->adj_predelay;
607 port = IR_PORT_PREDELAY;
608 } else if (widget == cp->scale_attack) {
609 adj = cp->adj_attack;
610 port = IR_PORT_ATTACK;
611 } else if (widget == cp->scale_attacktime) {
612 adj = cp->adj_attacktime;
613 port = IR_PORT_ATTACKTIME;
614 } else if (widget == cp->scale_envelope) {
615 adj = cp->adj_envelope;
616 port = IR_PORT_ENVELOPE;
617 } else if (widget == cp->scale_length) {
618 adj = cp->adj_length;
619 port = IR_PORT_LENGTH;
620 } else if (widget == cp->scale_stretch) {
621 adj = cp->adj_stretch;
622 port = IR_PORT_STRETCH;
623 cp->ir->resample_pending = 1;
624 } else if (widget == cp->scale_stereo_ir) {
625 adj = cp->adj_stereo_ir;
626 port = IR_PORT_STEREO_IR;
627 }
628
629 if (port == 0) {
630 return FALSE;
631 }
632
633 float value = get_adjustment(cp, adj);
634 save_value(cp, port, value);
635
636 //printf("on button_release adj value = %f\n", value);
637 send_port_value_to_host(cp, port, value);
638
639 cp->ir->run = 0;
640 cp->ir->reinit_pending = 1;
641 return FALSE;
642 }
643
update_envdisplay(struct control * cp)644 static void update_envdisplay(struct control * cp) {
645 int attack_time_s =
646 get_adjustment(cp, cp->adj_attacktime) *
647 (float)cp->ir->sample_rate / 1000.0;
648 float attack_pc = get_adjustment(cp, cp->adj_attack);
649 float env_pc = get_adjustment(cp, cp->adj_envelope);
650 float length_pc = get_adjustment(cp, cp->adj_length);
651 int reverse = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cp->toggle_reverse)) ? 1 : 0;
652 ir_wavedisplay_set_envparams(IR_WAVEDISPLAY(cp->wave_display),
653 attack_time_s, attack_pc,
654 env_pc, length_pc, reverse);
655 }
656
adjustment_changed_cb(GtkAdjustment * adj,gpointer data)657 static void adjustment_changed_cb(GtkAdjustment * adj, gpointer data) {
658 struct control * cp = (struct control *)data;
659 float value = get_adjustment(cp, adj);
660 int port = 0;
661 int update_ui = 0;
662 int label_idx = 0;
663 if (adj == cp->adj_predelay) {
664 label_idx = ADJ_PREDELAY;
665 } else if (adj == cp->adj_attack) {
666 label_idx = ADJ_ATTACK;
667 update_ui = 1;
668 } else if (adj == cp->adj_attacktime) {
669 label_idx = ADJ_ATTACK;
670 update_ui = 1;
671 } else if (adj == cp->adj_envelope) {
672 label_idx = ADJ_ENVELOPE;
673 update_ui = 1;
674 } else if (adj == cp->adj_length) {
675 label_idx = ADJ_LENGTH;
676 update_ui = 1;
677 } else if (adj == cp->adj_stretch) {
678 label_idx = ADJ_STRETCH;
679 } else if (adj == cp->adj_stereo_in) {
680 label_idx = ADJ_STEREO_IN;
681 port = IR_PORT_STEREO_IN;
682 } else if (adj == cp->adj_stereo_ir) {
683 label_idx = ADJ_STEREO_IR;
684 } else if (adj == cp->adj_dry_gain) {
685 label_idx = ADJ_DRY_GAIN;
686 port = IR_PORT_DRY_GAIN;
687 } else if (adj == cp->adj_wet_gain) {
688 label_idx = ADJ_WET_GAIN;
689 port = IR_PORT_WET_GAIN;
690 }
691
692 if (cp->ir->reinit_running && !port) {
693 return;
694 }
695
696 set_label(cp, label_idx);
697
698 if (port == 0) {
699 if (cp->key_pressed) {
700 save_value(cp, port, value);
701 if (update_ui) {
702 update_envdisplay(cp);
703 }
704 } else {
705 reset_value(cp, adj);
706 }
707 return;
708 }
709
710 //printf("adj changed to %f\n", value);
711 send_port_value_to_host(cp, port, value);
712 }
713
toggle_button_cb(GtkWidget * widget,gpointer data)714 static void toggle_button_cb(GtkWidget * widget, gpointer data) {
715
716 struct control * cp = (struct control *)data;
717 if (cp->ir->reinit_running && (widget == cp->toggle_reverse)) {
718 g_signal_handler_block(widget, cp->toggle_reverse_cbid);
719 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
720 !(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))));
721 g_signal_handler_unblock(widget, cp->toggle_reverse_cbid);
722 return;
723 }
724 int port = 0;
725 float value;
726 const char * text;
727 if (widget == cp->toggle_dry_sw) {
728 port = IR_PORT_DRY_SW;
729 } else if (widget == cp->toggle_wet_sw) {
730 port = IR_PORT_WET_SW;
731 } else if (widget == cp->toggle_reverse) {
732 port = IR_PORT_REVERSE;
733 }
734 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
735 value = 1.0f;
736 text = "ON";
737 } else {
738 value = 0.0f;
739 text = "off";
740 }
741 send_port_value_to_host(cp, port, value);
742
743 if (port == IR_PORT_REVERSE) {
744 cp->ir->run = 0;
745 cp->ir->reinit_pending = 1;
746 update_envdisplay(cp);
747 } else if ((port == IR_PORT_DRY_SW) ||
748 (port == IR_PORT_WET_SW)) {
749 gtk_button_set_label(GTK_BUTTON(widget), text);
750 }
751 }
752
irctrl_add_row(GtkWidget * table,int row,GtkWidget ** label,GtkAdjustment * adj,GtkWidget ** scale,int idx,gpointer data)753 static void irctrl_add_row(GtkWidget * table, int row, GtkWidget ** label, GtkAdjustment * adj,
754 GtkWidget ** scale, int idx, gpointer data) {
755
756 struct control * cp = (struct control *)data;
757 *label = gtk_label_new("");
758 gtk_label_set_justify(GTK_LABEL(*label), GTK_JUSTIFY_RIGHT);
759 set_label(cp, idx);
760 gtk_misc_set_alignment(GTK_MISC(*label), 1.0f, 0.0f);
761 gtk_table_attach(GTK_TABLE(table), *label, 0, 1, row, row + 1,
762 GTK_FILL, GTK_FILL, 0, 0);
763
764 *scale = gtk_hscale_new(adj);
765 gtk_scale_set_draw_value(GTK_SCALE(*scale), FALSE);
766 gtk_widget_add_events(*scale, GDK_BUTTON_RELEASE_MASK);
767 g_signal_connect(*scale, "button_press_event",
768 G_CALLBACK(key_pressed_cb), data);
769 g_signal_connect(*scale, "button_release_event",
770 G_CALLBACK(key_released_cb), data);
771 gtk_table_attach_defaults(GTK_TABLE(table), *scale, 1, 3, row, row + 1);
772 }
773
irctrl_add_row2(GtkWidget * table,int row,GtkWidget ** label,GtkAdjustment * adj1,GtkAdjustment * adj2,GtkWidget ** scale1,GtkWidget ** scale2,int idx,gpointer data)774 static void irctrl_add_row2(GtkWidget * table, int row,
775 GtkWidget ** label, GtkAdjustment * adj1, GtkAdjustment * adj2,
776 GtkWidget ** scale1, GtkWidget ** scale2,
777 int idx, gpointer data) {
778
779 struct control * cp = (struct control *)data;
780 *label = gtk_label_new("");
781 gtk_label_set_justify(GTK_LABEL(*label), GTK_JUSTIFY_RIGHT);
782 set_label(cp, idx);
783 gtk_misc_set_alignment(GTK_MISC(*label), 1.0f, 0.0f);
784 gtk_table_attach(GTK_TABLE(table), *label, 0, 1, row, row + 1,
785 GTK_FILL, GTK_FILL, 0, 0);
786
787 *scale1 = gtk_hscale_new(adj1);
788 gtk_scale_set_draw_value(GTK_SCALE(*scale1), FALSE);
789 gtk_widget_add_events(*scale1, GDK_BUTTON_RELEASE_MASK);
790 g_signal_connect(*scale1, "button_press_event",
791 G_CALLBACK(key_pressed_cb), data);
792 g_signal_connect(*scale1, "button_release_event",
793 G_CALLBACK(key_released_cb), data);
794 gtk_table_attach_defaults(GTK_TABLE(table), *scale1, 1, 2, row, row + 1);
795
796 *scale2 = gtk_hscale_new(adj2);
797 gtk_scale_set_draw_value(GTK_SCALE(*scale2), FALSE);
798 gtk_widget_add_events(*scale2, GDK_BUTTON_RELEASE_MASK);
799 g_signal_connect(*scale2, "button_press_event",
800 G_CALLBACK(key_pressed_cb), data);
801 g_signal_connect(*scale2, "button_release_event",
802 G_CALLBACK(key_released_cb), data);
803 gtk_table_attach_defaults(GTK_TABLE(table), *scale2, 2, 3, row, row + 1);
804 }
805
make_irctrl_frame(struct control * cp)806 static GtkWidget * make_irctrl_frame(struct control * cp) {
807
808 GtkWidget * frame = gtk_frame_new(NULL);
809 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
810
811 GtkWidget * table = gtk_table_new(6, 3, FALSE);
812 gtk_table_set_row_spacings(GTK_TABLE(table), PAD);
813 gtk_table_set_col_spacings(GTK_TABLE(table), 2*PAD);
814 gtk_container_add(GTK_CONTAINER(frame), table);
815
816 /* Predelay */
817 cp->adj_predelay = create_adjustment(ADJ_PREDELAY, cp);
818 irctrl_add_row(table, 0, &cp->label_predelay, cp->adj_predelay, &cp->scale_predelay,
819 ADJ_PREDELAY, cp);
820
821 /* Attack */
822 cp->adj_attack = create_adjustment(ADJ_ATTACK, cp);
823 cp->adj_attacktime = create_adjustment(ADJ_ATTACKTIME, cp);
824 irctrl_add_row2(table, 1, &cp->label_attack, cp->adj_attack, cp->adj_attacktime,
825 &cp->scale_attack, &cp->scale_attacktime,
826 ADJ_ATTACK, cp);
827
828 /* Envelope */
829 cp->adj_envelope = create_adjustment(ADJ_ENVELOPE, cp);
830 irctrl_add_row(table, 2, &cp->label_envelope, cp->adj_envelope, &cp->scale_envelope,
831 ADJ_ENVELOPE, cp);
832
833 /* Length */
834 cp->adj_length = create_adjustment(ADJ_LENGTH, cp);
835 irctrl_add_row(table, 3, &cp->label_length, cp->adj_length, &cp->scale_length,
836 ADJ_LENGTH, cp);
837
838 /* Stretch */
839 cp->adj_stretch = create_adjustment(ADJ_STRETCH, cp);
840 irctrl_add_row(table, 4, &cp->label_stretch, cp->adj_stretch, &cp->scale_stretch,
841 ADJ_STRETCH, cp);
842
843 /* Stereo width in/IR */
844 cp->adj_stereo_in = create_adjustment(ADJ_STEREO_IN, cp);
845 cp->adj_stereo_ir = create_adjustment(ADJ_STEREO_IR, cp);
846 irctrl_add_row2(table, 5, &cp->label_stereo, cp->adj_stereo_in, cp->adj_stereo_ir,
847 &cp->scale_stereo_in, &cp->scale_stereo_ir,
848 ADJ_STEREO_IN, cp);
849
850 gtk_scale_add_mark(GTK_SCALE(cp->scale_stretch), 100.0, GTK_POS_BOTTOM, XS1 " " XS2);
851 gtk_scale_add_mark(GTK_SCALE(cp->scale_stereo_in), 100.0, GTK_POS_BOTTOM, XS1 " " XS2);
852 gtk_scale_add_mark(GTK_SCALE(cp->scale_stereo_ir), 100.0, GTK_POS_BOTTOM, XS1 " " XS2);
853
854 gtk_widget_set_size_request(cp->scale_attack, 125, -1);
855 gtk_widget_set_size_request(cp->scale_attacktime, 125, -1);
856 return frame;
857 }
858
agc_toggle_cb(GtkWidget * widget,gpointer data)859 static void agc_toggle_cb(GtkWidget * widget, gpointer data) {
860 struct control * cp = (struct control *)data;
861 float value;
862 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
863 value = 1.0f;
864 } else {
865 value = 0.0f;
866 }
867
868 send_port_value_to_host(cp, IR_PORT_AGC_SW, value);
869 set_agc_label(cp);
870 }
871
make_mixer_frame(struct control * cp)872 static GtkWidget * make_mixer_frame(struct control * cp) {
873
874 GtkWidget * frame = gtk_frame_new(NULL);
875 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
876
877 GtkWidget * vbox_top = gtk_vbox_new(FALSE, 0);
878 gtk_container_add(GTK_CONTAINER(frame), vbox_top);
879
880 GtkWidget * hbox = gtk_hbox_new(TRUE, PAD);
881 gtk_box_pack_start(GTK_BOX(vbox_top), hbox, TRUE, TRUE, PAD);
882
883 cp->adj_dry_gain = create_adjustment(ADJ_DRY_GAIN, cp);
884 cp->adj_wet_gain = create_adjustment(ADJ_WET_GAIN, cp);
885
886 /* Dry */
887 GtkWidget * vbox = gtk_vbox_new(FALSE, 0);
888 gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, PAD);
889
890 GtkWidget * label = gtk_label_new("");
891 gtk_label_set_markup(GTK_LABEL(label), S1 "<b>Dry</b>" S2);
892 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, PAD);
893
894 GtkWidget * hbox_i = gtk_hbox_new(FALSE, 0);
895 gtk_box_pack_start(GTK_BOX(vbox), hbox_i, TRUE, TRUE, PAD);
896
897 GtkWidget * scale;
898 scale = gtk_vscale_new(cp->adj_dry_gain);
899 gtk_range_set_inverted(GTK_RANGE(scale), TRUE);
900 gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE);
901 gtk_scale_add_mark(GTK_SCALE(scale), convert_real_to_scale(ADJ_DRY_GAIN, 0.0),
902 GTK_POS_RIGHT, XS1 " " XS2);
903 gtk_box_pack_start(GTK_BOX(hbox_i), scale, TRUE, TRUE, 0);
904
905 cp->meter_L_dry = ir_meter_new();
906 gtk_widget_set_size_request(cp->meter_L_dry, 5, -1);
907 gtk_box_pack_start(GTK_BOX(hbox_i), cp->meter_L_dry, FALSE, TRUE, 1);
908
909 cp->meter_R_dry = ir_meter_new();
910 gtk_widget_set_size_request(cp->meter_R_dry, 5, -1);
911 gtk_box_pack_start(GTK_BOX(hbox_i), cp->meter_R_dry, FALSE, TRUE, 0);
912
913
914 cp->label_dry_gain = gtk_label_new("0.0 dB");
915 gtk_box_pack_start(GTK_BOX(vbox), cp->label_dry_gain, FALSE, TRUE, PAD);
916
917 cp->toggle_dry_sw = gtk_toggle_button_new_with_label("off");
918 g_signal_connect(cp->toggle_dry_sw, "toggled",
919 G_CALLBACK(toggle_button_cb), cp);
920 gtk_box_pack_start(GTK_BOX(vbox), cp->toggle_dry_sw, FALSE, FALSE, PAD);
921
922 /* Wet */
923 vbox = gtk_vbox_new(FALSE, 0);
924 gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, PAD);
925
926 label = gtk_label_new("");
927 gtk_label_set_markup(GTK_LABEL(label), S1 "<b>Wet</b>" S2);
928 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, PAD);
929
930 hbox_i = gtk_hbox_new(FALSE, 0);
931 gtk_box_pack_start(GTK_BOX(vbox), hbox_i, TRUE, TRUE, PAD);
932
933 scale = gtk_vscale_new(cp->adj_wet_gain);
934 gtk_range_set_inverted(GTK_RANGE(scale), TRUE);
935 gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE);
936 gtk_scale_add_mark(GTK_SCALE(scale), convert_real_to_scale(ADJ_WET_GAIN, 0.0),
937 GTK_POS_RIGHT, XS1 " " XS2);
938 gtk_box_pack_start(GTK_BOX(hbox_i), scale, TRUE, TRUE, 0);
939
940 cp->meter_L_wet = ir_meter_new();
941 gtk_widget_set_size_request(cp->meter_L_wet, 5, -1);
942 gtk_box_pack_start(GTK_BOX(hbox_i), cp->meter_L_wet, FALSE, TRUE, 1);
943
944 cp->meter_R_wet = ir_meter_new();
945 gtk_widget_set_size_request(cp->meter_R_wet, 5, -1);
946 gtk_box_pack_start(GTK_BOX(hbox_i), cp->meter_R_wet, FALSE, TRUE, 0);
947
948
949 cp->label_wet_gain = gtk_label_new("-6.0 dB");
950 gtk_box_pack_start(GTK_BOX(vbox), cp->label_wet_gain, FALSE, TRUE, PAD);
951
952 cp->toggle_wet_sw = gtk_toggle_button_new_with_label("off");
953 g_signal_connect(cp->toggle_wet_sw, "toggled",
954 G_CALLBACK(toggle_button_cb), cp);
955 gtk_box_pack_start(GTK_BOX(vbox), cp->toggle_wet_sw, FALSE, FALSE, PAD);
956
957 /* Autogain */
958 hbox = gtk_hbox_new(FALSE, PAD);
959 gtk_box_pack_start(GTK_BOX(vbox_top), hbox, FALSE, TRUE, 0);
960 cp->toggle_agc_sw = gtk_toggle_button_new_with_label("Autogain");
961 g_signal_connect(cp->toggle_agc_sw, "toggled",
962 G_CALLBACK(agc_toggle_cb), cp);
963 gtk_box_pack_start(GTK_BOX(hbox), cp->toggle_agc_sw, TRUE, TRUE, PAD);
964
965 return frame;
966 }
967
add_bookmark_button_clicked(GtkWidget * w,gpointer data)968 static void add_bookmark_button_clicked(GtkWidget * w, gpointer data) {
969 struct control * cp = (struct control *)data;
970 GtkWidget * dialog;
971 dialog = gtk_file_chooser_dialog_new("Select directory",
972 NULL,
973 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
974 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
975 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
976 NULL);
977
978 GtkWidget * hbox = gtk_hbox_new(FALSE, PAD);
979 GtkWidget * label = gtk_label_new("Bookmark name (optional):");
980 gtk_widget_show(label);
981 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, PAD);
982 GtkWidget * entry = gtk_entry_new();
983 gtk_widget_show(entry);
984 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, PAD);
985 gtk_widget_show(hbox);
986 gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(dialog), hbox);
987
988 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
989 char * filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
990 const gchar * bookmark = gtk_entry_get_text(GTK_ENTRY(entry));
991 char * name;
992
993 if ((bookmark != NULL) && (strlen(bookmark) > 0)) {
994 name = strdup(bookmark);
995 } else {
996 /* use last path component as name */
997 name = g_path_get_basename(filename);
998 }
999
1000 char * path = lookup_bookmark_in_store(cp->model_bookmarks, name);
1001 if (path) {
1002 fprintf(stderr, "IR: bookmark already exists!\n");
1003 g_free(path);
1004 } else {
1005 GtkTreeIter iter;
1006 gtk_list_store_append(cp->ir->store_bookmarks, &iter);
1007 gtk_list_store_set(cp->ir->store_bookmarks, &iter,
1008 0, name, 1, filename, -1);
1009 store_bookmark(cp->ir->keyfile, name, filename);
1010 }
1011 g_free(name);
1012 g_free(filename);
1013 }
1014 gtk_widget_destroy(dialog);
1015 }
1016
del_bookmark_button_clicked(GtkWidget * w,gpointer data)1017 static void del_bookmark_button_clicked(GtkWidget * w, gpointer data) {
1018 struct control * cp = (struct control *)data;
1019 GtkTreeIter iter; /* on sorted model */
1020 GtkTreeIter real_iter; /* on underlying model */
1021 GtkTreeModel * model;
1022 GtkTreeSelection * select;
1023 gchar * key;
1024
1025 select = gtk_tree_view_get_selection(GTK_TREE_VIEW(cp->tree_bookmarks));
1026 if (gtk_tree_selection_get_selected(select, &model, &iter)) {
1027 gtk_tree_model_get(model, &iter, 0, &key, -1);
1028 delete_bookmark(cp->ir->keyfile, key);
1029 gtk_tree_model_sort_convert_iter_to_child_iter(
1030 GTK_TREE_MODEL_SORT(cp->model_bookmarks),
1031 &real_iter, &iter);
1032 gtk_list_store_remove(cp->ir->store_bookmarks, &real_iter);
1033 g_free(key);
1034 }
1035 }
1036
bookmarks_selection_changed_cb(GtkTreeSelection * selection,gpointer data)1037 static void bookmarks_selection_changed_cb(GtkTreeSelection * selection, gpointer data) {
1038 struct control * cp = (struct control *)data;
1039 GtkTreeIter iter;
1040 GtkTreeModel * model;
1041 gchar * bookmark;
1042 gchar * dirpath;
1043
1044 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
1045 gtk_tree_model_get(model, &iter, 0, &bookmark, 1, &dirpath, -1);
1046 load_files(cp->store_files, dirpath);
1047 g_free(bookmark);
1048 g_free(dirpath);
1049 }
1050 }
1051
files_selection_changed_cb(GtkTreeSelection * selection,gpointer data)1052 static void files_selection_changed_cb(GtkTreeSelection * selection, gpointer data) {
1053
1054 struct control * cp = (struct control *)data;
1055
1056 GtkTreeIter iter;
1057 GtkTreeModel * model;
1058 gchar * filename;
1059
1060 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
1061 gtk_tree_model_get(model, &iter, 1, &filename, -1);
1062 if (g_file_test(filename, G_FILE_TEST_IS_DIR)) {
1063 load_files(cp->store_files, filename);
1064 /* clear bookmark selection so it is clickable again
1065 * for fast upwards navigation */
1066 gtk_tree_selection_unselect_all(
1067 gtk_tree_view_get_selection(GTK_TREE_VIEW(cp->tree_bookmarks)));
1068 } else {
1069 gui_load_sndfile(cp, filename);
1070 }
1071 g_free(filename);
1072 }
1073 }
1074
tree_view_realized_cb(GtkWidget * widget,gpointer data)1075 static void tree_view_realized_cb(GtkWidget * widget, gpointer data) {
1076
1077 struct control * cp = (struct control *)data;
1078
1079 if (widget == cp->tree_bookmarks) {
1080 cp->bookmarks_realized = 1;
1081 } else if (widget == cp->tree_files) {
1082 cp->files_realized = 1;
1083 }
1084
1085 if (cp->bookmarks_realized && cp->files_realized && cp->ir->source_path) {
1086 /* select appropriate entries if plugin loaded */
1087 char * dirpath = g_path_get_dirname(cp->ir->source_path);
1088 load_files(cp->store_files, dirpath);
1089
1090 GtkTreeSelection * select =
1091 gtk_tree_view_get_selection(GTK_TREE_VIEW(cp->tree_bookmarks));
1092 g_signal_handler_block(select, cp->bookmarks_sel_cbid);
1093 select_entry(cp->model_bookmarks, select, dirpath);
1094 g_signal_handler_unblock(select, cp->bookmarks_sel_cbid);
1095
1096 select = gtk_tree_view_get_selection(GTK_TREE_VIEW(cp->tree_files));
1097 g_signal_handler_block(select, cp->files_sel_cbid);
1098 select_entry(GTK_TREE_MODEL(cp->store_files), select, cp->ir->source_path);
1099 g_signal_handler_unblock(select, cp->files_sel_cbid);
1100
1101 g_free(dirpath);
1102
1103 refresh_gui_on_load(cp);
1104 }
1105 }
1106
make_lists_box(struct control * cp)1107 static GtkWidget * make_lists_box(struct control * cp) {
1108
1109 GtkWidget * hbox = gtk_hbox_new(FALSE, 0);
1110 GtkWidget * vbox = gtk_vbox_new(FALSE, 0);
1111
1112 GtkTreeModel * model = GTK_TREE_MODEL(cp->ir->store_bookmarks);
1113 cp->model_bookmarks = gtk_tree_model_sort_new_with_model(model);
1114 cp->tree_bookmarks = gtk_tree_view_new_with_model(cp->model_bookmarks);
1115 g_signal_connect(G_OBJECT(cp->tree_bookmarks), "realize",
1116 G_CALLBACK(tree_view_realized_cb), cp);
1117 GtkWidget * scroll_win = gtk_scrolled_window_new(NULL, NULL);
1118 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_win),
1119 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
1120 gtk_container_add(GTK_CONTAINER(scroll_win), cp->tree_bookmarks);
1121 gtk_box_pack_start(GTK_BOX(vbox), scroll_win, TRUE, TRUE, 0);
1122
1123 GtkCellRenderer * renderer;
1124 GtkTreeViewColumn * column;
1125 GtkTreeSelection * select_b;
1126 renderer = gtk_cell_renderer_text_new();
1127 g_object_set(renderer, "scale", 0.8, NULL);
1128 g_object_set(renderer, "scale-set", TRUE, NULL);
1129 column = gtk_tree_view_column_new_with_attributes("Bookmarks", renderer, "text", 0, NULL);
1130 gtk_tree_view_column_set_sort_column_id(column, 0);
1131 gtk_tree_view_column_set_sort_indicator(column, TRUE);
1132 gtk_tree_view_column_set_sort_order(column, GTK_SORT_ASCENDING);
1133 gtk_tree_view_append_column(GTK_TREE_VIEW(cp->tree_bookmarks), column);
1134 gtk_tree_view_column_clicked(column);
1135
1136 select_b = gtk_tree_view_get_selection(GTK_TREE_VIEW(cp->tree_bookmarks));
1137 gtk_tree_selection_set_mode(select_b, GTK_SELECTION_SINGLE);
1138 cp->bookmarks_sel_cbid =
1139 g_signal_connect(G_OBJECT(select_b), "changed",
1140 G_CALLBACK(bookmarks_selection_changed_cb), cp);
1141
1142 GtkWidget * hbox_1 = gtk_hbox_new(TRUE, PAD);
1143 gtk_box_pack_start(GTK_BOX(vbox), hbox_1, FALSE, FALSE, PAD);
1144
1145 GtkWidget * button = gtk_button_new_with_label("Add...");
1146 g_signal_connect(G_OBJECT(button), "clicked",
1147 G_CALLBACK(add_bookmark_button_clicked), cp);
1148 gtk_box_pack_start(GTK_BOX(hbox_1), button, TRUE, TRUE, PAD);
1149
1150 button = gtk_button_new_with_label("Remove");
1151 g_signal_connect(G_OBJECT(button), "clicked",
1152 G_CALLBACK(del_bookmark_button_clicked), cp);
1153 gtk_box_pack_start(GTK_BOX(hbox_1), button, TRUE, TRUE, PAD);
1154
1155 gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, PAD);
1156
1157 vbox = gtk_vbox_new(FALSE, 0);
1158
1159 cp->store_files = gtk_list_store_new(2,
1160 G_TYPE_STRING, /* visible name (key) */
1161 G_TYPE_STRING); /* full pathname (value) */
1162 cp->tree_files = gtk_tree_view_new_with_model(GTK_TREE_MODEL(cp->store_files));
1163 g_signal_connect(G_OBJECT(cp->tree_files), "realize",
1164 G_CALLBACK(tree_view_realized_cb), cp);
1165 scroll_win = gtk_scrolled_window_new(NULL, NULL);
1166 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_win),
1167 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
1168 gtk_container_add(GTK_CONTAINER(scroll_win), cp->tree_files);
1169 gtk_box_pack_start(GTK_BOX(vbox), scroll_win, TRUE, TRUE, 0);
1170
1171 renderer = gtk_cell_renderer_text_new();
1172 g_object_set(renderer, "scale", 0.8, NULL);
1173 g_object_set(renderer, "scale-set", TRUE, NULL);
1174 column = gtk_tree_view_column_new_with_attributes("Files", renderer, "text", 0, NULL);
1175 gtk_tree_view_column_set_sort_column_id(column, 0);
1176 gtk_tree_view_column_set_sort_indicator(column, TRUE);
1177 gtk_tree_view_column_set_sort_order(column, GTK_SORT_ASCENDING);
1178 gtk_tree_view_append_column(GTK_TREE_VIEW(cp->tree_files), column);
1179 gtk_tree_view_column_clicked(column);
1180 GtkTreeSelection * select_f;
1181 select_f = gtk_tree_view_get_selection(GTK_TREE_VIEW(cp->tree_files));
1182 gtk_tree_selection_set_mode(select_f, GTK_SELECTION_SINGLE);
1183 cp->files_sel_cbid =
1184 g_signal_connect(G_OBJECT(select_f), "changed",
1185 G_CALLBACK(files_selection_changed_cb), cp);
1186
1187 GtkWidget * browse_button = gtk_button_new_with_label("Open File...");
1188 gtk_box_pack_start(GTK_BOX(vbox), browse_button, FALSE, FALSE, PAD);
1189 g_signal_connect(G_OBJECT(browse_button), "clicked",
1190 G_CALLBACK(browse_button_clicked), cp);
1191 gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, PAD);
1192
1193 return hbox;
1194 }
1195
reinit_thread(gpointer data)1196 static gpointer reinit_thread(gpointer data) {
1197 struct control * cp = (struct control*)data;
1198 if (cp->ir->resample_pending) {
1199 int r = cp->ir->resample_init(cp->ir);
1200 if (r == 0) {
1201 while (r == 0) {
1202 r = cp->ir->resample_do(cp->ir);
1203 if (cp->interrupt_threads) {
1204 break;
1205 }
1206 }
1207 cp->ir->resample_cleanup(cp->ir);
1208 }
1209 cp->ir->resample_pending = 0;
1210 }
1211 cp->ir->prepare_convdata(cp->ir);
1212 cp->ir->init_conv(cp->ir);
1213 cp->ir->reinit_pending = 0;
1214 cp->ir->reinit_running = 0;
1215 return NULL;
1216 }
1217
reinit_timeout_callback(gpointer data)1218 static gint reinit_timeout_callback(gpointer data) {
1219 struct control * cp = (struct control*)data;
1220 if (!cp->ir->ir_samples || !cp->ir->ir_nfram) {
1221 ir_wavedisplay_set_message(IR_WAVEDISPLAY(cp->wave_display), NULL);
1222 cp->reinit_timeout_tag = 0;
1223 return FALSE;
1224 }
1225 if (cp->ir->reinit_running) {
1226 if (cp->ir->resample_pending) {
1227 ir_wavedisplay_set_progress(IR_WAVEDISPLAY(cp->wave_display),
1228 cp->ir->src_progress);
1229 }
1230 return TRUE;
1231 }
1232 g_thread_join(cp->reinit_thread);
1233 cp->reinit_thread = NULL;
1234 ir_wavedisplay_set_progress(IR_WAVEDISPLAY(cp->wave_display), -1.0);
1235 ir_wavedisplay_set_message(IR_WAVEDISPLAY(cp->wave_display), NULL);
1236 ir_wavedisplay_set_wave(IR_WAVEDISPLAY(cp->wave_display),
1237 cp->ir->ir_samples[cp->disp_chan],
1238 cp->ir->ir_nfram);
1239 reset_values(cp);
1240 cp->reinit_timeout_tag = 0;
1241 return FALSE;
1242 }
1243
timeout_callback(gpointer data)1244 static gint timeout_callback(gpointer data) {
1245 struct control * cp = (struct control*)data;
1246 if (cp->interrupt_threads) {
1247 cp->timeout_tag = 0;
1248 return FALSE;
1249 }
1250 if (cp->ir->reinit_running) {
1251 return TRUE;
1252 }
1253 if (cp->ir->run && cp->ir->reinit_pending) {
1254 if (cp->ir->resample_pending) {
1255 ir_wavedisplay_set_progress(IR_WAVEDISPLAY(cp->wave_display), 0.0);
1256 }
1257 ir_wavedisplay_set_message(IR_WAVEDISPLAY(cp->wave_display), "Calculating...");
1258 cp->ir->reinit_running = 1;
1259 cp->reinit_thread = g_thread_new("reinit_thread", reinit_thread, cp);
1260 cp->reinit_timeout_tag = g_timeout_add(100, reinit_timeout_callback, cp);
1261 cp->ir->run = 0;
1262 }
1263 return TRUE;
1264 }
1265
chan_toggle_cb(GtkWidget * widget,gpointer data)1266 static void chan_toggle_cb(GtkWidget * widget, gpointer data) {
1267
1268 struct control * cp = (struct control *)data;
1269 int i;
1270 for (i = 0; i < 4; i++) {
1271 if (widget == cp->chan_toggle[i]) {
1272 break;
1273 }
1274 }
1275 if (cp->ir->reinit_running) {
1276 g_signal_handler_block(widget, cp->chan_toggle_cbid[i]);
1277 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
1278 !(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))));
1279 g_signal_handler_unblock(widget, cp->chan_toggle_cbid[i]);
1280 return;
1281 }
1282 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
1283 for (int j = 0; j < 4; j++) {
1284 if (i != j) {
1285 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cp->chan_toggle[j]), FALSE);
1286 }
1287 }
1288 cp->disp_chan = i;
1289 if (cp->ir->ir_nfram) {
1290 ir_wavedisplay_set_wave(IR_WAVEDISPLAY(cp->wave_display),
1291 cp->ir->ir_samples[i], cp->ir->ir_nfram);
1292 }
1293 }
1294 }
1295
log_toggle_cb(GtkWidget * widget,gpointer data)1296 static void log_toggle_cb(GtkWidget * widget, gpointer data) {
1297 struct control * cp = (struct control *)data;
1298 if (cp->ir->reinit_running) {
1299 g_signal_handler_block(widget, cp->log_toggle_cbid);
1300 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
1301 !(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))));
1302 g_signal_handler_unblock(widget, cp->log_toggle_cbid);
1303 return;
1304 }
1305 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
1306 gtk_button_set_label(GTK_BUTTON(widget), " log ");
1307 ir_wavedisplay_set_logarithmic(IR_WAVEDISPLAY(cp->wave_display), 1);
1308 } else {
1309 gtk_button_set_label(GTK_BUTTON(widget), " lin ");
1310 ir_wavedisplay_set_logarithmic(IR_WAVEDISPLAY(cp->wave_display), 0);
1311 }
1312 }
1313
about_button_cb(GtkWidget * about_button,gpointer data)1314 static void about_button_cb(GtkWidget * about_button, gpointer data) {
1315
1316 GtkWidget * dialog;
1317 GtkWidget * frame = gtk_frame_new(NULL);
1318 GtkWidget * label = gtk_label_new("");
1319 GtkWidget * content_area;
1320
1321 dialog = gtk_dialog_new_with_buttons("About IR",
1322 NULL,
1323 GTK_DIALOG_DESTROY_WITH_PARENT,
1324 GTK_STOCK_OK,
1325 GTK_RESPONSE_NONE,
1326 NULL);
1327 content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1328
1329 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
1330 gtk_label_set_markup(GTK_LABEL(label),
1331 "<span size=\"x-large\" weight=\"heavy\">"
1332 "IR</span><span size=\"x-large\">: LV2 Convolution Reverb\n"
1333 "</span>"
1334 S1 "version 1.3.2" S2
1335 "\n\nCopyright (C) 2011-2012 <b>Tom Szilagyi</b>\n"
1336 XS1 "\nIR is free software under the GNU GPL. There is ABSOLUTELY\n"
1337 "NO WARRANTY, not even for MERCHANTABILITY or FITNESS\n"
1338 "FOR A PARTICULAR PURPOSE." XS2 "\n\n"
1339 "<small>Homepage: <b>http://tomszilagyi.github.io/plugins/ir.lv2</b></small>");
1340 gtk_label_set_selectable(GTK_LABEL(label), TRUE);
1341 gtk_container_add(GTK_CONTAINER(frame), label);
1342 gtk_container_set_border_width(GTK_CONTAINER(frame), 2*PAD);
1343
1344 g_signal_connect_swapped(dialog, "response",
1345 G_CALLBACK(gtk_widget_destroy),
1346 dialog);
1347
1348 gtk_container_add(GTK_CONTAINER(content_area), frame);
1349 gtk_container_set_border_width(GTK_CONTAINER(dialog), 2*PAD);
1350 gtk_widget_show_all(dialog);
1351 }
1352
make_top_hbox(struct control * cp)1353 static GtkWidget * make_top_hbox(struct control * cp) {
1354 GtkWidget * hbox = gtk_hbox_new(FALSE, PAD);
1355 GtkWidget * frame = gtk_frame_new(NULL);
1356 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
1357 gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, PAD);
1358 GtkWidget * vbox = gtk_vbox_new(FALSE, 0);
1359 gtk_container_add(GTK_CONTAINER(frame), vbox);
1360
1361 GtkWidget * hbox_wave = gtk_hbox_new(FALSE, PAD);
1362 gtk_box_pack_start(GTK_BOX(vbox), hbox_wave, TRUE, TRUE, PAD);
1363
1364 GtkWidget * vbox_toggle = gtk_vbox_new(TRUE, 0);
1365 gtk_box_pack_start(GTK_BOX(hbox_wave), vbox_toggle, FALSE, TRUE, PAD);
1366
1367 for (int i = 0; i < 4; i++) {
1368 char str[4];
1369 snprintf(str, 4, " %d ", i+1);
1370 cp->chan_toggle[i] = gtk_toggle_button_new_with_label(str);
1371 cp->chan_toggle_cbid[i] = g_signal_connect(cp->chan_toggle[i], "toggled",
1372 G_CALLBACK(chan_toggle_cb), cp);
1373 gtk_box_pack_start(GTK_BOX(vbox_toggle), cp->chan_toggle[i], TRUE, TRUE, PAD);
1374 gtk_widget_set_sensitive(cp->chan_toggle[i], FALSE);
1375 }
1376
1377 cp->wave_display = ir_wavedisplay_new();
1378 gtk_box_pack_start(GTK_BOX(hbox_wave), cp->wave_display, TRUE, TRUE, 0);
1379
1380 cp->mode_ind = ir_modeind_new();
1381 gtk_widget_set_size_request(cp->mode_ind, 100, -1);
1382 gtk_box_pack_start(GTK_BOX(hbox_wave), cp->mode_ind, FALSE, FALSE, PAD);
1383
1384 GtkWidget * hbox2 = gtk_hbox_new(FALSE, PAD);
1385 gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, PAD);
1386
1387 cp->log_toggle = gtk_toggle_button_new_with_label(" lin ");
1388 cp->log_toggle_cbid = g_signal_connect(cp->log_toggle, "toggled",
1389 G_CALLBACK(log_toggle_cb), cp);
1390 gtk_widget_set_size_request(cp->log_toggle, 50, -1);
1391 gtk_box_pack_start(GTK_BOX(hbox2), cp->log_toggle, FALSE, TRUE, PAD);
1392
1393 cp->wave_annot_label = gtk_label_new("");
1394 gtk_misc_set_alignment(GTK_MISC(cp->wave_annot_label), 0.0f, 0.5f);
1395 gtk_box_pack_start(GTK_BOX(hbox2), cp->wave_annot_label, TRUE, TRUE, PAD);
1396
1397 GtkWidget * about_button = gtk_button_new_with_label(" About ");
1398 g_signal_connect(about_button, "clicked",
1399 G_CALLBACK(about_button_cb), cp);
1400 gtk_box_pack_start(GTK_BOX(hbox2), about_button, FALSE, TRUE, PAD);
1401
1402 return hbox;
1403 }
1404
make_gui_proper(struct control * cp)1405 static void make_gui_proper(struct control * cp) {
1406
1407 GtkWidget * vbox_top = cp->vbox_top;
1408
1409 cp->toggle_reverse = gtk_toggle_button_new_with_label("Reverse");
1410 cp->toggle_reverse_cbid = g_signal_connect(cp->toggle_reverse, "toggled",
1411 G_CALLBACK(toggle_button_cb), cp);
1412
1413 /* upper half */
1414 gtk_box_pack_start(GTK_BOX(vbox_top), make_top_hbox(cp), TRUE, TRUE, PAD);
1415
1416 GtkWidget * hbox = gtk_hbox_new(FALSE, PAD);
1417 gtk_box_pack_start(GTK_BOX(vbox_top), hbox, TRUE, TRUE, 0);
1418
1419 GtkWidget * hpaned = gtk_hpaned_new();
1420 GtkWidget * hbox_1 = gtk_hbox_new(FALSE, PAD);
1421 gtk_paned_pack1(GTK_PANED(hpaned), hbox_1, TRUE, TRUE);
1422 gtk_box_pack_start(GTK_BOX(hbox_1), make_lists_box(cp), TRUE, TRUE, 0);
1423
1424 GtkWidget * hbox_2 = gtk_hbox_new(FALSE, 0);
1425 gtk_paned_pack2(GTK_PANED(hpaned), hbox_2, TRUE, FALSE);
1426 GtkWidget * vbox = gtk_vbox_new(FALSE, 0);
1427 gtk_box_pack_start(GTK_BOX(vbox), make_irctrl_frame(cp), TRUE, TRUE, 0);
1428 gtk_box_pack_start(GTK_BOX(vbox), cp->toggle_reverse, FALSE, TRUE, PAD);
1429 gtk_box_pack_start(GTK_BOX(hbox_2), vbox, TRUE, TRUE, PAD);
1430 gtk_box_pack_start(GTK_BOX(hbox_2), make_mixer_frame(cp), FALSE, TRUE, PAD);
1431
1432 gtk_box_pack_start(GTK_BOX(hbox), hpaned, TRUE, TRUE, 0);
1433
1434 cp->timeout_tag = g_timeout_add(100, timeout_callback, cp);
1435
1436 gtk_widget_show_all(vbox_top);
1437 }
1438
1439 static void port_event(LV2UI_Handle ui, uint32_t port_index, uint32_t buffer_size,
1440 uint32_t format, const void * buffer);
1441
replay_func(gpointer data,gpointer user_data)1442 static void replay_func(gpointer data, gpointer user_data) {
1443 port_event_t * pe = (port_event_t *)data;
1444 struct control * cp = (struct control*)user_data;
1445 port_event((LV2UI_Handle)cp, pe->port_index, 0, 0, &pe->value);
1446 free(pe);
1447 }
1448
replay_port_events(struct control * cp)1449 static void replay_port_events(struct control * cp) {
1450 GSList * q = cp->port_event_q;
1451 g_slist_foreach(q, replay_func, cp);
1452 g_slist_free(q);
1453 }
1454
waitplugin_timeout_callback(gpointer data)1455 static gint waitplugin_timeout_callback(gpointer data) {
1456 struct control * cp = (struct control*)data;
1457 if (cp->ir->first_conf_done) {
1458 gtk_widget_destroy(cp->hbox_waitplugin);
1459 make_gui_proper(cp);
1460 replay_port_events(cp);
1461 cp->waitplugin_timeout_tag = 0;
1462 return FALSE;
1463 }
1464 if (cp->interrupt_threads) {
1465 cp->waitplugin_timeout_tag = 0;
1466 return FALSE;
1467 }
1468 return TRUE;
1469 }
1470
make_gui(struct control * cp)1471 static GtkWidget * make_gui(struct control * cp) {
1472
1473 cp->toggle_reverse = gtk_toggle_button_new_with_label("Reverse");
1474 g_signal_connect(cp->toggle_reverse, "toggled",
1475 G_CALLBACK(toggle_button_cb), cp);
1476
1477 cp->vbox_top = gtk_vbox_new(FALSE, PAD);
1478
1479 if (cp->ir->first_conf_done) {
1480 make_gui_proper(cp);
1481 } else {
1482 cp->hbox_waitplugin = gtk_hbox_new(FALSE, PAD);
1483 gtk_box_pack_start(GTK_BOX(cp->vbox_top), cp->hbox_waitplugin, TRUE, TRUE, PAD);
1484 #ifdef _HAVE_GTK_ATLEAST_2_20
1485 GtkWidget * spinner = gtk_spinner_new();
1486 gtk_spinner_start(GTK_SPINNER(spinner));
1487 gtk_box_pack_start(GTK_BOX(cp->hbox_waitplugin), spinner, TRUE, TRUE, PAD);
1488 #endif /* _HAVE_GTK_ATLEAST_2_20 */
1489 GtkWidget * label = gtk_label_new("");
1490 gtk_label_set_markup(GTK_LABEL(label),
1491 "<span size=\"large\" weight=\"bold\">"
1492 " Please wait while plugin is initialised... "
1493 "</span>\n"
1494 XS1 " If the plugin is in BYPASS (Deactivated), please un-BYPASS (Activate) it." XS2);
1495 gtk_box_pack_start(GTK_BOX(cp->hbox_waitplugin), label, TRUE, TRUE, PAD);
1496 cp->waitplugin_timeout_tag = g_timeout_add(100, waitplugin_timeout_callback, cp);
1497 gtk_widget_show_all(cp->vbox_top);
1498 }
1499 return cp->vbox_top;
1500 }
1501
1502 /* join any threads and wait for timeouts to exit */
join_timeouts(struct control * cp)1503 static void join_timeouts(struct control * cp) {
1504 cp->interrupt_threads = 1;
1505 while (cp->timeout_tag ||
1506 cp->gui_load_timeout_tag ||
1507 cp->reinit_timeout_tag ||
1508 cp->waitplugin_timeout_tag) {
1509
1510 gtk_main_iteration_do(FALSE);
1511 }
1512 }
1513
cleanup(LV2UI_Handle ui)1514 static void cleanup(LV2UI_Handle ui) {
1515 //printf("cleanup()\n");
1516 struct control * cp = (struct control *)ui;
1517
1518 join_timeouts(cp);
1519 if (cp->store_files) {
1520 g_object_unref(cp->store_files);
1521 cp->store_files = 0;
1522 }
1523 free(cp);
1524 }
1525
instantiate(const struct 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)1526 static LV2UI_Handle instantiate(const struct LV2UI_Descriptor * descriptor,
1527 const char * plugin_uri,
1528 const char * bundle_path,
1529 LV2UI_Write_Function write_function,
1530 LV2UI_Controller controller,
1531 LV2UI_Widget * widget,
1532 const LV2_Feature * const * features) {
1533
1534 int instance_access_found = 0;
1535 struct control * cp;
1536 //printf("instantiate('%s', '%s') called\n", plugin_uri, bundle_path);
1537
1538 if (strcmp(plugin_uri, IR_URI) != 0) {
1539 fprintf(stderr, "IR_UI error: this GUI does not support plugin with URI %s\n", plugin_uri);
1540 goto fail;
1541 }
1542
1543 cp = (struct control*)calloc(1, sizeof(struct control));
1544 if (cp == NULL) {
1545 goto fail;
1546 }
1547
1548 if (features != NULL) {
1549 int i = 0;
1550 while (features[i] != NULL) {
1551 if (strcmp(features[i]->URI, LV2_INSTANCE_ACCESS_URI) == 0) {
1552 cp->ir = (IR *)(features[i]->data);
1553 instance_access_found = 1;
1554 }
1555 ++i;
1556 }
1557 if (!instance_access_found) {
1558 goto fail_free;
1559 }
1560 } else {
1561 goto fail_free;
1562 }
1563
1564 if (cp->ir == NULL) {
1565 goto fail_free;
1566 }
1567
1568 cp->controller = controller;
1569 cp->write_function = write_function;
1570
1571 *widget = (LV2UI_Widget)make_gui(cp);
1572 return (LV2UI_Handle)cp;
1573
1574 fail_free:
1575 if (!instance_access_found) {
1576 fprintf(stderr, "IR UI: error: required LV2 feature %s missing!\n", LV2_INSTANCE_ACCESS_URI);
1577 }
1578
1579 free(cp);
1580 fail:
1581 return NULL;
1582 }
1583
port_event(LV2UI_Handle ui,uint32_t port_index,uint32_t buffer_size,uint32_t format,const void * buffer)1584 static void port_event(LV2UI_Handle ui,
1585 uint32_t port_index,
1586 uint32_t buffer_size,
1587 uint32_t format,
1588 const void * buffer) {
1589
1590 struct control * cp = (struct control *)ui;
1591 float * pval = (float *)buffer;
1592 //printf("port_event(%u, %f) called\n", (unsigned int)port_index, *(float *)buffer);
1593
1594 if (format != 0) {
1595 return;
1596 }
1597
1598 if ((port_index < 0) || (port_index >= IR_N_PORTS)) {
1599 return;
1600 }
1601
1602 if (!set_port_value(cp, port_index, *pval)) {
1603 return;
1604 }
1605 cp->port_buffer[port_index] = *pval;
1606
1607 if (!cp->ir->first_conf_done) {
1608 port_event_t * pe = (port_event_t *)malloc(sizeof(port_event_t));
1609 pe->port_index = port_index;
1610 pe->value = *pval;
1611 cp->port_event_q = g_slist_prepend(cp->port_event_q, pe);
1612 return;
1613 }
1614
1615 int update_ui = 0;
1616 if (port_index == IR_PORT_REVERSE) {
1617 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cp->toggle_reverse),
1618 (*pval > 0.0f));
1619 update_ui = 1;
1620 } else if (port_index == IR_PORT_PREDELAY) {
1621 cp->predelay = *pval;
1622 set_adjustment(cp, cp->adj_predelay, *pval);
1623 update_ui = 1;
1624 } else if (port_index == IR_PORT_ATTACK) {
1625 cp->attack = *pval;
1626 set_adjustment(cp, cp->adj_attack, *pval);
1627 update_ui = 1;
1628 } else if (port_index == IR_PORT_ATTACKTIME) {
1629 cp->attacktime = *pval;
1630 set_adjustment(cp, cp->adj_attacktime, *pval);
1631 update_ui = 1;
1632 } else if (port_index == IR_PORT_ENVELOPE) {
1633 cp->envelope = *pval;
1634 set_adjustment(cp, cp->adj_envelope, *pval);
1635 update_ui = 1;
1636 } else if (port_index == IR_PORT_LENGTH) {
1637 cp->length = *pval;
1638 set_adjustment(cp, cp->adj_length, *pval);
1639 update_ui = 1;
1640 } else if (port_index == IR_PORT_STRETCH) {
1641 cp->stretch = *pval;
1642 set_adjustment(cp, cp->adj_stretch, *pval);
1643 update_ui = 1;
1644 } else if (port_index == IR_PORT_STEREO_IN) {
1645 set_adjustment(cp, cp->adj_stereo_in, *pval);
1646 } else if (port_index == IR_PORT_STEREO_IR) {
1647 cp->stereo_ir = *pval;
1648 set_adjustment(cp, cp->adj_stereo_ir, *pval);
1649 } else if (port_index == IR_PORT_AGC_SW) {
1650 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cp->toggle_agc_sw),
1651 (*pval > 0.0f));
1652 } else if (port_index == IR_PORT_DRY_SW) {
1653 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cp->toggle_dry_sw),
1654 (*pval > 0.0f));
1655 } else if (port_index == IR_PORT_DRY_GAIN) {
1656 set_adjustment(cp, cp->adj_dry_gain, *pval);
1657 } else if (port_index == IR_PORT_WET_SW) {
1658 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cp->toggle_wet_sw),
1659 (*pval > 0.0f));
1660 } else if (port_index == IR_PORT_WET_GAIN) {
1661 set_adjustment(cp, cp->adj_wet_gain, *pval);
1662 } else if (port_index == IR_PORT_FHASH_0) { /* NOP: plugin itself handles IR loading on session resume */
1663 } else if (port_index == IR_PORT_FHASH_1) { /* NOP */
1664 } else if (port_index == IR_PORT_FHASH_2) { /* NOP */
1665 } else if (port_index == IR_PORT_METER_DRY_L) {
1666 ir_meter_set_level(IR_METER(cp->meter_L_dry), convert_real_to_scale(ADJ_DRY_GAIN, CO_DB(*pval)));
1667 } else if (port_index == IR_PORT_METER_DRY_R) {
1668 ir_meter_set_level(IR_METER(cp->meter_R_dry), convert_real_to_scale(ADJ_DRY_GAIN, CO_DB(*pval)));
1669 } else if (port_index == IR_PORT_METER_WET_L) {
1670 ir_meter_set_level(IR_METER(cp->meter_L_wet), convert_real_to_scale(ADJ_WET_GAIN, CO_DB(*pval)));
1671 } else if (port_index == IR_PORT_METER_WET_R) {
1672 ir_meter_set_level(IR_METER(cp->meter_R_wet), convert_real_to_scale(ADJ_WET_GAIN, CO_DB(*pval)));
1673 }
1674
1675 if (update_ui) {
1676 update_envdisplay(cp);
1677 }
1678 }
1679
1680 static LV2UI_Descriptor descriptors[] = {
1681 {IR_UI_URI, instantiate, cleanup, port_event, NULL}
1682 };
1683
lv2ui_descriptor(uint32_t index)1684 const LV2UI_Descriptor * lv2ui_descriptor(uint32_t index) {
1685 //printf("lv2ui_descriptor(%u) called\n", (unsigned int)index);
1686 if (index >= sizeof(descriptors) / sizeof(descriptors[0])) {
1687 return NULL;
1688 }
1689 return descriptors + index;
1690 }
1691