#include <cstdlib>
#include <cstring>
-#include <giomm/file.h>
+#include <glib/gstdio.h>
#include <glib/gprintf.h>
#include <glibmm.h>
#include <boost/utility.hpp>
+#include "pbd/clear_dir.h"
#include "pbd/pathscanner.h"
#include "pbd/compose.h"
#include "pbd/error.h"
#include "ardour/types.h"
#include "ardour/utils.h"
#include "ardour/worker.h"
-#include "ardour/lv2_bundled_search_path.h"
+#include "ardour/search_paths.h"
#include "i18n.h"
#include <locale.h>
LilvNode* time_Position;
LilvNode* ui_GtkUI;
LilvNode* ui_external;
+ LilvNode* ui_externalkx;
+ LilvNode* units_unit;
+ LilvNode* units_midiNote;
private:
bool _bundle_checked;
_latency_control_port = 0;
_next_cycle_start = std::numeric_limits<framepos_t>::max();
_next_cycle_speed = 1.0;
- _block_length = _engine.frames_per_cycle();
+ _block_length = _engine.samples_per_cycle();
_seq_size = _engine.raw_buffer_size(DataType::MIDI);
_state_version = 0;
_was_activated = false;
if (!_impl->ui) {
LILV_FOREACH(uis, i, uis) {
const LilvUI* ui = lilv_uis_get(uis, i);
- if (lilv_ui_is_a(ui, _world.ui_external)) {
+ if (lilv_ui_is_a(ui, _world.ui_externalkx)) {
_impl->ui = ui;
_impl->ui_type = _world.ui_external;
break;
}
+ if (lilv_ui_is_a(ui, _world.ui_external)) {
+ _impl->ui = ui;
+ _impl->ui_type = _world.ui_external;
+ }
}
}
}
if (!_impl->ui) {
return false;
}
- return lilv_ui_is_a(_impl->ui, _world.ui_external);
+ return lilv_ui_is_a(_impl->ui, _world.ui_external) || lilv_ui_is_a(_impl->ui, _world.ui_externalkx);
+}
+
+bool
+LV2Plugin::is_external_kx() const
+{
+ if (!_impl->ui) {
+ return false;
+ }
+ return lilv_ui_is_a(_impl->ui, _world.ui_externalkx);
}
bool
return g_strndup(abs_path.c_str(), abs_path.length());
}
-static void
-remove_directory(const std::string& path)
-{
- if (!Glib::file_test(path, Glib::FILE_TEST_IS_DIR)) {
- warning << string_compose("\"%1\" is not a directory", path) << endmsg;
- return;
- }
-
- Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path(path);
- Glib::RefPtr<Gio::FileEnumerator> e = dir->enumerate_children();
- Glib::RefPtr<Gio::FileInfo> fi;
- while ((fi = e->next_file())) {
- if (fi->get_type() == Gio::FILE_TYPE_DIRECTORY) {
- remove_directory(fi->get_name());
- } else {
- dir->get_child(fi->get_name())->remove();
- }
- }
- dir->remove();
-}
-
void
LV2Plugin::add_state(XMLNode* root) const
{
} else {
// State is identical, decrement version and nuke directory
lilv_state_free(state);
- remove_directory(new_dir);
+ PBD::remove_directory(new_dir);
--_state_version;
}
if (state) {
lilv_state_restore(state, _impl->instance, set_port_value, this, 0, NULL);
lilv_state_free(state);
+ Plugin::load_preset(r);
}
lilv_node_free(pset);
lilv_state_free(state);
- return Glib::filename_to_uri(Glib::build_filename(bundle, file_name));
+ std::string uri = Glib::filename_to_uri(Glib::build_filename(bundle, file_name));
+ LilvNode *node_bundle = lilv_new_uri(_world.world, Glib::filename_to_uri(Glib::build_filename(bundle, "/")).c_str());
+ LilvNode *node_preset = lilv_new_uri(_world.world, uri.c_str());
+ lilv_world_load_bundle(_world.world, node_bundle);
+ lilv_world_load_resource(_world.world, node_preset);
+ lilv_node_free(node_bundle);
+ lilv_node_free(node_preset);
+ return uri;
}
void
name + ".ttl"
)
);
- unlink(preset_file.c_str());
+ ::g_unlink(preset_file.c_str());
}
bool
uint32_t size,
const uint8_t* body)
{
- const uint32_t buf_size = sizeof(UIMessage) + size;
- uint8_t buf[buf_size];
+ const uint32_t buf_size = sizeof(UIMessage) + size;
+ vector<uint8_t> buf(buf_size);
- UIMessage* msg = (UIMessage*)buf;
+ UIMessage* msg = (UIMessage*)&buf[0];
msg->index = index;
msg->protocol = protocol;
msg->size = size;
memcpy(msg + 1, body, size);
- return (dest->write(buf, buf_size) == buf_size);
+ return (dest->write(&buf[0], buf_size) == buf_size);
}
bool
const uint8_t* body)
{
if (!_from_ui) {
- _from_ui = new RingBuffer<uint8_t>(
- _session.engine().raw_buffer_size(DataType::MIDI) * NBUFS);
+ size_t rbs = _session.engine().raw_buffer_size(DataType::MIDI) * NBUFS;
+ /* buffer data communication from plugin UI to plugin instance.
+ * this buffer needs to potentially hold
+ * (port's minimumSize) * (audio-periods) / (UI-periods)
+ * bytes.
+ *
+ * e.g 48kSPS / 128fpp -> audio-periods = 375 Hz
+ * ui-periods = 25 Hz (SuperRapidScreenUpdate)
+ * default minimumSize = 32K (see LV2Plugin::allocate_atom_event_buffers()
+ *
+ * it is NOT safe to overflow (msg.size will be misinterpreted)
+ */
+ uint32_t bufsiz = 32768;
+ if (_atom_ev_buffers && _atom_ev_buffers[0]) {
+ bufsiz = lv2_evbuf_get_capacity(_atom_ev_buffers[0]);
+ }
+ rbs = max((size_t) bufsiz * 8, rbs);
+ _from_ui = new RingBuffer<uint8_t>(rbs);
}
if (!write_to(_from_ui, index, protocol, size, body)) {
LV2Plugin::enable_ui_emmission()
{
if (!_to_ui) {
- _to_ui = new RingBuffer<uint8_t>(
- _session.engine().raw_buffer_size(DataType::MIDI) * NBUFS);
+ /* see note in LV2Plugin::write_from_ui() */
+ uint32_t bufsiz = 32768;
+ if (_atom_ev_buffers && _atom_ev_buffers[0]) {
+ bufsiz = lv2_evbuf_get_capacity(_atom_ev_buffers[0]);
+ }
+ size_t rbs = _session.engine().raw_buffer_size(DataType::MIDI) * NBUFS;
+ rbs = max((size_t) bufsiz * 8, rbs);
+ _to_ui = new RingBuffer<uint8_t>(rbs);
}
}
error << "Error reading from Plugin=>UI RingBuffer" << endmsg;
break;
}
- uint8_t body[msg.size];
- if (_to_ui->read(body, msg.size) != msg.size) {
+ vector<uint8_t> body(msg.size);
+ if (_to_ui->read(&body[0], msg.size) != msg.size) {
error << "Error reading from Plugin=>UI RingBuffer" << endmsg;
break;
}
- sink(controller, msg.index, msg.size, msg.protocol, body);
+ sink(controller, msg.index, msg.size, msg.protocol, &body[0]);
read_space -= sizeof(msg) + msg.size;
}
{
const LilvPort* port = lilv_plugin_get_port_by_index(_impl->plugin, which);
+ LilvNodes* portunits;
LilvNode *def, *min, *max;
lilv_port_get_range(_impl->plugin, port, &def, &min, &max);
+ portunits = lilv_port_get_value(_impl->plugin, port, _world.units_unit);
desc.integer_step = lilv_port_has_property(_impl->plugin, port, _world.lv2_integer);
desc.toggled = lilv_port_has_property(_impl->plugin, port, _world.lv2_toggled);
desc.label = lilv_node_as_string(lilv_port_get_name(_impl->plugin, port));
desc.lower = min ? lilv_node_as_float(min) : 0.0f;
desc.upper = max ? lilv_node_as_float(max) : 1.0f;
+ desc.midinote = lilv_nodes_contains(portunits, _world.units_midiNote);
+
if (desc.sr_dependent) {
desc.lower *= _session.frame_rate ();
desc.upper *= _session.frame_rate ();
lilv_node_free(def);
lilv_node_free(min);
lilv_node_free(max);
+ lilv_nodes_free(portunits);
return 0;
}
return X_("hidden");
}
- if (lilv_port_has_property(_impl->plugin,
- lilv_plugin_get_port_by_index(_impl->plugin, which.id()), _world.lv2_sampleRate)) {
- return X_("hidden");
- }
-
if (lilv_port_has_property(_impl->plugin,
lilv_plugin_get_port_by_index(_impl->plugin, which.id()), _world.lv2_reportsLatency)) {
return X_("latency");
return;
}
- DEBUG_TRACE(DEBUG::LV2, string_compose("allocate %1 atom_ev_buffers\n", total_atom_buffers));
+ DEBUG_TRACE(DEBUG::LV2, string_compose("allocate %1 atom_ev_buffers of %d bytes\n", total_atom_buffers, minimumSize));
_atom_ev_buffers = (LV2_Evbuf**) malloc((total_atom_buffers + 1) * sizeof(LV2_Evbuf*));
for (int i = 0; i < total_atom_buffers; ++i ) {
_atom_ev_buffers[i] = lv2_evbuf_new(minimumSize, LV2_EVBUF_ATOM,
}
} else if (!valid) {
// Nothing we understand or care about, connect to scratch
+ // see note for midi-buffer size above
+ scratch_bufs.ensure_lv2_bufsize((flags & PORT_INPUT),
+ 0, _port_minimumSize[port_index]);
_ev_buffers[port_index] = scratch_bufs.get_lv2_midi(
(flags & PORT_INPUT), 0, (flags & PORT_EVENT));
}
error << "Error reading from UI=>Plugin RingBuffer" << endmsg;
break;
}
- uint8_t body[msg.size];
- if (_from_ui->read(body, msg.size) != msg.size) {
+ vector<uint8_t> body(msg.size);
+ if (_from_ui->read(&body[0], msg.size) != msg.size) {
error << "Error reading from UI=>Plugin RingBuffer" << endmsg;
break;
}
if (msg.protocol == urids.atom_eventTransfer) {
LV2_Evbuf* buf = _ev_buffers[msg.index];
LV2_Evbuf_Iterator i = lv2_evbuf_end(buf);
- const LV2_Atom* const atom = (const LV2_Atom*)body;
+ const LV2_Atom* const atom = (const LV2_Atom*)&body[0];
if (!lv2_evbuf_write(&i, nframes, 0, atom->type, atom->size,
(const uint8_t*)(atom + 1))) {
error << "Failed to write data to LV2 event buffer\n";
return port;
}
-static bool lv2_filter (const string& str, void *arg)
+static bool lv2_filter (const string& str, void* /*arg*/)
{
/* Not a dotfile, has a prefix before a period, suffix is "lv2" */
time_Position = lilv_new_uri(world, LV2_TIME__Position);
ui_GtkUI = lilv_new_uri(world, LV2_UI__GtkUI);
ui_external = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/ui#external");
+ 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_midiNote = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/units#midiNote");
}
LV2World::~LV2World()
{
+ lilv_node_free(units_midiNote);
+ lilv_node_free(units_unit);
+ lilv_node_free(ui_externalkx);
lilv_node_free(ui_external);
lilv_node_free(ui_GtkUI);
lilv_node_free(time_Position);
vector<string *> *plugin_objects = scanner (ARDOUR::lv2_bundled_search_path().to_string(), lv2_filter, 0, true, true);
if (plugin_objects) {
for ( vector<string *>::iterator x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
-#ifdef WINDOWS
+#ifdef PLATFORM_WINDOWS
string uri = "file:///" + **x + "/";
#else
string uri = "file://" + **x + "/";
PluginInfoList* plugs = new PluginInfoList;
const LilvPlugins* plugins = lilv_world_get_all_plugins(_world.world);
- info << "LV2: Discovering " << lilv_plugins_size(plugins) << " plugins" << endmsg;
+ if (!Config->get_show_plugin_scan_window()) {
+ info << "LV2: Discovering " << lilv_plugins_size(plugins) << " plugins" << endmsg;
+ }
LILV_FOREACH(plugins, i, plugins) {
const LilvPlugin* p = lilv_plugins_get(plugins, i);
info->name = string(lilv_node_as_string(name));
lilv_node_free(name);
+ ARDOUR::PluginScanMessage(_("LV2"), info->name, false);
const LilvPluginClass* pclass = lilv_plugin_get_class(p);
const LilvNode* label = lilv_plugin_class_get_label(pclass);