summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ingen/Status.hpp2
-rw-r--r--ingen/URIs.hpp1
-rw-r--r--src/URIs.cpp2
-rw-r--r--src/gui/NodeMenu.cpp60
-rw-r--r--src/gui/NodeMenu.hpp5
-rw-r--r--src/server/BlockImpl.cpp11
-rw-r--r--src/server/BlockImpl.hpp11
-rw-r--r--src/server/LV2Block.cpp27
-rw-r--r--src/server/LV2Block.hpp4
-rw-r--r--src/server/events/Delta.cpp63
-rw-r--r--src/server/events/Delta.hpp11
-rw-r--r--src/server/events/SetPortValue.cpp4
-rw-r--r--src/server/events/SetPortValue.hpp6
-rw-r--r--wscript2
14 files changed, 149 insertions, 60 deletions
diff --git a/ingen/Status.hpp b/ingen/Status.hpp
index ed388ccf..1fae5358 100644
--- a/ingen/Status.hpp
+++ b/ingen/Status.hpp
@@ -28,6 +28,7 @@ enum class Status {
BAD_REQUEST,
BAD_URI,
BAD_VALUE_TYPE,
+ BAD_VALUE,
CLIENT_NOT_FOUND,
CREATION_FAILED,
DIRECTION_MISMATCH,
@@ -60,6 +61,7 @@ ingen_status_string(Status st)
case Status::BAD_REQUEST: return "Invalid request";
case Status::BAD_URI: return "Invalid URI";
case Status::BAD_VALUE_TYPE: return "Invalid value type";
+ case Status::BAD_VALUE: return "Invalid value";
case Status::CLIENT_NOT_FOUND: return "Client not found";
case Status::CREATION_FAILED: return "Creation failed";
case Status::DIRECTION_MISMATCH: return "Direction mismatch";
diff --git a/ingen/URIs.hpp b/ingen/URIs.hpp
index 70406f57..2dc3f2f6 100644
--- a/ingen/URIs.hpp
+++ b/ingen/URIs.hpp
@@ -149,6 +149,7 @@ public:
const Quark patch_subject;
const Quark patch_value;
const Quark patch_wildcard;
+ const Quark pset_preset;
const Quark pprops_logarithmic;
const Quark rdf_type;
const Quark rdfs_seeAlso;
diff --git a/src/URIs.cpp b/src/URIs.cpp
index a70e8d77..66d7965b 100644
--- a/src/URIs.cpp
+++ b/src/URIs.cpp
@@ -24,6 +24,7 @@
#include "lv2/lv2plug.in/ns/ext/morph/morph.h"
#include "lv2/lv2plug.in/ns/ext/parameters/parameters.h"
#include "lv2/lv2plug.in/ns/ext/patch/patch.h"
+#include "lv2/lv2plug.in/ns/ext/presets/presets.h"
#include "lv2/lv2plug.in/ns/ext/port-props/port-props.h"
#include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h"
#include "lv2/lv2plug.in/ns/ext/time/time.h"
@@ -139,6 +140,7 @@ URIs::URIs(Forge& f, URIMap* map)
, patch_subject (forge, map, LV2_PATCH__subject)
, patch_value (forge, map, LV2_PATCH__value)
, patch_wildcard (forge, map, LV2_PATCH__wildcard)
+ , pset_preset (forge, map, LV2_PRESETS__preset)
, pprops_logarithmic (forge, map, LV2_PORT_PROPS__logarithmic)
, rdf_type (forge, map, NS_RDF "type")
, rdfs_seeAlso (forge, map, NS_RDFS "seeAlso")
diff --git a/src/gui/NodeMenu.cpp b/src/gui/NodeMenu.cpp
index 08524ade..b99ce546 100644
--- a/src/gui/NodeMenu.cpp
+++ b/src/gui/NodeMenu.cpp
@@ -108,18 +108,11 @@ NodeMenu::init(App& app, SPtr<const Client::BlockModel> block)
sigc::mem_fun(this, &NodeMenu::on_preset_activated),
string(lilv_node_as_string(preset)))));
- // I have no idea why this is necessary, signal_activated doesn't work
- // in this menu (and only this menu)
- Gtk::MenuItem* item = &(_presets_menu->items().back());
- item->signal_button_release_event().connect(
- sigc::bind<0>(sigc::mem_fun(this, &NodeMenu::on_preset_clicked),
- string(lilv_node_as_string(preset))));
-
lilv_nodes_free(labels);
++n_presets;
} else {
app.log().error(
- fmt("Preset <%1> has no rdfs:label\n")
+ fmt("Preset <%1%> has no rdfs:label\n")
% lilv_node_as_string(lilv_nodes_get(presets, i)));
}
}
@@ -177,7 +170,7 @@ NodeMenu::on_menu_randomize()
{
_app->interface()->bundle_begin();
- const BlockModel* const bm = (const BlockModel*)_object.get();
+ const SPtr<const BlockModel> bm = block();
for (const auto& p : bm->ports()) {
if (p->is_input() && _app->can_control(p.get())) {
float min = 0.0f, max = 1.0f;
@@ -198,60 +191,19 @@ NodeMenu::on_menu_disconnect()
_app->interface()->disconnect_all(_object->parent()->path(), _object->path());
}
-static void
-set_port_value(const char* port_symbol,
- void* user_data,
- const void* value,
- uint32_t size,
- uint32_t type)
-{
- NodeMenu* menu = (NodeMenu*)user_data;
- const BlockModel* const block = (const BlockModel*)menu->object().get();
-
- if (!Raul::Symbol::is_valid(port_symbol)) {
- menu->app()->log().error(
- fmt("Preset with invalid port symbol `%1'\n") % port_symbol);
- return;
- }
-
- menu->app()->set_property(
- Node::path_to_uri(block->path().child(Raul::Symbol(port_symbol))),
- menu->app()->uris().ingen_value,
- menu->app()->forge().alloc(size, type, value));
-}
-
void
NodeMenu::on_preset_activated(const std::string& uri)
{
- const BlockModel* const block = (const BlockModel*)_object.get();
- const PluginModel* const plugin = dynamic_cast<const PluginModel*>(block->plugin());
-
- LilvNode* pset = lilv_new_uri(plugin->lilv_world(), uri.c_str());
- LilvState* state = lilv_state_new_from_world(
- plugin->lilv_world(),
- &_app->world()->uri_map().urid_map_feature()->urid_map,
- pset);
-
- if (state) {
- lilv_state_restore(state, NULL, set_port_value, this, 0, NULL);
- lilv_state_free(state);
- }
-
- lilv_node_free(pset);
-}
+ _app->set_property(block()->uri(),
+ _app->uris().pset_preset,
+ _app->forge().alloc_uri(uri));
-bool
-NodeMenu::on_preset_clicked(const std::string& uri, GdkEventButton* ev)
-{
- on_preset_activated(uri);
- return false;
}
bool
NodeMenu::has_control_inputs()
{
- const BlockModel* const bm = (const BlockModel*)_object.get();
- for (const auto& p : bm->ports())
+ for (const auto& p : block()->ports())
if (p->is_input() && p->is_numeric())
return true;
diff --git a/src/gui/NodeMenu.hpp b/src/gui/NodeMenu.hpp
index d84bc84f..f28fe334 100644
--- a/src/gui/NodeMenu.hpp
+++ b/src/gui/NodeMenu.hpp
@@ -48,12 +48,15 @@ public:
sigc::signal<void, bool> signal_embed_gui;
protected:
+ SPtr<const Client::BlockModel> block() const {
+ return dynamic_ptr_cast<const Client::BlockModel>(_object);
+ }
+
void on_menu_disconnect();
void on_menu_embed_gui();
void on_menu_enabled();
void on_menu_randomize();
void on_preset_activated(const std::string& uri);
- bool on_preset_clicked(const std::string& uri, GdkEventButton* ev);
Gtk::MenuItem* _popup_gui_menuitem;
Gtk::CheckMenuItem* _embed_gui_menuitem;
diff --git a/src/server/BlockImpl.cpp b/src/server/BlockImpl.cpp
index ce6b169c..d21514ef 100644
--- a/src/server/BlockImpl.cpp
+++ b/src/server/BlockImpl.cpp
@@ -160,6 +160,17 @@ BlockImpl::nth_port_by_type(uint32_t n, bool input, PortType type)
return NULL;
}
+PortImpl*
+BlockImpl::port_by_symbol(const char* symbol)
+{
+ for (uint32_t p = 0; _ports && p < _ports->size(); ++p) {
+ if (_ports->at(p)->symbol() == symbol) {
+ return _ports->at(p);
+ }
+ }
+ return NULL;
+}
+
void
BlockImpl::pre_process(ProcessContext& context)
{
diff --git a/src/server/BlockImpl.hpp b/src/server/BlockImpl.hpp
index b3064168..965adbcc 100644
--- a/src/server/BlockImpl.hpp
+++ b/src/server/BlockImpl.hpp
@@ -21,6 +21,8 @@
#include <boost/intrusive/slist.hpp>
+#include "lilv/lilv.h"
+
#include "raul/Array.hpp"
#include "BufferRef.hpp"
@@ -98,6 +100,12 @@ public:
/** Enable or disable (bypass) this block. */
void set_enabled(bool e) { _enabled = e; }
+ /** Load a preset from the world for this block. */
+ virtual LilvState* load_preset(const Raul::URI& uri) { return NULL; }
+
+ /** Restore `state`. */
+ virtual void apply_state(LilvState* state) {}
+
/** Learn the next incoming MIDI event (for internals) */
virtual void learn() {}
@@ -122,6 +130,9 @@ public:
virtual Node* port(uint32_t index) const;
virtual PortImpl* port_impl(uint32_t index) const { return (*_ports)[index]; }
+ /** Get a port by symbol. */
+ virtual PortImpl* port_by_symbol(const char* symbol);
+
/** Blocks that are connected to this Block's inputs. */
std::list<BlockImpl*>& providers() { return _providers; }
diff --git a/src/server/LV2Block.cpp b/src/server/LV2Block.cpp
index 3f6f4be1..64c80764 100644
--- a/src/server/LV2Block.cpp
+++ b/src/server/LV2Block.cpp
@@ -20,6 +20,7 @@
#include <cmath>
#include "lv2/lv2plug.in/ns/ext/morph/morph.h"
+#include "lv2/lv2plug.in/ns/ext/presets/presets.h"
#include "lv2/lv2plug.in/ns/ext/options/options.h"
#include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h"
#include "lv2/lv2plug.in/ns/ext/state/state.h"
@@ -541,6 +542,32 @@ LV2Block::post_process(ProcessContext& context)
}
}
+LilvState*
+LV2Block::load_preset(const Raul::URI& uri)
+{
+ World* world = &_lv2_plugin->lv2_info()->world();
+ LilvWorld* lworld = _lv2_plugin->lv2_info()->lv2_world();
+ LilvNode* preset = lilv_new_uri(lworld, uri.c_str());
+
+ // Load preset into world if necessary
+ lilv_world_load_resource(lworld, preset);
+
+ // Load preset from world
+ LV2_URID_Map* map = &world->uri_map().urid_map_feature()->urid_map;
+ LilvState* state = lilv_state_new_from_world(lworld, map, preset);
+
+ lilv_node_free(preset);
+ return state;
+}
+
+void
+LV2Block::apply_state(LilvState* state)
+{
+ for (uint32_t v = 0; v < _polyphony; ++v) {
+ lilv_state_restore(state, instance(v), NULL, NULL, 0, NULL);
+ }
+}
+
void
LV2Block::set_port_buffer(uint32_t voice,
uint32_t port_num,
diff --git a/src/server/LV2Block.hpp b/src/server/LV2Block.hpp
index ec2f99f4..6b343df7 100644
--- a/src/server/LV2Block.hpp
+++ b/src/server/LV2Block.hpp
@@ -63,6 +63,10 @@ public:
void run(ProcessContext& context);
void post_process(ProcessContext& context);
+ LilvState* load_preset(const Raul::URI& uri);
+
+ void apply_state(LilvState* state);
+
void set_port_buffer(uint32_t voice,
uint32_t port_num,
BufferRef buf,
diff --git a/src/server/events/Delta.cpp b/src/server/events/Delta.cpp
index 03a7ccd5..8df79994 100644
--- a/src/server/events/Delta.cpp
+++ b/src/server/events/Delta.cpp
@@ -17,6 +17,7 @@
#include <vector>
#include <thread>
+#include "ingen/Log.hpp"
#include "ingen/Store.hpp"
#include "ingen/URIs.hpp"
#include "raul/Maid.hpp"
@@ -60,6 +61,7 @@ Delta::Delta(Engine& engine,
, _object(NULL)
, _graph(NULL)
, _compiled_graph(NULL)
+ , _state(NULL)
, _context(context)
, _type(type)
, _poly_lock(engine.store()->mutex(), std::defer_lock)
@@ -98,6 +100,37 @@ Delta::~Delta()
delete _create_event;
}
+void
+Delta::add_set_event(const char* port_symbol,
+ const void* value,
+ uint32_t size,
+ uint32_t type)
+{
+ BlockImpl* block = dynamic_cast<BlockImpl*>(_object);
+ PortImpl* port = block->port_by_symbol(port_symbol);
+ if (!port) {
+ _engine.log().warn(fmt("Unknown port `%1' in state") % port_symbol);
+ return;
+ }
+
+ SetPortValue* ev = new SetPortValue(
+ _engine, _request_client, _request_id, _time,
+ port, Atom(size, type, value), true);
+
+ ev->pre_process();
+ _set_events.push_back(ev);
+}
+
+static void
+s_add_set_event(const char* port_symbol,
+ void* user_data,
+ const void* value,
+ uint32_t size,
+ uint32_t type)
+{
+ ((Delta*)user_data)->add_set_event(port_symbol, value, size, type);
+}
+
bool
Delta::pre_process()
{
@@ -216,6 +249,22 @@ Delta::pre_process()
} else {
_status = Status::BAD_VALUE_TYPE;
}
+ } else if (key == uris.pset_preset) {
+ if (value.type() == uris.forge.URI) {
+ const char* str = value.ptr<char>();
+ if (Raul::URI::is_valid(str)) {
+ op = SpecialType::PRESET;
+ const Raul::URI uri(str);
+ if ((_state = block->load_preset(Raul::URI(str)))) {
+ lilv_state_emit_port_values(
+ _state, s_add_set_event, this);
+ }
+ } else {
+ _status = Status::BAD_VALUE;
+ }
+ } else {
+ _status = Status::BAD_VALUE_TYPE;
+ }
}
}
@@ -362,6 +411,9 @@ Delta::execute(ProcessContext& context)
}
}
break;
+ case SpecialType::PRESET:
+ block->set_enabled(false);
+ break;
case SpecialType::NONE:
if (port) {
if (key == uris.lv2_minimum) {
@@ -382,6 +434,15 @@ Delta::post_process()
_poly_lock.unlock();
}
+ if (_state) {
+ BlockImpl* block = dynamic_cast<BlockImpl*>(_object);
+ if (block) {
+ block->apply_state(_state);
+ block->set_enabled(true);
+ }
+ lilv_state_free(_state);
+ }
+
Broadcaster::Transfer t(*_engine.broadcaster());
if (_create_event) {
@@ -392,7 +453,7 @@ Delta::post_process()
}
for (auto& s : _set_events) {
- if (s->status() != Status::SUCCESS) {
+ if (s->synthetic() || s->status() != Status::SUCCESS) {
s->post_process(); // Set failed, report error
}
}
diff --git a/src/server/events/Delta.hpp b/src/server/events/Delta.hpp
index 43edacbf..750411ff 100644
--- a/src/server/events/Delta.hpp
+++ b/src/server/events/Delta.hpp
@@ -19,6 +19,8 @@
#include <vector>
+#include "lilv/lilv.h"
+
#include "raul/URI.hpp"
#include "ControlBindings.hpp"
@@ -87,6 +89,11 @@ public:
~Delta();
+ void add_set_event(const char* port_symbol,
+ const void* value,
+ uint32_t size,
+ uint32_t type);
+
bool pre_process();
void execute(ProcessContext& context);
void post_process();
@@ -98,7 +105,8 @@ private:
ENABLE_BROADCAST,
POLYPHONY,
POLYPHONIC,
- CONTROL_BINDING
+ CONTROL_BINDING,
+ PRESET
};
typedef std::vector<SetPortValue*> SetEvents;
@@ -113,6 +121,7 @@ private:
Ingen::Resource* _object;
GraphImpl* _graph;
CompiledGraph* _compiled_graph;
+ LilvState* _state;
Resource::Graph _context;
ControlBindings::Key _binding;
Type _type;
diff --git a/src/server/events/SetPortValue.cpp b/src/server/events/SetPortValue.cpp
index df0cb06d..655ff281 100644
--- a/src/server/events/SetPortValue.cpp
+++ b/src/server/events/SetPortValue.cpp
@@ -39,10 +39,12 @@ SetPortValue::SetPortValue(Engine& engine,
int32_t id,
SampleCount timestamp,
PortImpl* port,
- const Atom& value)
+ const Atom& value,
+ bool synthetic)
: Event(engine, client, id, timestamp)
, _port(port)
, _value(value)
+ , _synthetic(synthetic)
{
}
diff --git a/src/server/events/SetPortValue.hpp b/src/server/events/SetPortValue.hpp
index 852c694e..ed81db47 100644
--- a/src/server/events/SetPortValue.hpp
+++ b/src/server/events/SetPortValue.hpp
@@ -42,7 +42,8 @@ public:
int32_t id,
SampleCount timestamp,
PortImpl* port,
- const Atom& value);
+ const Atom& value,
+ bool synthetic = false);
~SetPortValue();
@@ -50,12 +51,15 @@ public:
void execute(ProcessContext& context);
void post_process();
+ bool synthetic() const { return _synthetic; }
+
private:
void apply(Context& context);
PortImpl* _port;
const Atom _value;
ControlBindings::Key _binding;
+ bool _synthetic;
};
} // namespace Events
diff --git a/wscript b/wscript
index 31384834..2ae08103 100644
--- a/wscript
+++ b/wscript
@@ -67,7 +67,7 @@ def configure(conf):
autowaf.check_pkg(conf, 'gthread-2.0', uselib_store='GTHREAD',
atleast_version='2.14.0', mandatory=True)
autowaf.check_pkg(conf, 'lilv-0', uselib_store='LILV',
- atleast_version='0.21.0', mandatory=True)
+ atleast_version='0.21.2', mandatory=True)
autowaf.check_pkg(conf, 'suil-0', uselib_store='SUIL',
atleast_version='0.2.0', mandatory=True)
autowaf.check_pkg(conf, 'sratom-0', uselib_store='SRATOM',