Implement LV2 request-value UI
* Handle cross-thread request from DSP context * Allow calls without plugin GUI * Implement boolean value requests, show dialog
This commit is contained in:
parent
eadd98efec
commit
532fbc41cb
@ -89,6 +89,7 @@
|
||||
|
||||
#include "gtkmm2ext/application.h"
|
||||
#include "gtkmm2ext/bindings.h"
|
||||
#include "gtkmm2ext/doi.h"
|
||||
#include "gtkmm2ext/gtk_ui.h"
|
||||
#include "gtkmm2ext/utils.h"
|
||||
#include "gtkmm2ext/window_title.h"
|
||||
@ -108,6 +109,7 @@
|
||||
#include "ardour/filename_extensions.h"
|
||||
#include "ardour/filesystem_paths.h"
|
||||
#include "ardour/ltc_file_reader.h"
|
||||
#include "ardour/lv2_plugin.h"
|
||||
#include "ardour/monitor_control.h"
|
||||
#include "ardour/midi_track.h"
|
||||
#include "ardour/port.h"
|
||||
@ -174,6 +176,7 @@
|
||||
#include "location_ui.h"
|
||||
#include "lua_script_manager.h"
|
||||
#include "luawindow.h"
|
||||
#include "lv2_plugin_ui.h"
|
||||
#include "main_clock.h"
|
||||
#include "missing_file_dialog.h"
|
||||
#include "missing_plugin_dialog.h"
|
||||
@ -437,6 +440,11 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
|
||||
|
||||
ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
|
||||
|
||||
#ifdef HAVE_LV2_1_17_2
|
||||
ARDOUR::LV2Plugin::Request.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::lv2_plugin_request, this, _1, _2, _3, _4), gui_context());
|
||||
LV2PluginUI::CatchDeletion.connect_same_thread (forever_connections, boost::bind (&delete_when_idle<LV2PluginUI>, _1));
|
||||
#endif
|
||||
|
||||
/* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
|
||||
|
||||
ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
|
||||
|
@ -72,6 +72,9 @@
|
||||
#include "gtkmm2ext/bindings.h"
|
||||
#include "gtkmm2ext/visibility_tracker.h"
|
||||
|
||||
#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
|
||||
#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
|
||||
|
||||
#include "ardour/ardour.h"
|
||||
#include "ardour/types.h"
|
||||
#include "ardour/utils.h"
|
||||
@ -177,6 +180,7 @@ namespace ARDOUR {
|
||||
class Route;
|
||||
class RouteGroup;
|
||||
class Location;
|
||||
class PluginInsert;
|
||||
class ProcessThread;
|
||||
}
|
||||
|
||||
@ -236,6 +240,8 @@ public:
|
||||
bool ask_about_loading_existing_session (const std::string& session_path);
|
||||
int load_session_from_startup_fsm ();
|
||||
|
||||
void lv2_plugin_request (boost::weak_ptr<ARDOUR::PluginInsert>, LV2_URID, LV2_URID, LV2_Feature const* const*);
|
||||
|
||||
/// @return true if session was successfully unloaded.
|
||||
int unload_session (bool hide_stuff = false);
|
||||
void close_session();
|
||||
|
@ -40,6 +40,8 @@
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/automation_watch.h"
|
||||
#include "ardour/control_protocol_manager.h"
|
||||
#include "ardour/lv2_plugin.h"
|
||||
#include "ardour/plugin_insert.h"
|
||||
#include "ardour/profile.h"
|
||||
#include "ardour/session.h"
|
||||
|
||||
@ -63,6 +65,7 @@
|
||||
#include "location_ui.h"
|
||||
#include "lua_script_manager.h"
|
||||
#include "luawindow.h"
|
||||
#include "lv2_plugin_ui.h"
|
||||
#include "main_clock.h"
|
||||
#include "meterbridge.h"
|
||||
#include "meter_patterns.h"
|
||||
@ -1034,6 +1037,25 @@ ARDOUR_UI::show_plugin_manager ()
|
||||
tact->set_active();
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::lv2_plugin_request (boost::weak_ptr<PluginInsert> wi, LV2_URID key, LV2_URID type, LV2_Feature const* const* features)
|
||||
{
|
||||
#ifdef HAVE_LV2_1_17_2
|
||||
boost::shared_ptr<PluginInsert> insert = wi.lock ();
|
||||
if (!insert) {
|
||||
return;
|
||||
}
|
||||
boost::shared_ptr<LV2Plugin> vp = boost::dynamic_pointer_cast<LV2Plugin> (insert->plugin());
|
||||
if (!vp) {
|
||||
return;
|
||||
}
|
||||
LV2PluginUI* lpu = new LV2PluginUI (insert, vp);
|
||||
if (LV2PluginUI::request_value (lpu, key, type, features) != LV2UI_REQUEST_VALUE_SUCCESS) {
|
||||
delete lpu;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ARDOUR_UI::timecode_button_press (GdkEventButton* ev)
|
||||
{
|
||||
|
@ -25,17 +25,18 @@
|
||||
|
||||
#include <gtkmm/stock.h>
|
||||
|
||||
#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
|
||||
|
||||
#include "ardour/lv2_plugin.h"
|
||||
#include "ardour/session.h"
|
||||
#include "pbd/error.h"
|
||||
|
||||
#include "gtkmm2ext/utils.h"
|
||||
|
||||
#include "gui_thread.h"
|
||||
#include "lv2_plugin_ui.h"
|
||||
#include "timers.h"
|
||||
|
||||
#include "gtkmm2ext/utils.h"
|
||||
|
||||
#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
|
||||
#include "ardour_message.h"
|
||||
|
||||
#include <lilv/lilv.h>
|
||||
#include <suil/suil.h>
|
||||
@ -48,6 +49,10 @@ using namespace PBD;
|
||||
|
||||
#define NS_UI "http://lv2plug.in/ns/extensions/ui#"
|
||||
|
||||
#ifdef HAVE_LV2_1_17_2
|
||||
PBD::Signal1<void, LV2PluginUI*> LV2PluginUI::CatchDeletion;
|
||||
#endif
|
||||
|
||||
static SuilHost* ui_host = NULL;
|
||||
|
||||
void
|
||||
@ -121,24 +126,31 @@ LV2PluginUI::touch(void* controller,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LV2_1_17_2
|
||||
|
||||
void
|
||||
LV2PluginUI::set_path_property (int response,
|
||||
const ParameterDescriptor& desc,
|
||||
Gtk::FileChooserDialog* widget)
|
||||
LV2PluginUI::request_response (int response,
|
||||
const ParameterDescriptor& desc,
|
||||
Gtk::Widget* widget)
|
||||
{
|
||||
if (response == Gtk::RESPONSE_ACCEPT) {
|
||||
plugin->set_property (desc.key, Variant (Variant::PATH, widget->get_filename()));
|
||||
switch (desc.datatype) {
|
||||
case Variant::PATH:
|
||||
if (response == Gtk::RESPONSE_ACCEPT) {
|
||||
set_path_property (desc.key, Variant (Variant::PATH, dynamic_cast<Gtk::FileChooserDialog*> (widget)->get_filename ()));
|
||||
}
|
||||
break;
|
||||
case Variant::BOOL:
|
||||
set_path_property (desc.key, Variant (Variant::BOOL, response == Gtk::RESPONSE_YES));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
widget->hide ();
|
||||
delete_when_idle (widget);
|
||||
#else
|
||||
|
||||
delete widget;
|
||||
#endif
|
||||
active_parameter_requests.erase (desc.key);
|
||||
_active_parameter_requests.erase (desc.key);
|
||||
CatchDeletion (this); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
#ifdef HAVE_LV2_1_17_2
|
||||
LV2UI_Request_Value_Status
|
||||
LV2PluginUI::request_value(void* handle,
|
||||
LV2_URID key,
|
||||
@ -150,39 +162,62 @@ LV2PluginUI::request_value(void* handle,
|
||||
const ParameterDescriptor& desc (me->_lv2->get_property_descriptor(key));
|
||||
if (desc.key == (uint32_t)-1) {
|
||||
return LV2UI_REQUEST_VALUE_ERR_UNKNOWN;
|
||||
} else if (desc.datatype != Variant::PATH) {
|
||||
return LV2UI_REQUEST_VALUE_ERR_UNSUPPORTED;
|
||||
} else if (me->active_parameter_requests.count (key)) {
|
||||
} else if (me->_active_parameter_requests.count (key)) {
|
||||
return LV2UI_REQUEST_VALUE_BUSY;
|
||||
}
|
||||
me->active_parameter_requests.insert (key);
|
||||
|
||||
Gtk::FileChooserDialog* lv2ui_file_dialog = new Gtk::FileChooserDialog(desc.label, FILE_CHOOSER_ACTION_OPEN);
|
||||
Gtkmm2ext::add_volume_shortcuts (*lv2ui_file_dialog);
|
||||
lv2ui_file_dialog->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
|
||||
lv2ui_file_dialog->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
|
||||
lv2ui_file_dialog->set_default_response(Gtk::RESPONSE_ACCEPT);
|
||||
me->_active_parameter_requests.insert (key);
|
||||
|
||||
/* this assumes announce_property_values() was called, or
|
||||
* the plugin has previously sent a patch:Set */
|
||||
const Variant& value = me->_lv2->get_property_value (desc.key);
|
||||
if (value.type() == Variant::PATH) {
|
||||
lv2ui_file_dialog->set_filename (value.get_path());
|
||||
}
|
||||
switch (desc.datatype) {
|
||||
case Variant::PATH:
|
||||
{
|
||||
Gtk::FileChooserDialog* lv2ui_file_dialog = new Gtk::FileChooserDialog(desc.label, FILE_CHOOSER_ACTION_OPEN);
|
||||
Gtkmm2ext::add_volume_shortcuts (*lv2ui_file_dialog);
|
||||
lv2ui_file_dialog->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
|
||||
lv2ui_file_dialog->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
|
||||
lv2ui_file_dialog->set_default_response(Gtk::RESPONSE_ACCEPT);
|
||||
|
||||
/* this assumes announce_property_values() was called, or
|
||||
* the plugin has previously sent a patch:Set */
|
||||
const Variant& value = me->_lv2->get_property_value (desc.key);
|
||||
if (value.type() == Variant::PATH) {
|
||||
lv2ui_file_dialog->set_filename (value.get_path());
|
||||
}
|
||||
|
||||
#if 0 // TODO mime-type, file-extension filter, get from LV2 Parameter Property
|
||||
FileFilter file_ext_filter;
|
||||
file_ext_filter.add_pattern ("*.foo");
|
||||
file_ext_filter.set_name ("Foo File");
|
||||
lv2ui_file_dialog.add_filter (file_ext_filter);
|
||||
FileFilter file_ext_filter;
|
||||
file_ext_filter.add_pattern ("*.foo");
|
||||
file_ext_filter.set_name ("Foo File");
|
||||
lv2ui_file_dialog.add_filter (file_ext_filter);
|
||||
#endif
|
||||
lv2ui_file_dialog->signal_response().connect (sigc::bind (sigc::mem_fun (*me, &LV2PluginUI::request_response), desc, lv2ui_file_dialog));
|
||||
lv2ui_file_dialog->present();
|
||||
}
|
||||
break;
|
||||
|
||||
case Variant::BOOL:
|
||||
{
|
||||
ArdourMessageDialog* msg = new ArdourMessageDialog (desc.label, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, false);
|
||||
msg->signal_response().connect (sigc::bind (sigc::mem_fun (*me, &LV2PluginUI::request_response), desc, msg));
|
||||
msg->present();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
me->_active_parameter_requests.erase (key);
|
||||
return LV2UI_REQUEST_VALUE_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
lv2ui_file_dialog->signal_response().connect (sigc::bind (sigc::mem_fun (*me, &LV2PluginUI::set_path_property), desc, lv2ui_file_dialog));
|
||||
lv2ui_file_dialog->present();
|
||||
return LV2UI_REQUEST_VALUE_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
LV2PluginUI::set_path_property (const uint32_t key, ARDOUR::Variant const& val)
|
||||
{
|
||||
plugin->set_property (key, val);
|
||||
}
|
||||
|
||||
void
|
||||
LV2PluginUI::update_timeout()
|
||||
{
|
||||
|
@ -66,6 +66,16 @@ public:
|
||||
int package (Gtk::Window&);
|
||||
void grab_focus ();
|
||||
|
||||
#ifdef HAVE_LV2_1_17_2
|
||||
static LV2UI_Request_Value_Status
|
||||
request_value(void* handle,
|
||||
LV2_URID key,
|
||||
LV2_URID type,
|
||||
const LV2_Feature* const* features);
|
||||
|
||||
static PBD::Signal1<void, LV2PluginUI*> CatchDeletion;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
void control_changed (uint32_t);
|
||||
@ -88,6 +98,7 @@ private:
|
||||
#ifdef HAVE_LV2_1_17_2
|
||||
LV2UI_Request_Value _lv2ui_request_value;
|
||||
LV2_Feature _lv2ui_request_feature;
|
||||
std::set<uint32_t> _active_parameter_requests;
|
||||
#endif
|
||||
struct lv2_external_ui* _external_ui_ptr;
|
||||
LV2_Feature _parent_feature;
|
||||
@ -115,18 +126,14 @@ private:
|
||||
uint32_t port_index,
|
||||
bool grabbed);
|
||||
|
||||
void set_path_property (const uint32_t key, ARDOUR::Variant const&);
|
||||
|
||||
#ifdef HAVE_LV2_1_17_2
|
||||
static LV2UI_Request_Value_Status
|
||||
request_value(void* handle,
|
||||
LV2_URID key,
|
||||
LV2_URID type,
|
||||
const LV2_Feature* const* features);
|
||||
void request_response (int,
|
||||
ARDOUR::ParameterDescriptor const&,
|
||||
Gtk::Widget*);
|
||||
#endif
|
||||
|
||||
void set_path_property (int,
|
||||
const ARDOUR::ParameterDescriptor&,
|
||||
Gtk::FileChooserDialog*);
|
||||
std::set<uint32_t> active_parameter_requests;
|
||||
|
||||
void update_timeout();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user