prototype [LV2]patch-change support for generic plugin UIs.
This commit is contained in:
parent
1648d9cbc6
commit
b8cea19b95
@ -41,6 +41,9 @@
|
|||||||
#include "ardour/plugin.h"
|
#include "ardour/plugin.h"
|
||||||
#include "ardour/plugin_insert.h"
|
#include "ardour/plugin_insert.h"
|
||||||
#include "ardour/session.h"
|
#include "ardour/session.h"
|
||||||
|
#ifdef LV2_SUPPORT
|
||||||
|
#include "ardour/lv2_plugin.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "ardour_ui.h"
|
#include "ardour_ui.h"
|
||||||
#include "prompter.h"
|
#include "prompter.h"
|
||||||
@ -305,6 +308,34 @@ GenericPluginUI::build ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LV2_SUPPORT
|
||||||
|
boost::shared_ptr<ARDOUR::LV2Plugin> lv2p = boost::dynamic_pointer_cast<LV2Plugin> (plugin);
|
||||||
|
if (lv2p) {
|
||||||
|
_fcb = (Gtk::FileChooserButton**) malloc(lv2p->patch_count() * sizeof(Gtk::FileChooserButton*));
|
||||||
|
for (uint32_t p = 0; p < lv2p->patch_count(); ++p) {
|
||||||
|
_fcb[p] = manage (new Gtk::FileChooserButton (Gtk::FILE_CHOOSER_ACTION_OPEN));
|
||||||
|
_fcb[p]->signal_file_set().connect (sigc::bind(sigc::mem_fun (*this, &GenericPluginUI::patch_set_file), p));
|
||||||
|
lv2p->PatchChanged.connect (*this, invalidator (*this), boost::bind (&GenericPluginUI::patch_changed, this, _1), gui_context());
|
||||||
|
// when user cancels file selection the FileChooserButton will display "None"
|
||||||
|
// TODO hack away around this..
|
||||||
|
if (lv2p->patch_val(p)) {
|
||||||
|
_fcb[p]->set_filename(lv2p->patch_val(p));
|
||||||
|
}
|
||||||
|
if (lv2p->patch_key(p)) {
|
||||||
|
_fcb[p]->set_title(lv2p->patch_key(p));
|
||||||
|
Gtk::Label* fcl = manage (new Label (lv2p->patch_key(p)));
|
||||||
|
button_table.attach (*fcl, 0, button_cols, button_row, button_row + 1, FILL|EXPAND, FILL);
|
||||||
|
++button_row;
|
||||||
|
} else {
|
||||||
|
_fcb[p]->set_title(_("LV2 Patch"));
|
||||||
|
}
|
||||||
|
|
||||||
|
button_table.attach (*_fcb[p], 0, button_cols, button_row, button_row + 1, FILL|EXPAND, FILL);
|
||||||
|
++button_row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Iterate over the list of controls to find which adjacent controls
|
// Iterate over the list of controls to find which adjacent controls
|
||||||
// are similar enough to be grouped together.
|
// are similar enough to be grouped together.
|
||||||
|
|
||||||
@ -934,4 +965,20 @@ GenericPluginUI::output_update ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LV2_SUPPORT
|
||||||
|
|
||||||
|
void
|
||||||
|
GenericPluginUI::patch_set_file (uint32_t p)
|
||||||
|
{
|
||||||
|
boost::shared_ptr<ARDOUR::LV2Plugin> lv2p = boost::dynamic_pointer_cast<LV2Plugin> (plugin);
|
||||||
|
lv2p->patch_set(p, _fcb[p]->get_filename ().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GenericPluginUI::patch_changed (uint32_t p)
|
||||||
|
{
|
||||||
|
boost::shared_ptr<ARDOUR::LV2Plugin> lv2p = boost::dynamic_pointer_cast<LV2Plugin> (plugin);
|
||||||
|
_fcb[p]->set_filename(lv2p->patch_val(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -278,6 +278,12 @@ class GenericPluginUI : public PlugUIBase, public Gtk::VBox
|
|||||||
void print_parameter (char *buf, uint32_t len, uint32_t param);
|
void print_parameter (char *buf, uint32_t len, uint32_t param);
|
||||||
bool integer_printer (char* buf, Gtk::Adjustment &, ControlUI *);
|
bool integer_printer (char* buf, Gtk::Adjustment &, ControlUI *);
|
||||||
bool midinote_printer(char* buf, Gtk::Adjustment &, ControlUI *);
|
bool midinote_printer(char* buf, Gtk::Adjustment &, ControlUI *);
|
||||||
|
|
||||||
|
#ifdef LV2_SUPPORT
|
||||||
|
void patch_set_file (uint32_t patch_idx);
|
||||||
|
void patch_changed (uint32_t patch_idx);
|
||||||
|
Gtk::FileChooserButton **_fcb;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class PluginUIWindow : public ArdourWindow
|
class PluginUIWindow : public ArdourWindow
|
||||||
|
@ -30,6 +30,10 @@
|
|||||||
#include "ardour/worker.h"
|
#include "ardour/worker.h"
|
||||||
#include "pbd/ringbuffer.h"
|
#include "pbd/ringbuffer.h"
|
||||||
|
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
#define PATH_MAX 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct LV2_Evbuf_Impl LV2_Evbuf;
|
typedef struct LV2_Evbuf_Impl LV2_Evbuf;
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
@ -142,6 +146,13 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
|
|||||||
|
|
||||||
Worker* worker() { return _worker; }
|
Worker* worker() { return _worker; }
|
||||||
|
|
||||||
|
uint32_t patch_count() const { return _patch_count; }
|
||||||
|
const char * patch_uri(const uint32_t p) const { if (p < _patch_count) return _patch_value_uri[p]; else return NULL; }
|
||||||
|
const char * patch_key(const uint32_t p) const { if (p < _patch_count) return _patch_value_key[p]; else return NULL; }
|
||||||
|
const char * patch_val(const uint32_t p) const { if (p < _patch_count) return _patch_value_cur[p]; else return NULL; }
|
||||||
|
bool patch_set(const uint32_t p, const char * val);
|
||||||
|
PBD::Signal1<void,const uint32_t> PatchChanged;
|
||||||
|
|
||||||
int work(uint32_t size, const void* data);
|
int work(uint32_t size, const void* data);
|
||||||
int work_response(uint32_t size, const void* data);
|
int work_response(uint32_t size, const void* data);
|
||||||
|
|
||||||
@ -152,6 +163,8 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
|
|||||||
uint32_t atom_Path;
|
uint32_t atom_Path;
|
||||||
uint32_t atom_Sequence;
|
uint32_t atom_Sequence;
|
||||||
uint32_t atom_eventTransfer;
|
uint32_t atom_eventTransfer;
|
||||||
|
uint32_t atom_URID;
|
||||||
|
uint32_t atom_Blank;
|
||||||
uint32_t log_Error;
|
uint32_t log_Error;
|
||||||
uint32_t log_Note;
|
uint32_t log_Note;
|
||||||
uint32_t log_Warning;
|
uint32_t log_Warning;
|
||||||
@ -164,6 +177,9 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
|
|||||||
uint32_t time_beatsPerMinute;
|
uint32_t time_beatsPerMinute;
|
||||||
uint32_t time_frame;
|
uint32_t time_frame;
|
||||||
uint32_t time_speed;
|
uint32_t time_speed;
|
||||||
|
uint32_t patch_Set;
|
||||||
|
uint32_t patch_property;
|
||||||
|
uint32_t patch_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
static URIDs urids;
|
static URIDs urids;
|
||||||
@ -187,6 +203,13 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
|
|||||||
double _next_cycle_speed; ///< Expected start frame of next run cycle
|
double _next_cycle_speed; ///< Expected start frame of next run cycle
|
||||||
PBD::ID _insert_id;
|
PBD::ID _insert_id;
|
||||||
|
|
||||||
|
uint32_t _patch_count;
|
||||||
|
char ** _patch_value_uri;
|
||||||
|
char ** _patch_value_key;
|
||||||
|
char (*_patch_value_cur)[PATH_MAX]; ///< current value
|
||||||
|
char (*_patch_value_set)[PATH_MAX]; ///< new value to set
|
||||||
|
Glib::Threads::Mutex _patch_set_lock;
|
||||||
|
|
||||||
friend const void* lv2plugin_get_port_value(const char* port_symbol,
|
friend const void* lv2plugin_get_port_value(const char* port_symbol,
|
||||||
void* user_data,
|
void* user_data,
|
||||||
uint32_t* size,
|
uint32_t* size,
|
||||||
@ -200,7 +223,8 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
|
|||||||
PORT_EVENT = 1 << 4, ///< Old event API event port
|
PORT_EVENT = 1 << 4, ///< Old event API event port
|
||||||
PORT_SEQUENCE = 1 << 5, ///< New atom API event port
|
PORT_SEQUENCE = 1 << 5, ///< New atom API event port
|
||||||
PORT_MIDI = 1 << 6, ///< Event port understands MIDI
|
PORT_MIDI = 1 << 6, ///< Event port understands MIDI
|
||||||
PORT_POSITION = 1 << 7 ///< Event port understands position
|
PORT_POSITION = 1 << 7, ///< Event port understands position
|
||||||
|
PORT_PATCHMSG = 1 << 8 ///< Event port supports patch:Message
|
||||||
} PortFlag;
|
} PortFlag;
|
||||||
|
|
||||||
typedef unsigned PortFlags;
|
typedef unsigned PortFlags;
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
#include "lv2/lv2plug.in/ns/ext/worker/worker.h"
|
#include "lv2/lv2plug.in/ns/ext/worker/worker.h"
|
||||||
#include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h"
|
#include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h"
|
||||||
#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
|
#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
|
||||||
|
#include "lv2/lv2plug.in/ns/ext/patch/patch.h"
|
||||||
#ifdef HAVE_NEW_LV2
|
#ifdef HAVE_NEW_LV2
|
||||||
#include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h"
|
#include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h"
|
||||||
#include "lv2/lv2plug.in/ns/ext/options/options.h"
|
#include "lv2/lv2plug.in/ns/ext/options/options.h"
|
||||||
@ -94,6 +95,8 @@ LV2Plugin::URIDs LV2Plugin::urids = {
|
|||||||
_uri_map.uri_to_id(LV2_ATOM__Path),
|
_uri_map.uri_to_id(LV2_ATOM__Path),
|
||||||
_uri_map.uri_to_id(LV2_ATOM__Sequence),
|
_uri_map.uri_to_id(LV2_ATOM__Sequence),
|
||||||
_uri_map.uri_to_id(LV2_ATOM__eventTransfer),
|
_uri_map.uri_to_id(LV2_ATOM__eventTransfer),
|
||||||
|
_uri_map.uri_to_id(LV2_ATOM__URID),
|
||||||
|
_uri_map.uri_to_id(LV2_ATOM__Blank),
|
||||||
_uri_map.uri_to_id(LV2_LOG__Error),
|
_uri_map.uri_to_id(LV2_LOG__Error),
|
||||||
_uri_map.uri_to_id(LV2_LOG__Note),
|
_uri_map.uri_to_id(LV2_LOG__Note),
|
||||||
_uri_map.uri_to_id(LV2_LOG__Warning),
|
_uri_map.uri_to_id(LV2_LOG__Warning),
|
||||||
@ -105,7 +108,10 @@ LV2Plugin::URIDs LV2Plugin::urids = {
|
|||||||
_uri_map.uri_to_id(LV2_TIME__beatsPerBar),
|
_uri_map.uri_to_id(LV2_TIME__beatsPerBar),
|
||||||
_uri_map.uri_to_id(LV2_TIME__beatsPerMinute),
|
_uri_map.uri_to_id(LV2_TIME__beatsPerMinute),
|
||||||
_uri_map.uri_to_id(LV2_TIME__frame),
|
_uri_map.uri_to_id(LV2_TIME__frame),
|
||||||
_uri_map.uri_to_id(LV2_TIME__speed)
|
_uri_map.uri_to_id(LV2_TIME__speed),
|
||||||
|
_uri_map.uri_to_id(LV2_PATCH__Set),
|
||||||
|
_uri_map.uri_to_id(LV2_PATCH__property),
|
||||||
|
_uri_map.uri_to_id(LV2_PATCH__value)
|
||||||
};
|
};
|
||||||
|
|
||||||
class LV2World : boost::noncopyable {
|
class LV2World : boost::noncopyable {
|
||||||
@ -146,6 +152,8 @@ public:
|
|||||||
LilvNode* ui_externalkx;
|
LilvNode* ui_externalkx;
|
||||||
LilvNode* units_unit;
|
LilvNode* units_unit;
|
||||||
LilvNode* units_midiNote;
|
LilvNode* units_midiNote;
|
||||||
|
LilvNode* patch_writable;
|
||||||
|
LilvNode* patch_Message;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _bundle_checked;
|
bool _bundle_checked;
|
||||||
@ -254,6 +262,11 @@ LV2Plugin::LV2Plugin (AudioEngine& engine,
|
|||||||
, _features(NULL)
|
, _features(NULL)
|
||||||
, _worker(NULL)
|
, _worker(NULL)
|
||||||
, _insert_id("0")
|
, _insert_id("0")
|
||||||
|
, _patch_count(0)
|
||||||
|
, _patch_value_uri(NULL)
|
||||||
|
, _patch_value_key(NULL)
|
||||||
|
, _patch_value_cur(NULL)
|
||||||
|
, _patch_value_set(NULL)
|
||||||
{
|
{
|
||||||
init(c_plugin, rate);
|
init(c_plugin, rate);
|
||||||
}
|
}
|
||||||
@ -265,6 +278,11 @@ LV2Plugin::LV2Plugin (const LV2Plugin& other)
|
|||||||
, _features(NULL)
|
, _features(NULL)
|
||||||
, _worker(NULL)
|
, _worker(NULL)
|
||||||
, _insert_id(other._insert_id)
|
, _insert_id(other._insert_id)
|
||||||
|
, _patch_count(0)
|
||||||
|
, _patch_value_uri(NULL)
|
||||||
|
, _patch_value_key(NULL)
|
||||||
|
, _patch_value_cur(NULL)
|
||||||
|
, _patch_value_set(NULL)
|
||||||
{
|
{
|
||||||
init(other._impl->plugin, other._sample_rate);
|
init(other._impl->plugin, other._sample_rate);
|
||||||
|
|
||||||
@ -456,6 +474,9 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
|
|||||||
if (lilv_nodes_contains(atom_supports, _world.time_Position)) {
|
if (lilv_nodes_contains(atom_supports, _world.time_Position)) {
|
||||||
flags |= PORT_POSITION;
|
flags |= PORT_POSITION;
|
||||||
}
|
}
|
||||||
|
if (lilv_nodes_contains(atom_supports, _world.patch_Message)) {
|
||||||
|
flags |= PORT_PATCHMSG;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
LilvNodes* min_size_v = lilv_port_get_value(_impl->plugin, port, _world.rsz_minimumSize);
|
LilvNodes* min_size_v = lilv_port_get_value(_impl->plugin, port, _world.rsz_minimumSize);
|
||||||
LilvNode* min_size = min_size_v ? lilv_nodes_get_first(min_size_v) : NULL;
|
LilvNode* min_size = min_size_v ? lilv_nodes_get_first(min_size_v) : NULL;
|
||||||
@ -532,6 +553,25 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
|
|||||||
|
|
||||||
delete[] params;
|
delete[] params;
|
||||||
|
|
||||||
|
/* scan supported patch:writable for this plugin.
|
||||||
|
* Note: the first Atom-port (in every direction) that supports patch:Message will be used
|
||||||
|
*/
|
||||||
|
LilvNode* rdfs_label = lilv_new_uri(_world.world, LILV_NS_RDFS "label");
|
||||||
|
LilvNodes* properties = lilv_world_find_nodes (_world.world, lilv_plugin_get_uri(plugin), _world.patch_writable, NULL);
|
||||||
|
LILV_FOREACH(nodes, p, properties) {
|
||||||
|
const LilvNode* property = lilv_nodes_get(properties, p);
|
||||||
|
LilvNode* label = lilv_nodes_get_first (lilv_world_find_nodes (_world.world, property, rdfs_label, NULL));
|
||||||
|
|
||||||
|
_patch_value_uri = (char**) realloc (_patch_value_uri, (_patch_count + 1) * sizeof(char**));
|
||||||
|
_patch_value_key = (char**) realloc (_patch_value_key, (_patch_count + 1) * sizeof(char**));
|
||||||
|
_patch_value_uri[_patch_count] = strdup(lilv_node_as_uri(property));
|
||||||
|
_patch_value_key[_patch_count] = strdup(lilv_node_as_string(property));
|
||||||
|
++_patch_count;
|
||||||
|
}
|
||||||
|
lilv_nodes_free(properties);
|
||||||
|
_patch_value_cur = (char(*)[PATH_MAX]) calloc(_patch_count, sizeof(char[PATH_MAX]));
|
||||||
|
_patch_value_set = (char(*)[PATH_MAX]) calloc(_patch_count, sizeof(char[PATH_MAX]));
|
||||||
|
|
||||||
LilvUIs* uis = lilv_plugin_get_uis(plugin);
|
LilvUIs* uis = lilv_plugin_get_uis(plugin);
|
||||||
if (lilv_uis_size(uis) > 0) {
|
if (lilv_uis_size(uis) > 0) {
|
||||||
#ifdef HAVE_SUIL
|
#ifdef HAVE_SUIL
|
||||||
@ -597,6 +637,13 @@ LV2Plugin::~LV2Plugin ()
|
|||||||
free(_make_path_feature.data);
|
free(_make_path_feature.data);
|
||||||
free(_work_schedule_feature.data);
|
free(_work_schedule_feature.data);
|
||||||
|
|
||||||
|
for (uint32_t pidx = 0; pidx < _patch_count; ++pidx) {
|
||||||
|
free(_patch_value_uri[pidx]);
|
||||||
|
free(_patch_value_key[pidx]);
|
||||||
|
}
|
||||||
|
free(_patch_value_cur);
|
||||||
|
free(_patch_value_set);
|
||||||
|
|
||||||
delete _to_ui;
|
delete _to_ui;
|
||||||
delete _from_ui;
|
delete _from_ui;
|
||||||
delete _worker;
|
delete _worker;
|
||||||
@ -1556,6 +1603,48 @@ write_position(LV2_Atom_Forge* forge,
|
|||||||
(const uint8_t*)(atom + 1));
|
(const uint8_t*)(atom + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
write_patch_change(
|
||||||
|
LV2_Atom_Forge* forge,
|
||||||
|
LV2_Evbuf* buf,
|
||||||
|
const char* uri,
|
||||||
|
const char* filename
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LV2_Atom_Forge_Frame frame;
|
||||||
|
uint8_t patch_buf[PATH_MAX];
|
||||||
|
lv2_atom_forge_set_buffer(forge, patch_buf, sizeof(patch_buf));
|
||||||
|
|
||||||
|
#if 0 // new LV2
|
||||||
|
lv2_atom_forge_object(forge, &frame, 0, LV2Plugin::urids.patch_Set);
|
||||||
|
lv2_atom_forge_key(forge, LV2Plugin::urids.patch_property);
|
||||||
|
lv2_atom_forge_urid(forge, uri_map.uri_to_id(uri));
|
||||||
|
lv2_atom_forge_key(forge, LV2Plugin::urids.patch_value);
|
||||||
|
lv2_atom_forge_path(forge, filename, strlen(filename));
|
||||||
|
#else
|
||||||
|
lv2_atom_forge_blank(forge, &frame, 1, LV2Plugin::urids.patch_Set);
|
||||||
|
lv2_atom_forge_property_head(forge, LV2Plugin::urids.patch_property, 0);
|
||||||
|
lv2_atom_forge_urid(forge, LV2Plugin::_uri_map.uri_to_id(uri));
|
||||||
|
lv2_atom_forge_property_head(forge, LV2Plugin::urids.patch_value, 0);
|
||||||
|
lv2_atom_forge_path(forge, filename, strlen(filename));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LV2_Evbuf_Iterator end = lv2_evbuf_end(buf);
|
||||||
|
const LV2_Atom* const atom = (const LV2_Atom*)patch_buf;
|
||||||
|
return lv2_evbuf_write(&end, 0, 0, atom->type, atom->size,
|
||||||
|
(const uint8_t*)(atom + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
LV2Plugin::patch_set (const uint32_t p, const char * val) {
|
||||||
|
if (p >= _patch_count) return false;
|
||||||
|
_patch_set_lock.lock();
|
||||||
|
strncpy(_patch_value_set[p], val, PATH_MAX);
|
||||||
|
_patch_value_set[p][PATH_MAX - 1] = 0;
|
||||||
|
_patch_set_lock.unlock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
LV2Plugin::connect_and_run(BufferSet& bufs,
|
LV2Plugin::connect_and_run(BufferSet& bufs,
|
||||||
ChanMapping in_map, ChanMapping out_map,
|
ChanMapping in_map, ChanMapping out_map,
|
||||||
@ -1687,6 +1776,24 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
|
|||||||
_ev_buffers[port_index] = scratch_bufs.get_lv2_midi(
|
_ev_buffers[port_index] = scratch_bufs.get_lv2_midi(
|
||||||
(flags & PORT_INPUT), 0, (flags & PORT_EVENT));
|
(flags & PORT_INPUT), 0, (flags & PORT_EVENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* queue patch messages */
|
||||||
|
if (flags & PORT_PATCHMSG) {
|
||||||
|
if (_patch_set_lock.trylock()) {
|
||||||
|
for (uint32_t pidx = 0; pidx < _patch_count; ++ pidx) {
|
||||||
|
if (strlen(_patch_value_set[pidx]) > 0
|
||||||
|
&& 0 != strcmp(_patch_value_cur[pidx], _patch_value_set[pidx])
|
||||||
|
)
|
||||||
|
{
|
||||||
|
write_patch_change(&_impl->forge, _ev_buffers[port_index],
|
||||||
|
_patch_value_uri[pidx], _patch_value_set[pidx]);
|
||||||
|
strncpy(_patch_value_cur[pidx], _patch_value_set[pidx], PATH_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_patch_set_lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buf = lv2_evbuf_get_buffer(_ev_buffers[port_index]);
|
buf = lv2_evbuf_get_buffer(_ev_buffers[port_index]);
|
||||||
} else {
|
} else {
|
||||||
continue; // Control port, leave buffer alone
|
continue; // Control port, leave buffer alone
|
||||||
@ -1759,8 +1866,9 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Write messages to UI
|
// Write messages to UI
|
||||||
if (_to_ui && (flags & PORT_OUTPUT) && (flags & (PORT_EVENT|PORT_SEQUENCE))) {
|
if ((_to_ui || _patch_count > 0) && (flags & PORT_OUTPUT) && (flags & (PORT_EVENT|PORT_SEQUENCE))) {
|
||||||
LV2_Evbuf* buf = _ev_buffers[port_index];
|
LV2_Evbuf* buf = _ev_buffers[port_index];
|
||||||
for (LV2_Evbuf_Iterator i = lv2_evbuf_begin(buf);
|
for (LV2_Evbuf_Iterator i = lv2_evbuf_begin(buf);
|
||||||
lv2_evbuf_is_valid(i);
|
lv2_evbuf_is_valid(i);
|
||||||
@ -1768,6 +1876,48 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
|
|||||||
uint32_t frames, subframes, type, size;
|
uint32_t frames, subframes, type, size;
|
||||||
uint8_t* data;
|
uint8_t* data;
|
||||||
lv2_evbuf_get(i, &frames, &subframes, &type, &size, &data);
|
lv2_evbuf_get(i, &frames, &subframes, &type, &size, &data);
|
||||||
|
|
||||||
|
// intercept patch change messages
|
||||||
|
/* TODO this should eventually be done in the UI-thread
|
||||||
|
* using a ringbuffer and no locks.
|
||||||
|
* The current UI ringbuffer is unsuitable. It only exists
|
||||||
|
* if a UI enabled and misses initial patch-set or changes.
|
||||||
|
*/
|
||||||
|
if (_patch_count > 0 && (flags & PORT_OUTPUT) && (flags & PORT_PATCHMSG)) {
|
||||||
|
// TODO reduce if() nesting below:
|
||||||
|
LV2_Atom* atom = (LV2_Atom*)(data - sizeof(LV2_Atom));
|
||||||
|
if (atom->type == LV2Plugin::urids.atom_Blank) {
|
||||||
|
LV2_Atom_Object* obj = (LV2_Atom_Object*)atom;
|
||||||
|
if (obj->body.otype == LV2Plugin::urids.patch_Set) {
|
||||||
|
const LV2_Atom* property = NULL;
|
||||||
|
lv2_atom_object_get (obj, LV2Plugin::urids.patch_property, &property, 0);
|
||||||
|
if (property->type == LV2Plugin::urids.atom_URID) {
|
||||||
|
for (uint32_t pidx = 0; pidx < _patch_count; ++ pidx) {
|
||||||
|
if (((const LV2_Atom_URID*)property)->body != _uri_map.uri_to_id(_patch_value_uri[pidx])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Get value. */
|
||||||
|
const LV2_Atom* file_path = NULL;
|
||||||
|
lv2_atom_object_get(obj, LV2Plugin::urids.patch_value, &file_path, 0);
|
||||||
|
if (!file_path || file_path->type != LV2Plugin::urids.atom_Path) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// LV2_ATOM_BODY() casts away qualifiers, so do it explicitly:
|
||||||
|
const char* uri = (const char*)((uint8_t const*)(file_path) + sizeof(LV2_Atom));
|
||||||
|
_patch_set_lock.lock();
|
||||||
|
strncpy(_patch_value_cur[pidx], uri, PATH_MAX);
|
||||||
|
strncpy(_patch_value_set[pidx], uri, PATH_MAX);
|
||||||
|
_patch_value_cur[pidx][PATH_MAX - 1] = 0;
|
||||||
|
_patch_value_set[pidx][PATH_MAX - 1] = 0;
|
||||||
|
_patch_set_lock.unlock();
|
||||||
|
PatchChanged(pidx); // emit signal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_to_ui) continue;
|
||||||
write_to_ui(port_index, urids.atom_eventTransfer,
|
write_to_ui(port_index, urids.atom_eventTransfer,
|
||||||
size + sizeof(LV2_Atom),
|
size + sizeof(LV2_Atom),
|
||||||
data - sizeof(LV2_Atom));
|
data - sizeof(LV2_Atom));
|
||||||
@ -1983,10 +2133,14 @@ LV2World::LV2World()
|
|||||||
ui_externalkx = lilv_new_uri(world, "http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget");
|
ui_externalkx = lilv_new_uri(world, "http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget");
|
||||||
units_unit = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/units#unit");
|
units_unit = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/units#unit");
|
||||||
units_midiNote = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/units#midiNote");
|
units_midiNote = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/units#midiNote");
|
||||||
|
patch_writable = lilv_new_uri(world, LV2_PATCH__writable);
|
||||||
|
patch_Message = lilv_new_uri(world, LV2_PATCH__Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
LV2World::~LV2World()
|
LV2World::~LV2World()
|
||||||
{
|
{
|
||||||
|
lilv_node_free(patch_Message);
|
||||||
|
lilv_node_free(patch_writable);
|
||||||
lilv_node_free(units_midiNote);
|
lilv_node_free(units_midiNote);
|
||||||
lilv_node_free(units_unit);
|
lilv_node_free(units_unit);
|
||||||
lilv_node_free(ui_externalkx);
|
lilv_node_free(ui_externalkx);
|
||||||
|
Loading…
Reference in New Issue
Block a user