3 // shared between parent/child fork
5 #include "pluginlv2ui.h"
13 int PluginLV2UI::init_ui(const char *path, int sample_rate)
15 if( load_lv2(path, title) ) return 1;
16 if( init_lv2(config, sample_rate) ) return 1;
18 lilv_uis = lilv_plugin_get_uis(lilv);
20 printf("lv2: lilv_plugin_get_uis(%s) failed\n", path);
25 LilvNode *gui_type = lilv_new_uri(world, gtk_type);
26 LILV_FOREACH(uis, i, lilv_uis) {
27 const LilvUI *ui = lilv_uis_get(lilv_uis, i);
28 if( lilv_ui_is_supported(ui, suil_ui_supported, gui_type, &lilv_type)) {
33 lilv_node_free(gui_type);
36 lilv_ui = lilv_uis_get(lilv_uis, lilv_uis_begin(lilv_uis));
38 printf("lv2_gui: init_ui failed: %s\n", title);
42 lilv_instance_activate(inst);
46 void PluginLV2UI::update_value(int idx, uint32_t bfrsz, uint32_t typ, const void *bfr)
48 if( idx >= config.nb_ports ) return;
49 for( int i=0, sz=config.size(); i<sz; ++i ) {
50 PluginLV2Client_Opt *opt = config[i];
51 if( opt->idx == idx ) {
52 opt->set_value(*(const float*)bfr);
53 updates = UPDATE_HOST;
58 void PluginLV2UI::write_from_ui(void *the, uint32_t idx,
59 uint32_t bfrsz, uint32_t typ, const void *bfr)
61 ((PluginLV2UI*)the)->update_value(idx, bfrsz, typ, bfr);
64 uint32_t PluginLV2UI::port_index(void* obj, const char* sym)
66 PluginLV2UI *the = (PluginLV2UI*)obj;
67 for( int i=0, sz=the->config.size(); i<sz; ++i ) {
68 PluginLV2Client_Opt *opt = the->config[i];
69 if( !strcmp(sym, opt->sym) ) return opt->idx;
74 void PluginLV2UI::update_control(int idx, uint32_t bfrsz, uint32_t typ, const void *bfr)
76 if( !sinst || idx >= config.nb_ports ) return;
77 suil_instance_port_event(sinst, idx, bfrsz, typ, bfr);
82 void PluginLV2UI::touch(void *obj, uint32_t pidx, bool grabbed)
84 PluginLV2UI* the = (PluginLV2GUI*)obj;
86 if( idx >= the->config.nb_ports ) return;
87 printf("%s %s(%u)\n", (grabbed? _("press") : _("release")),
88 the->config.names[idx], idx);
92 uint32_t PluginLV2UI::uri_to_id(LV2_URID_Map_Handle handle, const char *map, const char *uri)
94 return ((PluginLV2UriTable *)handle)->map(uri);
97 LV2_URID PluginLV2UI::uri_table_map(LV2_URID_Map_Handle handle, const char *uri)
99 return ((PluginLV2UriTable *)handle)->map(uri);
102 const char *PluginLV2UI::uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
104 return ((PluginLV2UriTable *)handle)->unmap(urid);
107 void PluginLV2UI::lv2ui_instantiate(void *parent)
110 ui_host = suil_host_new(
111 PluginLV2UI::write_from_ui,
112 PluginLV2UI::port_index,
114 // suil_host_set_touch_func(ui_host,
115 // PluginLV2GUI::touch);
118 features.remove(); // remove terminating zero
119 ui_features = features.size();
120 LV2_Handle lilv_handle = lilv_instance_get_handle(inst);
121 features.append(new Lv2Feature(NS_EXT "instance-access", lilv_handle));
122 const LV2_Descriptor *lilv_desc = lilv_instance_get_descriptor(inst);
123 ext_data = new LV2_Extension_Data_Feature();
124 ext_data->data_access = lilv_desc->extension_data;
125 features.append(new Lv2Feature(LV2_DATA_ACCESS_URI, ext_data));
126 features.append(new Lv2Feature(LV2_UI__parent, parent));
127 features.append(new Lv2Feature(LV2_UI__idleInterface, 0));
128 features.append(0); // add new terminating zero
130 const char* bundle_uri = lilv_node_as_uri(lilv_ui_get_bundle_uri(lilv_ui));
131 char* bundle_path = lilv_file_uri_parse(bundle_uri, NULL);
132 const char* binary_uri = lilv_node_as_uri(lilv_ui_get_binary_uri(lilv_ui));
133 char* binary_path = lilv_file_uri_parse(binary_uri, NULL);
134 sinst = suil_instance_new(ui_host, this, gtk_type,
135 lilv_node_as_uri(lilv_plugin_get_uri(lilv)),
136 lilv_node_as_uri(lilv_ui_get_uri(lilv_ui)),
137 lilv_node_as_uri(lilv_type),
138 bundle_path, binary_path, features);
140 lilv_free(binary_path);
141 lilv_free(bundle_path);
144 bool PluginLV2UI::lv2ui_resizable()
146 if( !lilv_ui ) return false;
147 const LilvNode* s = lilv_ui_get_uri(lilv_ui);
148 LilvNode *p = lilv_new_uri(world, LV2_CORE__optionalFeature);
149 LilvNode *fs = lilv_new_uri(world, LV2_UI__fixedSize);
150 LilvNode *nrs = lilv_new_uri(world, LV2_UI__noUserResize);
151 LilvNodes *fs_matches = lilv_world_find_nodes(world, s, p, fs);
152 LilvNodes *nrs_matches = lilv_world_find_nodes(world, s, p, nrs);
153 lilv_nodes_free(nrs_matches);
154 lilv_nodes_free(fs_matches);
158 return !fs_matches && !nrs_matches;
161 int PluginLV2UI::send_host(int64_t token, const void *data, int bytes)
163 return !child ? 0 : child->send_parent(token, data, bytes);
166 int PluginLV2UI::update_lv2_input(float *vals, int force)
169 float *ctls = config.ctls;
170 for( int i=0; i<config.size(); ++i ) {
171 int idx = config[i]->idx;
172 float val = vals[idx];
173 if( !force && ctls[idx] == val ) continue;
175 update_control(idx, sizeof(ctls[idx]), 0, &ctls[idx]);
181 void PluginLV2UI::update_lv2_output()
183 int *ports = config.ports;
184 float *ctls = config.ctls;
185 for( int i=0; i<config.nb_ports; ++i ) {
186 if( !(ports[i] & PORTS_UPDATE) ) continue;
187 ports[i] &= ~PORTS_UPDATE;
188 update_control(i, sizeof(ctls[i]), 0, &ctls[i]);
192 static void lilv_destroy(GtkWidget* widget, gpointer data)
194 PluginLV2UI *the = (PluginLV2UI*)data;
198 void PluginLV2UI::start_gui()
200 if( !hidden ) return;
201 top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
202 g_signal_connect(top_level, "destroy", G_CALLBACK(lilv_destroy), this);
203 gtk_window_set_title(GTK_WINDOW(top_level), title);
205 GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
206 gtk_window_set_role(GTK_WINDOW(top_level), "plugin_ui");
207 gtk_container_add(GTK_CONTAINER(top_level), vbox);
209 GtkWidget *alignment = gtk_alignment_new(0.5, 0.5, 1.0, 1.0);
210 gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0);
211 gtk_widget_show(alignment);
212 lv2ui_instantiate(alignment);
213 GtkWidget* widget = (GtkWidget*)suil_instance_get_widget(sinst);
214 gtk_container_add(GTK_CONTAINER(alignment), widget);
215 gtk_window_set_resizable(GTK_WINDOW(top_level), lv2ui_resizable());
216 gtk_widget_show_all(vbox);
217 gtk_widget_grab_focus(widget);
218 update_lv2_input(config.ctls, 1);
219 connect_ports(config, PORTS_CONTROL);
222 gtk_window_present(GTK_WINDOW(top_level));
223 send_host(LV2_SHOW, 0, 0);
227 void PluginLV2UI::update_host()
230 if( running < 0 ) { running = 1; return; }
231 send_host(LV2_UPDATE, config.ctls, sizeof(float)*config.nb_ports);
234 void PluginLV2UI::reset_gui()
237 if( sinst ) { suil_instance_free(sinst); sinst = 0; }
238 if( ui_host ) { suil_host_free(ui_host); ui_host = 0; }
239 if( top_level ) { gtk_widget_destroy(top_level); top_level = 0; }
241 while( features.size() > ui_features ) features.remove_object();
244 send_host(LV2_HIDE, 0, 0);
249 int PluginLV2UI::run_ui(PluginLV2ChildUI *child)
255 if( gtk_events_pending() ) {
256 gtk_main_iteration();
259 if( !top_level && !hidden )
262 if( (updates & UPDATE_PORTS) )
264 if( (updates & UPDATE_HOST) )
268 if( !child ) usleep(10000);
269 else if( child->child_iteration() < 0 )
276 void PluginLV2UI::run_lilv(int samples)
278 float ctls[config.nb_ports];
279 for( int i=0; i<config.nb_ports; ++i ) ctls[i] = config.ctls[i];
281 lilv_instance_run(inst, samples);
283 for( int i=0; i<config.nb_ports; ++i ) {
284 if( !(config.ports[i] & PORTS_OUTPUT) ) continue;
285 if( !(config.ports[i] & PORTS_CONTROL) ) continue;
286 if( config.ctls[i] == ctls[i] ) continue;
287 config.ports[i] |= PORTS_UPDATE;
288 updates |= UPDATE_PORTS;
292 void PluginLV2ChildUI::run_buffer(int shmid)
294 if( !shm_buffer(shmid) ) return;
296 connect_ports(config, PORTS_ALL);
297 run_lilv(shm_bfr->samples);
301 int PluginLV2ChildUI::handle_child()
303 switch( child_token ) {
305 open_bfr_t *open_bfr = (open_bfr_t *)child_data;
306 if( init_ui(open_bfr->path, open_bfr->sample_rate) ) exit(1);
309 float *vals = (float *)child_data;
310 update_lv2_input(vals, 1);
313 float *vals = (float *)child_data;
314 update_lv2_input(vals, 0);
323 int shmid = *(int *)child_data;
325 send_parent(LV2_SHMID, 0, 0);
333 #endif /* HAVE_LV2UI */