#ifdef HAVE_LV2UI #include "file.h" #include "language.h" #include "pluginlv2gui.h" #include #include PluginLV2ChildGUI::PluginLV2ChildGUI() { lv2_gui = 0; } PluginLV2ChildGUI::~PluginLV2ChildGUI() { delete lv2_gui; } void PluginLV2ChildGUI::run() { ArrayList av; av.set_array_delete(); char arg[BCTEXTLEN]; const char *exec_path = File::get_cinlib_path(); snprintf(arg, sizeof(arg), "%s/%s", exec_path, "lv2ui"); av.append(cstrdup(arg)); sprintf(arg, "%d", child_fd); av.append(cstrdup(arg)); sprintf(arg, "%d", parent_fd); av.append(cstrdup(arg)); av.append(0); execv(av[0], &av.values[0]); fprintf(stderr, "execv failed: %s\n %m\n", av.values[0]); av.remove_all_objects(); _exit(1); } #define NS_EXT "http://lv2plug.in/ns/ext/" PluginLV2GUI::PluginLV2GUI() { world = 0; lilv = 0; uri_map = 0; ext_data = 0; inst = 0; sinst = 0; ui_host = 0; uis = 0; ui = 0; ui_type = 0; lv2_InputPort = 0; lv2_ControlPort = 0; updates = 0; last = 0; done = 0; running = 0; redraw = 0; // only gtk-2 gtk_type = "http://lv2plug.in/ns/extensions/ui#GtkUI"; } PluginLV2GUI::~PluginLV2GUI () { reset_gui(); if( world ) lilv_world_free(world); } void PluginLV2GUI::reset_gui() { if( inst ) lilv_instance_deactivate(inst); if( uri_map ) { delete uri_map; uri_map = 0; } if( ext_data ) { delete ext_data; ext_data = 0; } if( inst ) { lilv_instance_free(inst); inst = 0; } if( sinst ) { suil_instance_free(sinst); sinst = 0; } if( ui_host ) { suil_host_free(ui_host); ui_host = 0; } if( uis ) { lilv_uis_free(uis); uis = 0; } if( lv2_InputPort ) { lilv_node_free(lv2_InputPort); lv2_InputPort = 0; } if( lv2_ControlPort ) { lilv_node_free(lv2_ControlPort); lv2_ControlPort = 0; } ui_features.remove_all_objects(); uri_table.remove_all_objects(); config.reset(); config.remove_all_objects(); } int PluginLV2GUI::init_gui(const char *path) { reset_gui(); if( !world ) world = lilv_world_new(); if( !world ) { printf("lv2_gui: lilv_world_new failed"); return 1; } lilv_world_load_all(world); LilvNode *uri = lilv_new_uri(world, path); if( !uri ) { printf("lv2_gui: lilv_new_uri(%s) failed", path); return 1; } const LilvPlugins *all_plugins = lilv_world_get_all_plugins(world); lilv = lilv_plugins_get_by_uri(all_plugins, uri); lilv_node_free(uri); if( !lilv ) { printf("lv2_gui: lilv_plugins_get_by_uriPlugin(%s) failed", path); return 1; } LilvNode *name = lilv_plugin_get_name(lilv); const char *nm = lilv_node_as_string(name); snprintf(title,sizeof(title),"L2_%s",nm); lilv_node_free(name); config.init_lv2(lilv); lv2_InputPort = lilv_new_uri(world, LV2_CORE__InputPort); lv2_ControlPort = lilv_new_uri(world, LV2_CORE__ControlPort); for( int i=0; icallback_data = (LV2_URI_Map_Callback_Data)this; uri_map->uri_to_id = uri_to_id; ui_features.append(new Lv2Feature(NS_EXT "uri-map", uri_map)); map.handle = (void*)&uri_table; map.map = uri_table_map; ui_features.append(new Lv2Feature(LV2_URID__map, &map)); unmap.handle = (void*)&uri_table; unmap.unmap = uri_table_unmap; ui_features.append(new Lv2Feature(LV2_URID__unmap, &unmap)); ui_features.append(0); int sample_rate = 64; // cant be too low inst = lilv_plugin_instantiate(lilv, sample_rate, ui_features); if( !inst ) { printf("lv2_gui: lilv_plugin_instantiate failed: %s\n", title); return 1; } uis = lilv_plugin_get_uis(lilv); if( gtk_type ) { LilvNode *gui_type = lilv_new_uri(world, gtk_type); LILV_FOREACH(uis, i, uis) { const LilvUI *gui = lilv_uis_get(uis, i); if( lilv_ui_is_supported(gui, suil_ui_supported, gui_type, &ui_type)) { ui = gui; break; } } lilv_node_free(gui_type); } if( !ui ) ui = lilv_uis_get(uis, lilv_uis_begin(uis)); if( !ui ) { printf("lv2_gui: init_ui failed: %s\n", title); return 1; } lilv_instance_activate(inst); return 0; } void PluginLV2GUI::update_value(int idx, uint32_t bfrsz, uint32_t typ, const void *bfr) { if( idx >= config.nb_ports ) return; for( int i=0, sz=config.size(); iidx == idx ) { opt->set_value(*(const float*)bfr); //printf("set %s = %f\n", opt->get_symbol(), opt->get_value()); ++updates; break; } } } void PluginLV2GUI::write_from_ui(void *the, uint32_t idx, uint32_t bfrsz, uint32_t typ, const void *bfr) { ((PluginLV2GUI*)the)->update_value(idx, bfrsz, typ, bfr); } uint32_t PluginLV2GUI::port_index(void* obj, const char* sym) { PluginLV2GUI *the = (PluginLV2GUI*)obj; for( int i=0, sz=the->config.size(); iconfig[i]; if( !strcmp(sym, opt->sym) ) return opt->idx; } return UINT32_MAX; } void PluginLV2GUI::update_control(int idx, uint32_t bfrsz, uint32_t typ, const void *bfr) { if( !sinst || idx >= config.nb_ports ) return; suil_instance_port_event(sinst, idx, bfrsz, typ, bfr); } #if 0 void PluginLV2GUI::touch(void *obj, uint32_t pidx, bool grabbed) { PluginLV2GUI* the = (PluginLV2GUI*)obj; int idx = pidx; if( idx >= the->config.nb_ports ) return; printf("%s %s(%u)\n", (grabbed? _("press") : _("release")), the->config.names[idx], idx); } #endif uint32_t PluginLV2GUI::uri_to_id(LV2_URID_Map_Handle handle, const char *map, const char *uri) { return ((PluginLV2UriTable *)handle)->map(uri); } LV2_URID PluginLV2GUI::uri_table_map(LV2_URID_Map_Handle handle, const char *uri) { return ((PluginLV2UriTable *)handle)->map(uri); } const char *PluginLV2GUI::uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid) { return ((PluginLV2UriTable *)handle)->unmap(urid); } void PluginLV2GUI::lv2ui_instantiate(void *parent) { if ( !ui_host ) { ui_host = suil_host_new( PluginLV2GUI::write_from_ui, PluginLV2GUI::port_index, 0, 0); // suil_host_set_touch_func(ui_host, // PluginLV2GUI::touch); } ui_features.remove(); LV2_Handle lilv_handle = lilv_instance_get_handle(inst); ui_features.append(new Lv2Feature(NS_EXT "instance-access", lilv_handle)); const LV2_Descriptor *lilv_desc = lilv_instance_get_descriptor(inst); ext_data = new LV2_Extension_Data_Feature(); ext_data->data_access = lilv_desc->extension_data; ui_features.append(new Lv2Feature(LV2_DATA_ACCESS_URI, ext_data)); ui_features.append(new Lv2Feature(LV2_UI__parent, parent)); ui_features.append(new Lv2Feature(LV2_UI__idleInterface, 0)); ui_features.append(0); const char* bundle_uri = lilv_node_as_uri(lilv_ui_get_bundle_uri(ui)); char* bundle_path = lilv_file_uri_parse(bundle_uri, NULL); const char* binary_uri = lilv_node_as_uri(lilv_ui_get_binary_uri(ui)); char* binary_path = lilv_file_uri_parse(binary_uri, NULL); sinst = suil_instance_new(ui_host, this, gtk_type, lilv_node_as_uri(lilv_plugin_get_uri(lilv)), lilv_node_as_uri(lilv_ui_get_uri(ui)), lilv_node_as_uri(ui_type), bundle_path, binary_path, ui_features); lilv_free(binary_path); lilv_free(bundle_path); } bool PluginLV2GUI::lv2ui_resizable() { if( !ui ) return false; const LilvNode* s = lilv_ui_get_uri(ui); LilvNode *p = lilv_new_uri(world, LV2_CORE__optionalFeature); LilvNode *fs = lilv_new_uri(world, LV2_UI__fixedSize); LilvNode *nrs = lilv_new_uri(world, LV2_UI__noUserResize); LilvNodes *fs_matches = lilv_world_find_nodes(world, s, p, fs); LilvNodes *nrs_matches = lilv_world_find_nodes(world, s, p, nrs); lilv_nodes_free(nrs_matches); lilv_nodes_free(fs_matches); lilv_node_free(nrs); lilv_node_free(fs); lilv_node_free(p); return !fs_matches && !nrs_matches; } int PluginLV2GUI::update_lv2(float *vals, int force) { int ret = 0; float *ctls = (float *)config.ctls; for( int i=0; iidx; float val = vals[idx]; if( !force && ctls[idx] == val ) continue; update_control(idx, sizeof(val), 0, &val); ++ret; } for( int i=0; i