summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/interface/ClientInterface.h6
-rw-r--r--src/common/interface/EngineInterface.h6
-rw-r--r--src/common/util/Condition.h42
-rw-r--r--src/common/util/Makefile.am4
-rw-r--r--src/common/util/Mutex.h41
-rw-r--r--src/common/util/Semaphore.h2
-rw-r--r--src/common/util/Slave.h (renamed from src/libs/engine/Slave.h)8
-rw-r--r--src/common/util/Thread.h100
-rw-r--r--src/libs/client/ConnectionModel.cpp6
-rw-r--r--src/libs/client/OSCClientReceiver.cpp21
-rw-r--r--src/libs/client/OSCEngineSender.cpp20
-rw-r--r--src/libs/client/OSCEngineSender.h4
-rw-r--r--src/libs/client/ObjectModel.cpp12
-rw-r--r--src/libs/client/PatchLibrarian.cpp377
-rw-r--r--src/libs/client/PatchLibrarian.h22
-rw-r--r--src/libs/client/PatchModel.cpp24
-rw-r--r--src/libs/client/PluginModel.h41
-rw-r--r--src/libs/client/SigClientInterface.h40
-rw-r--r--src/libs/client/Store.cpp222
-rw-r--r--src/libs/client/Store.h20
-rw-r--r--src/libs/client/ThreadedSigClientInterface.h12
-rw-r--r--src/libs/engine/ClientBroadcaster.cpp10
-rw-r--r--src/libs/engine/ClientBroadcaster.h5
-rw-r--r--src/libs/engine/Engine.h2
-rw-r--r--src/libs/engine/Makefile.am7
-rw-r--r--src/libs/engine/NodeFactory.cpp19
-rw-r--r--src/libs/engine/NodeFactory.h1
-rw-r--r--src/libs/engine/OSCClientSender.cpp16
-rw-r--r--src/libs/engine/OSCClientSender.h6
-rw-r--r--src/libs/engine/OSCEngineReceiver.cpp57
-rw-r--r--src/libs/engine/OSCEngineReceiver.h5
-rw-r--r--src/libs/engine/ObjectSender.cpp90
-rw-r--r--src/libs/engine/ObjectSender.h4
-rw-r--r--src/libs/engine/Plugin.h9
-rw-r--r--src/libs/engine/PostProcessor.h2
-rw-r--r--src/libs/engine/QueuedEngineInterface.cpp33
-rw-r--r--src/libs/engine/QueuedEngineInterface.h4
-rw-r--r--src/libs/engine/QueuedEventSource.h2
-rw-r--r--src/libs/engine/Thread.cpp104
-rw-r--r--src/libs/engine/events.h2
-rw-r--r--src/libs/engine/events/AddNodeEvent.cpp31
-rw-r--r--src/libs/engine/events/AddNodeEvent.h18
-rw-r--r--src/libs/engine/events/AddPortEvent.cpp31
-rw-r--r--src/libs/engine/events/AddPortEvent.h2
-rw-r--r--src/libs/engine/events/CreatePatchEvent.cpp8
-rw-r--r--src/libs/engine/events/Makefile.am4
-rw-r--r--src/libs/engine/events/RequestAllObjectsEvent.cpp2
-rw-r--r--src/libs/engine/events/RequestObjectEvent.cpp97
-rw-r--r--src/libs/engine/events/RequestObjectEvent.h55
-rw-r--r--src/libs/engine/events/RequestPluginEvent.cpp78
-rw-r--r--src/libs/engine/events/RequestPluginEvent.h (renamed from src/libs/engine/Thread.h)48
-rw-r--r--src/progs/ingenuity/App.cpp2
-rw-r--r--src/progs/ingenuity/BreadCrumbBox.cpp18
-rw-r--r--src/progs/ingenuity/BreadCrumbBox.h4
-rw-r--r--src/progs/ingenuity/LoadPluginWindow.cpp4
-rw-r--r--src/progs/ingenuity/LoadSubpatchWindow.cpp15
-rw-r--r--src/progs/ingenuity/Loader.cpp216
-rw-r--r--src/progs/ingenuity/Loader.h120
-rw-r--r--src/progs/ingenuity/NodeMenu.cpp3
-rw-r--r--src/progs/ingenuity/NodeModule.cpp22
-rw-r--r--src/progs/ingenuity/NodeModule.h1
-rw-r--r--src/progs/ingenuity/PatchCanvas.cpp13
-rw-r--r--src/progs/ingenuity/PatchView.cpp10
-rw-r--r--src/progs/ingenuity/PatchView.h1
-rw-r--r--src/progs/ingenuity/PatchWindow.cpp19
-rw-r--r--src/progs/ingenuity/PatchWindow.h4
66 files changed, 1253 insertions, 981 deletions
diff --git a/src/common/interface/ClientInterface.h b/src/common/interface/ClientInterface.h
index 5d56fa8e..3a9d9508 100644
--- a/src/common/interface/ClientInterface.h
+++ b/src/common/interface/ClientInterface.h
@@ -57,14 +57,12 @@ public:
virtual void num_plugins(uint32_t num_plugins) = 0;
- virtual void new_plugin(string type,
- string uri,
+ virtual void new_plugin(string uri,
string name) = 0;
virtual void new_patch(string path, uint32_t poly) = 0;
- virtual void new_node(string plugin_type,
- string plugin_uri,
+ virtual void new_node(string plugin_uri,
string node_path,
bool is_polyphonic,
uint32_t num_ports) = 0;
diff --git a/src/common/interface/EngineInterface.h b/src/common/interface/EngineInterface.h
index b8dcb6d8..1c07a561 100644
--- a/src/common/interface/EngineInterface.h
+++ b/src/common/interface/EngineInterface.h
@@ -117,8 +117,12 @@ public:
virtual void ping() = 0;
+ virtual void request_plugin(const string& uri) = 0;
+
+ virtual void request_object(const string& path) = 0;
+
virtual void request_port_value(const string& port_path) = 0;
-
+
virtual void request_plugins() = 0;
virtual void request_all_objects() = 0;
diff --git a/src/common/util/Condition.h b/src/common/util/Condition.h
new file mode 100644
index 00000000..1ee28dbd
--- /dev/null
+++ b/src/common/util/Condition.h
@@ -0,0 +1,42 @@
+/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef CONDITION_H
+#define CONDITION_H
+
+#include <pthread.h>
+
+
+/** Trivial (but pretty) wrapper around POSIX Conditions (zero memory overhead).
+ *
+ * A semaphore that isn't a counter and is slow and NOT realtime safe.
+ */
+class Condition {
+public:
+ inline Condition() { pthread_cond_init(&_cond, NULL); }
+
+ inline ~Condition() { pthread_cond_destroy(&_cond); }
+
+ inline void signal() { pthread_cond_signal(&_cond); }
+ inline void wait(Mutex& mutex) { pthread_cond_wait(&_cond, &mutex._mutex); }
+
+private:
+ pthread_cond_t _cond;
+};
+
+
+#endif // CONDITION_H
+
diff --git a/src/common/util/Makefile.am b/src/common/util/Makefile.am
index 46bc3691..845a5d9a 100644
--- a/src/common/util/Makefile.am
+++ b/src/common/util/Makefile.am
@@ -3,5 +3,9 @@ EXTRA_DIST = \
Path.h \
Queue.h \
Semaphore.h \
+ Mutex.h \
+ Condition.h \
+ Thread.h \
+ Slave.h \
Atom.h \
LibloAtom.h
diff --git a/src/common/util/Mutex.h b/src/common/util/Mutex.h
new file mode 100644
index 00000000..c5aaf3ae
--- /dev/null
+++ b/src/common/util/Mutex.h
@@ -0,0 +1,41 @@
+/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef MUTEX_H
+#define MUTEX_H
+
+#include <pthread.h>
+
+
+/** Trivial (but pretty) wrapper around POSIX Mutexes (zero memory overhead).
+ */
+class Mutex {
+public:
+ inline Mutex() { pthread_mutex_init(&_mutex, NULL); }
+
+ inline ~Mutex() { pthread_mutex_destroy(&_mutex); }
+
+ inline bool try_lock() { return (pthread_mutex_trylock(&_mutex) == 0); }
+ inline void lock() { pthread_mutex_lock(&_mutex); }
+ inline void unlock() { pthread_mutex_unlock(&_mutex); }
+
+private:
+ friend class Condition;
+ pthread_mutex_t _mutex;
+};
+
+
+#endif // MUTEX_H
diff --git a/src/common/util/Semaphore.h b/src/common/util/Semaphore.h
index a98124bf..168a7059 100644
--- a/src/common/util/Semaphore.h
+++ b/src/common/util/Semaphore.h
@@ -20,7 +20,7 @@
#include <semaphore.h>
-/** Trivial wrapper around POSIX semaphores.
+/** Trivial wrapper around POSIX semaphores (zero memory overhead).
*
* This was created to provide an alternative debuggable implementation of
* semaphores based on a cond/mutex pair because semaphore's appeared not to
diff --git a/src/libs/engine/Slave.h b/src/common/util/Slave.h
index b48a3ab7..0d0976b8 100644
--- a/src/libs/engine/Slave.h
+++ b/src/common/util/Slave.h
@@ -19,9 +19,7 @@
#include <pthread.h>
#include "util/Semaphore.h"
-#include "Thread.h"
-
-namespace Ingen {
+#include "util/Thread.h"
/** Thread driven by (realtime safe) signals.
@@ -42,7 +40,7 @@ protected:
Semaphore _whip;
private:
- // Prevent copies
+ // Prevent copies (undefined)
Slave(const Slave&);
Slave& operator=(const Slave&);
@@ -56,6 +54,4 @@ private:
};
-} // namespace Ingen
-
#endif // SLAVE_H
diff --git a/src/common/util/Thread.h b/src/common/util/Thread.h
new file mode 100644
index 00000000..c139434b
--- /dev/null
+++ b/src/common/util/Thread.h
@@ -0,0 +1,100 @@
+/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef THREAD_H
+#define THREAD_H
+
+#include <string>
+#include <iostream>
+#include <pthread.h>
+
+
+/** Abstract base class for a thread.
+ *
+ * Extend this and override the _run method to easily create a thread
+ * to perform some task.
+ *
+ * \ingroup engine
+ */
+class Thread
+{
+public:
+ Thread() : _pthread_exists(false) {}
+
+ virtual ~Thread() { stop(); }
+
+ void set_name(const std::string& name) { _name = name; }
+
+ virtual void start() {
+ std::cout << "[" << _name << " Thread] Starting." << std::endl;
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 1500000);
+
+ pthread_create(&_pthread, &attr, _static_run, this);
+ _pthread_exists = true;
+ }
+
+ virtual void stop() {
+ if (_pthread_exists) {
+ pthread_cancel(_pthread);
+ pthread_join(_pthread, NULL);
+ _pthread_exists = false;
+ }
+ }
+
+ void set_scheduling(int policy, unsigned int priority) {
+ sched_param sp;
+ sp.sched_priority = priority;
+ int result = pthread_setschedparam(_pthread, SCHED_FIFO, &sp);
+ if (!result) {
+ std::cout << "[" << _name << "] Set scheduling policy to ";
+ switch (policy) {
+ case SCHED_FIFO: std::cout << "SCHED_FIFO"; break;
+ case SCHED_RR: std::cout << "SCHED_RR"; break;
+ case SCHED_OTHER: std::cout << "SCHED_OTHER"; break;
+ default: std::cout << "UNKNOWN"; break;
+ }
+ std::cout << ", priority " << sp.sched_priority << std::endl;
+ } else {
+ std::cout << "[" << _name << "] Unable to set scheduling policy ("
+ << strerror(result) << ")" << std::endl;
+ }
+ }
+
+
+protected:
+ virtual void _run() = 0;
+
+private:
+ // Prevent copies (undefined)
+ Thread(const Thread&);
+ Thread& operator=(const Thread&);
+
+ inline static void* _static_run(void* me) {
+ Thread* myself = (Thread*)me;
+ myself->_run();
+ return NULL; // and I
+ }
+
+ std::string _name;
+ bool _pthread_exists;
+ pthread_t _pthread;
+};
+
+
+#endif // THREAD_H
diff --git a/src/libs/client/ConnectionModel.cpp b/src/libs/client/ConnectionModel.cpp
index 421b620d..e120207d 100644
--- a/src/libs/client/ConnectionModel.cpp
+++ b/src/libs/client/ConnectionModel.cpp
@@ -14,6 +14,7 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <cassert>
#include "ConnectionModel.h"
#include "PortModel.h"
#include "PatchModel.h"
@@ -38,6 +39,11 @@ ConnectionModel::ConnectionModel(CountedPtr<PortModel> src, CountedPtr<PortModel
_src_port(src),
_dst_port(dst)
{
+ assert(_src_port);
+ assert(_dst_port);
+ assert(_src_port->parent());
+ assert(_dst_port->parent());
+
// Be sure connection is within one patch
//assert(_src_port_path.parent().parent()
// == _dst_port_path.parent().parent());
diff --git a/src/libs/client/OSCClientReceiver.cpp b/src/libs/client/OSCClientReceiver.cpp
index e5a2ccc3..0ae41e75 100644
--- a/src/libs/client/OSCClientReceiver.cpp
+++ b/src/libs/client/OSCClientReceiver.cpp
@@ -67,7 +67,7 @@ OSCClientReceiver::start()
}
// Print all incoming messages
- lo_server_thread_add_method(_st, NULL, NULL, generic_cb, NULL);
+ //lo_server_thread_add_method(_st, NULL, NULL, generic_cb, NULL);
//lo_server_thread_add_method(_st, "/om/response/ok", "i", om_response_ok_cb, this);
//lo_server_thread_add_method(_st, "/om/response/error", "is", om_responseerror_cb, this);
@@ -139,7 +139,7 @@ OSCClientReceiver::setup_callbacks()
{
lo_server_thread_add_method(_st, "/om/response", "iis", response_cb, this);
lo_server_thread_add_method(_st, "/om/num_plugins", "i", num_plugins_cb, this);
- lo_server_thread_add_method(_st, "/om/plugin", "sss", plugin_cb, this);
+ lo_server_thread_add_method(_st, "/om/plugin", "ss", plugin_cb, this);
lo_server_thread_add_method(_st, "/om/new_patch", "si", new_patch_cb, this);
lo_server_thread_add_method(_st, "/om/destroyed", "s", destroyed_cb, this);
lo_server_thread_add_method(_st, "/om/patch_enabled", "s", patch_enabled_cb, this);
@@ -148,7 +148,7 @@ OSCClientReceiver::setup_callbacks()
lo_server_thread_add_method(_st, "/om/object_renamed", "ss", object_renamed_cb, this);
lo_server_thread_add_method(_st, "/om/new_connection", "ss", connection_cb, this);
lo_server_thread_add_method(_st, "/om/disconnection", "ss", disconnection_cb, this);
- lo_server_thread_add_method(_st, "/om/new_node", "sssii", new_node_cb, this);
+ lo_server_thread_add_method(_st, "/om/new_node", "ssii", new_node_cb, this);
lo_server_thread_add_method(_st, "/om/new_port", "ssi", new_port_cb, this);
lo_server_thread_add_method(_st, "/om/metadata/update", NULL, metadata_update_cb, this);
lo_server_thread_add_method(_st, "/om/control_change", "sf", control_change_cb, this);
@@ -246,13 +246,12 @@ OSCClientReceiver::m_disconnection_cb(const char* path, const char* types, lo_ar
int
OSCClientReceiver::m_new_node_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
{
- const char* type = &argv[0]->s;
- const char* uri = &argv[1]->s;
- const char* node_path = &argv[2]->s;
- const int32_t poly = argv[3]->i;
- const int32_t num_ports = argv[4]->i;
+ const char* uri = &argv[0]->s;
+ const char* node_path = &argv[1]->s;
+ const int32_t poly = argv[2]->i;
+ const int32_t num_ports = argv[3]->i;
- new_node(type, uri, node_path, poly, num_ports);
+ new_node(uri, node_path, poly, num_ports);
/*_receiving_node_model = new NodeModel(node_path);
_receiving_node_model->polyphonic((poly == 1));
@@ -386,8 +385,8 @@ OSCClientReceiver::m_num_plugins_cb(const char* path, const char* types, lo_arg*
int
OSCClientReceiver::m_plugin_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
{
- assert(argc == 3 && !strcmp(types, "sss"));
- new_plugin(&argv[0]->s, &argv[1]->s, &argv[2]->s); // type, uri
+ assert(argc == 2 && !strcmp(types, "ss"));
+ new_plugin(&argv[0]->s, &argv[1]->s); // type, uri
return 0;
}
diff --git a/src/libs/client/OSCEngineSender.cpp b/src/libs/client/OSCEngineSender.cpp
index 7bc67aa0..826b53b2 100644
--- a/src/libs/client/OSCEngineSender.cpp
+++ b/src/libs/client/OSCEngineSender.cpp
@@ -397,6 +397,26 @@ OSCEngineSender::ping()
void
+OSCEngineSender::request_plugin(const string& uri)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/request/plugin", "is",
+ next_id(),
+ uri.c_str());
+}
+
+
+void
+OSCEngineSender::request_object(const string& path)
+{
+ assert(_engine_addr);
+ lo_send(_engine_addr, "/om/request/object", "is",
+ next_id(),
+ path.c_str());
+}
+
+
+void
OSCEngineSender::request_port_value(const string& port_path)
{
assert(_engine_addr);
diff --git a/src/libs/client/OSCEngineSender.h b/src/libs/client/OSCEngineSender.h
index 1a4fa0e5..fb133706 100644
--- a/src/libs/client/OSCEngineSender.h
+++ b/src/libs/client/OSCEngineSender.h
@@ -131,6 +131,10 @@ public:
void ping();
+ void request_plugin(const string& uri);
+
+ void request_object(const string& path);
+
void request_port_value(const string& port_path);
void request_plugins();
diff --git a/src/libs/client/ObjectModel.cpp b/src/libs/client/ObjectModel.cpp
index 6e18e680..e50882ca 100644
--- a/src/libs/client/ObjectModel.cpp
+++ b/src/libs/client/ObjectModel.cpp
@@ -66,11 +66,13 @@ ObjectModel::assimilate(CountedPtr<ObjectModel> model)
{
assert(_path == model->path());
- for (MetadataMap::const_iterator i = model->metadata().begin();
- i != model->metadata().end(); ++i) {
- MetadataMap::const_iterator i = _metadata.find(i->first);
- if (i == _metadata.end())
- _metadata[i->first] = i->second;
+ for (MetadataMap::const_iterator other = model->metadata().begin();
+ other != model->metadata().end(); ++other) {
+
+ MetadataMap::const_iterator mine = _metadata.find(other->first);
+
+ if (mine == _metadata.end())
+ _metadata[other->first] = other->second;
}
}
diff --git a/src/libs/client/PatchLibrarian.cpp b/src/libs/client/PatchLibrarian.cpp
index ebc33f36..00687993 100644
--- a/src/libs/client/PatchLibrarian.cpp
+++ b/src/libs/client/PatchLibrarian.cpp
@@ -117,6 +117,7 @@ PatchLibrarian::translate_load_path(const string& path)
* - The filename does not have an extension (ie contain a ".")
* - The patch_model has no (Ingen) path
*/
+#if 0
void
PatchLibrarian::save_patch(CountedPtr<PatchModel> patch_model, const string& filename, bool recursive)
{
@@ -360,6 +361,7 @@ PatchLibrarian::save_patch(CountedPtr<PatchModel> patch_model, const string& fil
xmlFreeDoc(xml_doc);
xmlCleanupParser();
}
+#endif
/** Load a patch in to the engine (and client) from a patch file.
@@ -369,47 +371,52 @@ PatchLibrarian::save_patch(CountedPtr<PatchModel> patch_model, const string& fil
* is 0, it will be loaded from file. Otherwise the given values will
* be used.
*
- * If @a wait is set, the patch will be checked for existence before
+ * @param wait If true the patch will be checked for existence before
* loading everything in to it (to prevent messing up existing patches
* that exist at the path this one should load as).
*
- * If the @a existing parameter is true, the patch will be loaded into a
- * currently existing patch (ie a merging will take place). Errors will
- * result if Nodes of conflicting names exist.
+ * @param existing If true, the patch will be loaded into a currently
+ * existing patch (ie a merging will take place). Errors will result
+ * if Nodes of conflicting names exist.
+ *
+ * @param parent_path Patch to load this patch as a child of (empty string to load
+ * to the root patch)
+ *
+ * @param name Name of this patch (loaded/generated if the empty string)
+ *
+ * @param initial_data will be set last, so values passed there will override
+ * any values loaded from the patch file.
*
* Returns the path of the newly created patch.
*/
string
-PatchLibrarian::load_patch(CountedPtr<PatchModel> pm, bool wait, bool existing)
+PatchLibrarian::load_patch(const string& filename,
+ const string& parent_path,
+ const string& name,
+ size_t poly,
+ MetadataMap initial_data,
+ bool existing)
{
- string filename = pm->filename();
+ cerr << "[PatchLibrarian] Loading patch " << filename << "" << endl;
- string additional_path = (!pm->parent())
- ? "" : ((PatchModel*)pm->parent().get())->filename();
- additional_path = additional_path.substr(0, additional_path.find_last_of("/"));
+ Path path = "/"; // path of the new patch
- filename = find_file(pm->filename(), additional_path);
-
- size_t poly = pm->poly();
-
- //cerr << "[PatchLibrarian] Loading patch " << filename << "" << endl;
-
- //const size_t temp_buf_length = 255;
- //char temp_buf[temp_buf_length];
-
- bool load_name = (pm->path() == "");
- bool load_poly = (poly == 0);
+ const bool load_name = (name == "");
+ const bool load_poly = (poly == 0);
+ if (initial_data.find("filename") == initial_data.end())
+ initial_data["filename"] = Atom(filename.c_str()); // FIXME: URL?
+
xmlDocPtr doc = xmlParseFile(filename.c_str());
- if (doc == NULL ) {
+ if (!doc) {
cerr << "Unable to parse patch file." << endl;
return "";
}
xmlNodePtr cur = xmlDocGetRootElement(doc);
- if (cur == NULL) {
+ if (!cur) {
cerr << "Empty document." << endl;
xmlFreeDoc(doc);
return "";
@@ -423,10 +430,6 @@ PatchLibrarian::load_patch(CountedPtr<PatchModel> pm, bool wait, bool existing)
xmlChar* key = NULL;
cur = cur->xmlChildrenNode;
- string path;
-
- cerr << "FIXME: patch filename" << endl;
- //pm->filename(filename);
// Load Patch attributes
while (cur != NULL) {
@@ -435,21 +438,12 @@ PatchLibrarian::load_patch(CountedPtr<PatchModel> pm, bool wait, bool existing)
if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) {
if (load_name) {
assert(key != NULL);
- if (pm->parent()) {
- path = pm->parent()->path().base() + string((char*)key);
- } else {
- path = string("/") + string((char*)key);
- }
- assert(path.find("//") == string::npos);
- assert(path.length() > 0);
- cerr << "FIXME: patch path (2)" << endl;
- //pm->set_path(path);
+ if (parent_path != "")
+ path = Path(parent_path).base() + Path::nameify((char*)key);
}
} else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) {
if (load_poly) {
poly = atoi((char*)key);
- cerr << "FIXME: patch poly" << endl;
- //pm->poly(poly);
}
} else if (xmlStrcmp(cur->name, (const xmlChar*)"connection")
&& xmlStrcmp(cur->name, (const xmlChar*)"node")
@@ -458,12 +452,9 @@ PatchLibrarian::load_patch(CountedPtr<PatchModel> pm, bool wait, bool existing)
&& xmlStrcmp(cur->name, (const xmlChar*)"preset")) {
// Don't know what this tag is, add it as metadata without overwriting
// (so caller can set arbitrary parameters which will be preserved)
- if (key != NULL)
- cerr << "FIXME: save metadata\n";
- /*
- if (pm->get_metadata((const char*)cur->name) == "")
- pm->set_metadata((const char*)cur->name, (const char*)key);
- */
+ if (key)
+ if (initial_data.find((const char*)cur->name) == initial_data.end())
+ initial_data[(const char*)cur->name] = (const char*)key;
}
xmlFree(key);
@@ -472,57 +463,19 @@ PatchLibrarian::load_patch(CountedPtr<PatchModel> pm, bool wait, bool existing)
cur = cur->next;
}
- if (poly == 0) poly = 1;
-
- if (!existing) {
- // Wait until the patch is created or the node creations may fail
- if (wait) {
- //int id = _engine->get_next_request_id();
- //_engine->set_wait_response_id(id);
- cerr << "FIXME: create patch\n";
- //_engine->create_patch_from_model(pm.get());
- //bool succeeded = _engine->wait_for_response();
-
- // If creating the patch failed, bail out so we don't load all these nodes
- // into an already existing patch
- /*if (!succeeded) {
- cerr << "[PatchLibrarian] Patch load failed (patch already exists)" << endl;
- return "";
- }*/ // FIXME
- } else {
- cerr << "FIXME: create patch (2)\n";
- //_engine->create_patch_from_model(pm.get());
- }
- }
-
+ if (poly == 0)
+ poly = 1;
- // Set the filename metadata. (FIXME)
- // This isn't so good, considering multiple clients on multiple machines, and
- // absolute filesystem paths obviously aren't going to be correct. But for now
- // this is all I can figure out to have Save/Save As work properly for subpatches
- _engine->set_metadata(pm->path(), "filename", Atom(pm->filename().c_str()));
+ // Create it, if we're not merging
+ if (!existing)
+ _engine->create_patch_with_data(path, poly, initial_data);
// Load nodes
cur = xmlDocGetRootElement(doc)->xmlChildrenNode;
-
while (cur != NULL) {
- if ((!xmlStrcmp(cur->name, (const xmlChar*)"node"))) {
- CountedPtr<NodeModel> nm = parse_node(pm, doc, cur);
- if (nm) {
- cerr << "FIXME: load node\n";
- //_engine->create_node_from_model(nm.get());
- //_engine->set_all_metadata(nm.get());
-
- /*
- //for (PortModelList::const_iterator j = nm->ports().begin(); j != nm->ports().end(); ++j) {
- // FIXME: ew
- snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_min());
- _engine->set_metadata((*j)->path(), "user-min", temp_buf);
- snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_max());
- _engine->set_metadata((*j)->path(), "user-max", temp_buf);
- }*/
- }
- }
+ if ((!xmlStrcmp(cur->name, (const xmlChar*)"node")))
+ load_node(path, doc, cur);
+
cur = cur->next;
}
@@ -530,84 +483,87 @@ PatchLibrarian::load_patch(CountedPtr<PatchModel> pm, bool wait, bool existing)
cur = xmlDocGetRootElement(doc)->xmlChildrenNode;
while (cur != NULL) {
if ((!xmlStrcmp(cur->name, (const xmlChar*)"subpatch"))) {
- load_subpatch(pm, doc, cur);
+ load_subpatch(path, doc, cur);
}
cur = cur->next;
}
- ConnectionModel* cm = NULL;
// Load connections
cur = xmlDocGetRootElement(doc)->xmlChildrenNode;
while (cur != NULL) {
if ((!xmlStrcmp(cur->name, (const xmlChar*)"connection"))) {
- cm = parse_connection(pm, doc, cur);
- if (cm != NULL) {
- _engine->connect(cm->src_port_path(), cm->dst_port_path());
- }
+ load_connection(path, doc, cur);
}
cur = cur->next;
}
// Load presets (control values)
- PresetModel* preset_model = NULL;
- cur = xmlDocGetRootElement(doc)->xmlChildrenNode;
+ cerr << "FIXME: load preset\n";
+ /*cur = xmlDocGetRootElement(doc)->xmlChildrenNode;
while (cur != NULL) {
if ((!xmlStrcmp(cur->name, (const xmlChar*)"preset"))) {
- preset_model = parse_preset(pm, doc, cur);
+ load_preset(pm, doc, cur);
assert(preset_model != NULL);
if (preset_model->name() == "default")
_engine->set_preset(pm->path(), preset_model);
}
cur = cur->next;
}
+ */
xmlFreeDoc(doc);
xmlCleanupParser();
- _engine->set_metadata_map(pm->path(), pm->metadata());
+ // Done above.. late enough?
+ //_engine->set_metadata_map(path, initial_data);
if (!existing)
- _engine->enable_patch(pm->path());
+ _engine->enable_patch(path);
_load_path_translations.clear();
- string ret = pm->path();
- return ret;
+ return path;
}
/** Build a NodeModel given a pointer to a Node in a patch file.
*/
-CountedPtr<NodeModel>
-PatchLibrarian::parse_node(const CountedPtr<const PatchModel> parent, xmlDocPtr doc, const xmlNodePtr node)
+bool
+PatchLibrarian::load_node(const Path& parent, xmlDocPtr doc, const xmlNodePtr node)
{
-cerr << "FIXME: load node\n";
-#if 0
- CountedPtr<PluginModel> plugin(new PluginModel());
-
xmlChar* key;
xmlNodePtr cur = node->xmlChildrenNode;
- string path = ""'
+ string path = "";
bool polyphonic = false;
+ string plugin_uri;
+
+ string plugin_type; // deprecated
+ string library_name; // deprecated
+ string plugin_label; // deprecated
+
+ MetadataMap initial_data;
+
while (cur != NULL) {
key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) {
- path = parent->path().base() + Path::nameify((char*)key));
+ path = parent.base() + Path::nameify((char*)key);
} else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphonic"))) {
polyphonic = !strcmp((char*)key, "true");
} else if ((!xmlStrcmp(cur->name, (const xmlChar*)"type"))) {
- plugin->set_type((const char*)key);
+ plugin_type = (const char*)key;
} else if ((!xmlStrcmp(cur->name, (const xmlChar*)"library-name"))) {
- plugin->lib_name((char*)key);
+ library_name = (char*)key;
} else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-label"))) {
- plugin->plug_label((char*)key);
+ plugin_label = (char*)key;
} else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-uri"))) {
- plugin->uri((char*)key);
+ plugin_uri = (char*)key;
} else if ((!xmlStrcmp(cur->name, (const xmlChar*)"port"))) {
+ cerr << "FIXME: load port\n";
+#if 0
xmlNodePtr child = cur->xmlChildrenNode;
string port_name;
@@ -640,12 +596,15 @@ cerr << "FIXME: load node\n";
0.0, user_min, user_max));
//pm->set_parent(nm);
nm->add_port(pm);
+#endif
// DSSI hacks. Stored in the patch files as special elements, but sent to
// the engine as normal metadata with specially formatted key/values. Not
// sure if this is the best way to go about this, but it's the least damaging
// right now
} else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-program"))) {
+ cerr << "FIXME: load dssi program\n";
+#if 0
xmlNodePtr child = cur->xmlChildrenNode;
string bank;
@@ -665,8 +624,11 @@ cerr << "FIXME: load node\n";
child = child->next;
}
nm->set_metadata("dssi-program", Atom(bank.append("/").append(program).c_str()));
+#endif
} else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-configure"))) {
+ cerr << "FIXME: load dssi configure\n";
+#if 0
xmlNodePtr child = cur->xmlChildrenNode;
string dssi_key;
@@ -687,10 +649,18 @@ cerr << "FIXME: load node\n";
child = child->next;
}
nm->set_metadata(string("dssi-configure--").append(dssi_key), Atom(dssi_value.c_str()));
-
+#endif
} else { // Don't know what this tag is, add it as metadata
- if (key != NULL)
- nm->set_metadata((const char*)cur->name, (const char*)key);
+ if (key) {
+
+ // Hack to make module-x and module-y set as floats
+ char* endptr = NULL;
+ float fval = strtof((const char*)key, &endptr);
+ if (endptr != (char*)key && *endptr == '\0')
+ initial_data[(const char*)cur->name] = Atom(fval);
+ else
+ initial_data[(const char*)cur->name] = Atom((const char*)key);
+ }
}
xmlFree(key);
key = NULL;
@@ -698,37 +668,41 @@ cerr << "FIXME: load node\n";
cur = cur->next;
}
- if (nm->path() == "") {
+ if (path == "") {
cerr << "[PatchLibrarian] Malformed patch file (node tag has empty children)" << endl;
cerr << "[PatchLibrarian] Node ignored." << endl;
- return CountedPtr<NodeModel>();
+ return false;
+ }
- // Compatibility hacks for old patches
- } else if (plugin->type() == PluginModel::Internal) {
+ // Compatibility hacks for old patches that represent patch ports as nodes
+ if (plugin_uri == "") {
+ cerr << "WARNING: Loading deprecated Node. Resave! " << path << endl;
bool is_port = false;
- const string path = Path::pathify(nm->path());
- if (plugin->plug_label() == "audio_input") {
- _engine->create_port(path, "AUDIO", false);
- is_port = true;
- } else if ( plugin->plug_label() == "audio_output") {
- _engine->create_port(path, "AUDIO", true);
- is_port = true;
- } else if ( plugin->plug_label() == "control_input") {
- _engine->create_port(path, "CONTROL", false);
- is_port = true;
- } else if ( plugin->plug_label() == "control_output" ) {
- _engine->create_port(path, "CONTROL", true);
- is_port = true;
- } else if ( plugin->plug_label() == "midi_input") {
- _engine->create_port(path, "MIDI", false);
- is_port = true;
- } else if ( plugin->plug_label() == "midi_output" ) {
- _engine->create_port(path, "MIDI", true);
- is_port = true;
+
+ if (plugin_type == "Internal") {
+ if (plugin_label == "audio_input") {
+ _engine->create_port(path, "AUDIO", false);
+ is_port = true;
+ } else if (plugin_label == "audio_output") {
+ _engine->create_port(path, "AUDIO", true);
+ is_port = true;
+ } else if (plugin_label == "control_input") {
+ _engine->create_port(path, "CONTROL", false);
+ is_port = true;
+ } else if (plugin_label == "control_output" ) {
+ _engine->create_port(path, "CONTROL", true);
+ is_port = true;
+ } else if (plugin_label == "midi_input") {
+ _engine->create_port(path, "MIDI", false);
+ is_port = true;
+ } else if (plugin_label == "midi_output" ) {
+ _engine->create_port(path, "MIDI", true);
+ is_port = true;
+ }
}
if (is_port) {
- const string old_path = nm->path();
+ const string old_path = path;
const string new_path = Path::pathify(old_path);
// Set up translations (for connections etc) to alias both the old
@@ -737,58 +711,71 @@ cerr << "FIXME: load node\n";
_load_path_translations[old_path + "/in"] = new_path;
_load_path_translations[old_path + "/out"] = new_path;
- nm->set_path(new_path);
- _engine->set_all_metadata(nm.get());
+ path = new_path;
+
+ _engine->set_metadata_map(path, initial_data);
+
return CountedPtr<NodeModel>();
+
} else {
- if (plugin->uri() == "") {
- if (plugin->plug_label() == "note_in") {
- plugin->uri("ingen:note_node");
- } else if (plugin->plug_label() == "control_input") {
- plugin->uri("ingen:control_node");
- } else if (plugin->plug_label() == "transport") {
- plugin->uri("ingen:transport_node");
- } else if (plugin->plug_label() == "trigger_in") {
- plugin->uri("ingen:trigger_node");
- }
+ if (plugin_label == "note_in") {
+ plugin_uri = "ingen:note_node";
+ } else if (plugin_label == "control_input") {
+ plugin_uri = "ingen:control_node";
+ } else if (plugin_label == "transport") {
+ plugin_uri = "ingen:transport_node";
+ } else if (plugin_label == "trigger_in") {
+ plugin_uri = "ingen:trigger_node";
+ } else {
+ cerr << "WARNING: Unknown deprecated node (label " << plugin_label
+ << ")." << endl;
}
+
+ if (plugin_uri != "")
+ _engine->create_node(path, plugin_uri, polyphonic);
+ else
+ _engine->create_node(path, plugin_type, library_name, plugin_label, polyphonic);
+
+ _engine->set_metadata_map(path, initial_data);
+
+ return true;
}
+
+ // Not deprecated
+ } else {
+ _engine->create_node(path, plugin_uri, polyphonic);
+ _engine->set_metadata_map(path, initial_data);
+ return true;
}
- //nm->plugin(plugin);
-
- return nm;
-#endif
- return CountedPtr<NodeModel>();
+ // (shouldn't get here)
}
-void
-PatchLibrarian::load_subpatch(const CountedPtr<PatchModel> parent, xmlDocPtr doc, const xmlNodePtr subpatch)
+bool
+PatchLibrarian::load_subpatch(const Path& parent, xmlDocPtr doc, const xmlNodePtr subpatch)
{
- //xmlChar *key;
- //xmlNodePtr cur = subpatch->xmlChildrenNode;
+ xmlChar *key;
+ xmlNodePtr cur = subpatch->xmlChildrenNode;
- cerr << "FIXME: load subpatch" << endl;
-
-#if 0
- //CountedPtr<PatchModel> pm(new PatchModel("/UNINITIALIZED", 1)); // FIXME: ew
+ string name = "";
+ string filename = "";
+ size_t poly = 0;
+ MetadataMap initial_data;
+
while (cur != NULL) {
key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) {
- if (parent == NULL)
- pm->set_path(string("/") + (const char*)key);
- else
- pm->set_path(parent->path().base() + (const char*)key);
+ name = (const char*)key;
} else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) {
- pm->poly(atoi((const char*)key));
+ poly = atoi((const char*)key);
} else if ((!xmlStrcmp(cur->name, (const xmlChar*)"filename"))) {
- pm->filename((const char*)key);
+ filename = (const char*)key;
} else { // Don't know what this tag is, add it as metadata
if (key != NULL && strlen((const char*)key) > 0)
- pm->set_metadata((const char*)cur->name, (const char*)key);
+ initial_data[(const char*)cur->name] = Atom((const char*)key);
}
xmlFree(key);
key = NULL;
@@ -796,25 +783,19 @@ PatchLibrarian::load_subpatch(const CountedPtr<PatchModel> parent, xmlDocPtr doc
cur = cur->next;
}
- // This needs to be done after setting the path above, to prevent
- // NodeModel::set_path from calling it's parent's rename_node with
- // an invalid (nonexistant) name
- pm->set_parent(parent);
-
- load_patch(pm, false);
-#endif
+ // load_patch sets the passed metadata last, so values stored in the parent
+ // will override values stored in the child patch file
+ string path = load_patch(filename, parent, name, poly, initial_data, false);
+
+ return false;
}
/** Build a ConnectionModel given a pointer to a connection in a patch file.
*/
-ConnectionModel*
-PatchLibrarian::parse_connection(const CountedPtr<const PatchModel> parent, xmlDocPtr doc, const xmlNodePtr node)
+bool
+PatchLibrarian::load_connection(const Path& parent, xmlDocPtr doc, const xmlNodePtr node)
{
- //cerr << "[PatchLibrarian] Parsing connection..." << endl;
-
- cerr << "FIXME: load connection" << endl;
-#if 0
xmlChar *key;
xmlNodePtr cur = node->xmlChildrenNode;
@@ -840,9 +821,9 @@ PatchLibrarian::parse_connection(const CountedPtr<const PatchModel> parent, xmlD
}
if (source_node == "" || source_port == "" || dest_node == "" || dest_port == "") {
- cerr << "[PatchLibrarian] Malformed patch file (connection tag has empty children)" << endl;
- cerr << "[PatchLibrarian] Connection ignored." << endl;
- return NULL;
+ cerr << "ERROR: Malformed patch file (connection tag has empty children)" << endl;
+ cerr << "ERROR: Connection ignored." << endl;
+ return false;
}
// Compatibility fixes for old (fundamentally broken) patches
@@ -851,21 +832,21 @@ PatchLibrarian::parse_connection(const CountedPtr<const PatchModel> parent, xmlD
dest_node = Path::nameify(dest_node);
dest_port = Path::nameify(dest_port);
- ConnectionModel* cm = new ConnectionModel(
- translate_load_path(parent->path().base() + source_node +"/"+ source_port),
- translate_load_path(parent->path().base() + dest_node +"/"+ dest_port));
+ _engine->connect(
+ translate_load_path(parent.base() + source_node +"/"+ source_port),
+ translate_load_path(parent.base() + dest_node +"/"+ dest_port));
- return cm;
-#endif
- return 0;
+ return true;
}
/** Build a PresetModel given a pointer to a preset in a patch file.
*/
-PresetModel*
-PatchLibrarian::parse_preset(const CountedPtr<const PatchModel> patch, xmlDocPtr doc, const xmlNodePtr node)
+bool
+PatchLibrarian::load_preset(const Path& parent, xmlDocPtr doc, const xmlNodePtr node)
{
+ cerr << "FIXME: load preset\n";
+#if 0
xmlNodePtr cur = node->xmlChildrenNode;
xmlChar* key;
@@ -929,6 +910,8 @@ PatchLibrarian::parse_preset(const CountedPtr<const PatchModel> patch, xmlDocPtr
}
return pm;
+#endif
+ return false;
}
} // namespace Client
diff --git a/src/libs/client/PatchLibrarian.h b/src/libs/client/PatchLibrarian.h
index cf90d876..893d5cdc 100644
--- a/src/libs/client/PatchLibrarian.h
+++ b/src/libs/client/PatchLibrarian.h
@@ -23,6 +23,8 @@
#include <libxml/tree.h>
#include <cassert>
#include "util/CountedPtr.h"
+#include "util/Path.h"
+#include "ObjectModel.h"
using std::string;
@@ -43,8 +45,6 @@ class ModelEngineInterface;
class PatchLibrarian
{
public:
- // FIXME: return booleans and set an errstr that can be checked or something?
-
PatchLibrarian(CountedPtr<ModelEngineInterface> engine)
: _patch_search_path("."), _engine(engine)
{
@@ -56,8 +56,14 @@ public:
string find_file(const string& filename, const string& additional_path = "");
- void save_patch(CountedPtr<PatchModel> patch_model, const string& filename, bool recursive);
- string load_patch(CountedPtr<PatchModel> pm, bool wait = true, bool existing = false);
+ //void save_patch(CountedPtr<PatchModel> patch_model, const string& filename, bool recursive);
+
+ string load_patch(const string& filename,
+ const string& parent_path,
+ const string& name,
+ size_t poly,
+ MetadataMap initial_data,
+ bool existing = false);
private:
string translate_load_path(const string& path);
@@ -68,10 +74,10 @@ private:
/// Translations of paths from the loading file to actual paths (for deprecated patches)
std::map<string, string> _load_path_translations;
- CountedPtr<NodeModel> parse_node(const CountedPtr<const PatchModel> parent, xmlDocPtr doc, const xmlNodePtr cur);
- ConnectionModel* parse_connection(const CountedPtr<const PatchModel> parent, xmlDocPtr doc, const xmlNodePtr cur);
- PresetModel* parse_preset(const CountedPtr<const PatchModel> parent, xmlDocPtr doc, const xmlNodePtr cur);
- void load_subpatch(const CountedPtr<PatchModel> parent, xmlDocPtr doc, const xmlNodePtr cur);
+ bool load_node(const Path& parent, xmlDocPtr doc, const xmlNodePtr cur);
+ bool load_connection(const Path& parent, xmlDocPtr doc, const xmlNodePtr cur);
+ bool load_preset(const Path& parent, xmlDocPtr doc, const xmlNodePtr cur);
+ bool load_subpatch(const Path& parent, xmlDocPtr doc, const xmlNodePtr cur);
};
diff --git a/src/libs/client/PatchModel.cpp b/src/libs/client/PatchModel.cpp
index a0e94ba4..a8cdf4ef 100644
--- a/src/libs/client/PatchModel.cpp
+++ b/src/libs/client/PatchModel.cpp
@@ -107,14 +107,11 @@ PatchModel::add_node(CountedPtr<NodeModel> nm)
NodeModelMap::iterator existing = m_nodes.find(nm->path().name());
- if (existing != m_nodes.end()) {
- cerr << "Warning: node clash, assimilating old node " << _path << endl;
- nm->assimilate((*existing).second);
- (*existing).second = nm;
- } else {
- m_nodes[nm->path().name()] = nm;
- new_node_sig.emit(nm);
- }
+ // Store should have handled this by merging the two
+ assert(existing == m_nodes.end());
+
+ m_nodes[nm->path().name()] = nm;
+ new_node_sig.emit(nm);
}
@@ -235,10 +232,13 @@ PatchModel::add_connection(CountedPtr<ConnectionModel> cm)
assert(cm);
assert(cm->patch_path() == path());
assert(cm->src_port());
- assert(cm->src_port()->parent()->parent().get() == this
- || cm->src_port()->parent().get() == this);
- assert(cm->dst_port()->parent()->parent().get() == this
- || cm->dst_port()->parent().get() == this);
+ assert(cm->dst_port());
+ assert(cm->src_port()->parent());
+ assert(cm->dst_port()->parent());
+ assert(cm->src_port()->parent().get() == this
+ || cm->src_port()->parent()->parent().get() == this);
+ assert(cm->dst_port()->parent().get() == this
+ || cm->dst_port()->parent()->parent().get() == this);
CountedPtr<ConnectionModel> existing = get_connection(cm->src_port_path(), cm->dst_port_path());
assert(!existing); // Store should have handled this
diff --git a/src/libs/client/PluginModel.h b/src/libs/client/PluginModel.h
index 5174db76..74eee7cb 100644
--- a/src/libs/client/PluginModel.h
+++ b/src/libs/client/PluginModel.h
@@ -18,7 +18,9 @@
#define PLUGINMODEL_H
#include <string>
-using std::string;
+#include <iostream>
+#include "util/Path.h"
+using std::string; using std::cerr; using std::endl;
namespace Ingen {
namespace Client {
@@ -33,40 +35,17 @@ class PluginModel
public:
enum Type { LV2, LADSPA, DSSI, Internal, Patch };
- // FIXME: remove
- PluginModel() {}
-
- PluginModel(const string& type_string, const string& uri)
- : m_uri(uri)
- { set_type(type_string); }
-
- PluginModel(Type type)
- : m_type(type)
- {}
-
- PluginModel(Type type, const string& uri, const string& name)
- : m_type(type),
- m_uri(uri),
+ PluginModel(const string& uri, const string& name)
+ : m_uri(uri),
m_name(name)
- {}
+ {
+ cerr << "FIXME: plugin type" << endl;
+ }
- PluginModel(Type type, const string& lib_name, const string& plug_label, const string& name)
- : m_type(type),
- m_lib_name(lib_name),
- m_plug_label(plug_label),
- m_name(name)
- {}
-
- //PluginModel() {}
-
Type type() const { return m_type; }
void type(Type t) { m_type = t; }
const string& uri() const { return m_uri; }
void uri(const string& s) { m_uri = s; }
- const string& lib_name() const { return m_lib_name; }
- void lib_name(const string& s) { m_lib_name = s; }
- const string& plug_label() const { return m_plug_label; }
- void plug_label(const string& s) { m_plug_label = s; }
const string& name() const { return m_name; }
void name(const string& s) { m_name = s; }
@@ -87,6 +66,8 @@ public:
else if (type_string == "Patch") m_type = Patch;
}
+ string default_node_name() { return Path::nameify(m_name); }
+
private:
// Prevent copies
PluginModel(const PluginModel& copy);
@@ -94,8 +75,6 @@ private:
Type m_type;
string m_uri;
- string m_lib_name;
- string m_plug_label;
string m_name;
};
diff --git a/src/libs/client/SigClientInterface.h b/src/libs/client/SigClientInterface.h
index cab1fd78..1f24ad40 100644
--- a/src/libs/client/SigClientInterface.h
+++ b/src/libs/client/SigClientInterface.h
@@ -42,26 +42,26 @@ public:
// Signal parameters math up directly with ClientInterface calls
- sigc::signal<void, int32_t, bool, string> response_sig;
- sigc::signal<void> bundle_begin_sig;
- sigc::signal<void> bundle_end_sig;
- sigc::signal<void, string> error_sig;
- sigc::signal<void, uint32_t> num_plugins_sig;
- sigc::signal<void, string, string, string> new_plugin_sig;
- sigc::signal<void, string, uint32_t> new_patch_sig;
- sigc::signal<void, string, string, string, bool, uint32_t> new_node_sig;
- sigc::signal<void, string, string, bool> new_port_sig;
- sigc::signal<void, string> patch_enabled_sig;
- sigc::signal<void, string> patch_disabled_sig;
- sigc::signal<void, string> patch_cleared_sig;
- sigc::signal<void, string, string> object_renamed_sig;
- sigc::signal<void, string> object_destroyed_sig;
- sigc::signal<void, string, string> connection_sig;
- sigc::signal<void, string, string> disconnection_sig;
- sigc::signal<void, string, string, Atom> metadata_update_sig;
- sigc::signal<void, string, float> control_change_sig;
- sigc::signal<void, string, uint32_t, uint32_t, string> program_add_sig;
- sigc::signal<void, string, uint32_t, uint32_t> program_remove_sig;
+ sigc::signal<void, int32_t, bool, string> response_sig;
+ sigc::signal<void> bundle_begin_sig;
+ sigc::signal<void> bundle_end_sig;
+ sigc::signal<void, string> error_sig;
+ sigc::signal<void, uint32_t> num_plugins_sig;
+ sigc::signal<void, string, string> new_plugin_sig;
+ sigc::signal<void, string, uint32_t> new_patch_sig;
+ sigc::signal<void, string, string, bool, uint32_t> new_node_sig;
+ sigc::signal<void, string, string, bool> new_port_sig;
+ sigc::signal<void, string> patch_enabled_sig;
+ sigc::signal<void, string> patch_disabled_sig;
+ sigc::signal<void, string> patch_cleared_sig;
+ sigc::signal<void, string, string> object_renamed_sig;
+ sigc::signal<void, string> object_destroyed_sig;
+ sigc::signal<void, string, string> connection_sig;
+ sigc::signal<void, string, string> disconnection_sig;
+ sigc::signal<void, string, string, Atom> metadata_update_sig;
+ sigc::signal<void, string, float> control_change_sig;
+ sigc::signal<void, string, uint32_t, uint32_t, string> program_add_sig;
+ sigc::signal<void, string, uint32_t, uint32_t> program_remove_sig;
protected:
SigClientInterface() {}
diff --git a/src/libs/client/Store.cpp b/src/libs/client/Store.cpp
index f30240fb..f6662422 100644
--- a/src/libs/client/Store.cpp
+++ b/src/libs/client/Store.cpp
@@ -28,9 +28,10 @@ namespace Client {
-Store::Store(CountedPtr<SigClientInterface> emitter)
+Store::Store(CountedPtr<EngineInterface> engine, CountedPtr<SigClientInterface> emitter)
+: _engine(engine)
+, _emitter(emitter)
{
- //emitter.new_plugin_sig.connect(sigc::mem_fun(this, &Store::add_plugin));
emitter->object_destroyed_sig.connect(sigc::mem_fun(this, &Store::destruction_event));
emitter->new_plugin_sig.connect(sigc::mem_fun(this, &Store::new_plugin_event));
emitter->new_patch_sig.connect(sigc::mem_fun(this, &Store::new_patch_event));
@@ -64,6 +65,8 @@ Store::add_plugin_orphan(CountedPtr<NodeModel> node)
map<string, list<CountedPtr<NodeModel> > >::iterator spawn
= m_plugin_orphans.find(node->plugin_uri());
+ _engine->request_plugin(node->plugin_uri());
+
if (spawn != m_plugin_orphans.end()) {
spawn->second.push_back(node);
} else {
@@ -77,11 +80,19 @@ Store::add_plugin_orphan(CountedPtr<NodeModel> node)
void
Store::resolve_plugin_orphans(CountedPtr<PluginModel> plugin)
{
- map<string, list<CountedPtr<NodeModel> > >::iterator spawn
+ map<string, list<CountedPtr<NodeModel> > >::iterator n
= m_plugin_orphans.find(plugin->uri());
- if (spawn != m_plugin_orphans.end()) {
- cerr << "XXXXXXXXXX PLUGIN-ORPHAN PLUGIN FOUND!! XXXXXXXXXXXXXXXXX" << endl;
+ if (n != m_plugin_orphans.end()) {
+
+ list<CountedPtr<NodeModel> > spawn = n->second; // take a copy
+
+ m_plugin_orphans.erase(plugin->uri()); // prevent infinite recursion
+
+ for (list<CountedPtr<NodeModel> >::iterator i = spawn.begin();
+ i != spawn.end(); ++i) {
+ add_object(*i);
+ }
}
}
@@ -89,39 +100,42 @@ Store::resolve_plugin_orphans(CountedPtr<PluginModel> plugin)
void
Store::add_connection_orphan(CountedPtr<ConnectionModel> connection)
{
- cerr << "WARNING: Orphan connection received." << endl;
+ cerr << "WARNING: Orphan connection " << connection->src_port_path()
+ << " -> " << connection->dst_port_path() << " received." << endl;
- cerr << "FIXME (add_connection_orphan)" << endl;
-
- throw; // FIXME: (lazy)
-#if 0
- map<string, list<CountedPtr<ConnectionModel> > >::iterator spawn
- = m_connection_orphans.find(node->connection_uri());
-
- if (spawn != m_connection_orphans.end()) {
- spawn->second.push_back(node);
- } else {
- list<CountedPtr<ConnectionModel> > l;
- l.push_back(node);
- m_connection_orphans[node->connection_uri()] = l;
- }
-#endif
+ m_connection_orphans.push_back(connection);
}
void
Store::resolve_connection_orphans(CountedPtr<PortModel> port)
{
- cerr << "FIXME (add_connection_orphan)" << endl;
- throw; // FIXME: (lazy)
-#if 0
- map<string, list<CountedPtr<ConnectionModel> > >::iterator spawn
- = m_connection_orphans.find(connection->uri());
-
- if (spawn != m_connection_orphans.end()) {
- cerr << "XXXXXXXXXX PLUGIN-ORPHAN PLUGIN FOUND!! XXXXXXXXXXXXXXXXX" << endl;
+ assert(port->parent());
+
+ for (list<CountedPtr<ConnectionModel> >::iterator c = m_connection_orphans.begin();
+ c != m_connection_orphans.end(); ) {
+
+ if ((*c)->src_port_path() == port->path())
+ (*c)->set_src_port(port);
+
+ if ((*c)->dst_port_path() == port->path())
+ (*c)->set_dst_port(port);
+
+ list<CountedPtr<ConnectionModel> >::iterator next = c;
+ ++next;
+
+ if ((*c)->src_port() && (*c)->dst_port()) {
+ CountedPtr<PatchModel> patch = PtrCast<PatchModel>(this->object((*c)->patch_path()));
+ if (patch) {
+ cerr << "Resolved orphan connection " << (*c)->src_port_path() <<
+ (*c)->dst_port_path() << endl;
+ patch->add_connection(*c);
+ m_connection_orphans.erase(c);
+ }
+ }
+
+ c = next;
}
-#endif
}
@@ -133,6 +147,8 @@ Store::add_orphan(CountedPtr<ObjectModel> child)
map<Path, list<CountedPtr<ObjectModel> > >::iterator children
= m_orphans.find(child->path().parent());
+ _engine->request_object(child->path().parent());
+
if (children != m_orphans.end()) {
children->second.push_back(child);
} else {
@@ -144,35 +160,66 @@ Store::add_orphan(CountedPtr<ObjectModel> child)
void
-Store::resolve_orphans(CountedPtr<ObjectModel> parent)
+Store::add_metadata_orphan(const Path& subject_path, const string& predicate, const Atom& value)
{
- map<Path, list<CountedPtr<ObjectModel> > >::iterator children
- = m_orphans.find(parent->path());
+ map<Path, list<std::pair<string, Atom> > >::iterator orphans
+ = m_metadata_orphans.find(subject_path);
- if (children != m_orphans.end()) {
- cerr << "XXXXXXXXXXXXX ORPHAN PARENT FOUND!! XXXXXXXXXXXXXXXXX" << endl;
+ _engine->request_object(subject_path);
+
+ if (orphans != m_metadata_orphans.end()) {
+ orphans->second.push_back(std::pair<string, Atom>(predicate, value));
+ } else {
+ list<std::pair<string, Atom> > l;
+ l.push_back(std::pair<string, Atom>(predicate, value));
+ m_metadata_orphans[subject_path] = l;
}
}
void
-Store::add_object(CountedPtr<ObjectModel> object)
+Store::resolve_metadata_orphans(CountedPtr<ObjectModel> subject)
{
- assert(object->path() != "");
- assert(m_objects.find(object->path()) == m_objects.end());
-
- if (object->path() != "/") {
- CountedPtr<ObjectModel> parent = this->object(object->path().parent());
- if (parent) {
- assert(object->path().is_child_of(parent->path()));
- object->set_parent(parent);
- parent->add_child(object);
- assert(object->parent() == parent);
- } else {
- add_orphan(object);
+ map<Path, list<std::pair<string, Atom> > >::iterator v
+ = m_metadata_orphans.find(subject->path());
+
+ if (v != m_metadata_orphans.end()) {
+
+ list<std::pair<string, Atom> > values = v->second; // take a copy
+
+ m_metadata_orphans.erase(subject->path());
+
+ for (list<std::pair<string, Atom> >::iterator i = values.begin();
+ i != values.end(); ++i) {
+ subject->set_metadata(i->first, i->second);
+ }
+ }
+}
+
+
+void
+Store::resolve_orphans(CountedPtr<ObjectModel> parent)
+{
+ map<Path, list<CountedPtr<ObjectModel> > >::iterator c
+ = m_orphans.find(parent->path());
+
+ if (c != m_orphans.end()) {
+
+ list<CountedPtr<ObjectModel> > children = c->second; // take a copy
+
+ m_orphans.erase(parent->path()); // prevent infinite recursion
+
+ for (list<CountedPtr<ObjectModel> >::iterator i = children.begin();
+ i != children.end(); ++i) {
+ add_object(*i);
}
}
+}
+
+void
+Store::add_object(CountedPtr<ObjectModel> object)
+{
// If we already have "this" object, merge the existing one into the new
// one (with precedence to the new values).
ObjectMap::iterator existing = m_objects.find(object->path());
@@ -180,14 +227,31 @@ Store::add_object(CountedPtr<ObjectModel> object)
cerr << "[Store] Warning: Assimilating " << object->path() << endl;
object->assimilate(existing->second);
existing->second = object;
- }
-
- m_objects[object->path()] = object;
+ } else {
- // FIXME: emit this when we already had one?
- new_object_sig.emit(object);
+ if (object->path() != "/") {
+ CountedPtr<ObjectModel> parent = this->object(object->path().parent());
+ if (parent) {
+ assert(object->path().is_child_of(parent->path()));
+ object->set_parent(parent);
+ parent->add_child(object);
+ assert(parent && (object->parent() == parent));
+
+ m_objects[object->path()] = object;
+ new_object_sig.emit(object);
+
+ resolve_metadata_orphans(parent);
+ resolve_orphans(parent);
+
+ } else {
+ add_orphan(object);
+ }
+ } else {
+ m_objects[object->path()] = object;
+ new_object_sig.emit(object);
+ }
- resolve_orphans(object);
+ }
//cout << "[Store] Added " << object->path() << endl;
}
@@ -208,6 +272,8 @@ Store::remove_object(const Path& path)
result->destroyed_sig.emit();
if (result->path() != "/") {
+ assert(result->parent());
+
CountedPtr<ObjectModel> parent = this->object(result->path().parent());
if (parent) {
parent->remove_child(result);
@@ -248,7 +314,7 @@ Store::object(const Path& path)
void
Store::add_plugin(CountedPtr<PluginModel> pm)
{
- // FIXME: dupes?
+ // FIXME: dupes? assimilate?
m_plugins[pm->uri()] = pm;
}
@@ -270,10 +336,9 @@ Store::destruction_event(const Path& path)
}
void
-Store::new_plugin_event(const string& type, const string& uri, const string& name)
+Store::new_plugin_event(const string& uri, const string& name)
{
- CountedPtr<PluginModel> p(new PluginModel(type, uri));
- p->name(name);
+ CountedPtr<PluginModel> p(new PluginModel(uri, name));
add_plugin(p);
resolve_plugin_orphans(p);
}
@@ -288,7 +353,7 @@ Store::new_patch_event(const Path& path, uint32_t poly)
void
-Store::new_node_event(const string& plugin_type, const string& plugin_uri, const Path& node_path, bool is_polyphonic, uint32_t num_ports)
+Store::new_node_event(const string& plugin_uri, const Path& node_path, bool is_polyphonic, uint32_t num_ports)
{
// FIXME: num_ports unused
@@ -318,6 +383,8 @@ Store::new_port_event(const Path& path, const string& type, bool is_output)
CountedPtr<PortModel> p(new PortModel(path, ptype, pdir));
add_object(p);
+ if (p->parent())
+ resolve_connection_orphans(p);
}
@@ -356,10 +423,13 @@ void
Store::metadata_update_event(const Path& subject_path, const string& predicate, const Atom& value)
{
CountedPtr<ObjectModel> subject = object(subject_path);
- if (subject)
+
+ if (subject) {
subject->set_metadata(predicate, value);
- else
- cerr << "ERROR: metadata for nonexistant object." << endl;
+ } else {
+ add_metadata_orphan(subject_path, predicate, value);
+ cerr << "WARNING: metadata for unknown object." << endl;
+ }
}
@@ -380,30 +450,24 @@ Store::connection_event(const Path& src_port_path, const Path& dst_port_path)
CountedPtr<PortModel> src_port = PtrCast<PortModel>(object(src_port_path));
CountedPtr<PortModel> dst_port = PtrCast<PortModel>(object(dst_port_path));
- assert(src_port);
- assert(dst_port);
+ CountedPtr<ConnectionModel> dangling_cm(new ConnectionModel(src_port_path, dst_port_path));
- src_port->connected_to(dst_port);
- dst_port->connected_to(src_port);
+ if (src_port && src_port->parent() && dst_port && dst_port->parent()) {
+
+ CountedPtr<PatchModel> patch = PtrCast<PatchModel>(this->object(dangling_cm->patch_path()));
+ assert(patch);
- CountedPtr<ConnectionModel> cm(new ConnectionModel(src_port, dst_port));
+ CountedPtr<ConnectionModel> cm(new ConnectionModel(src_port, dst_port));
+
+ src_port->connected_to(dst_port);
+ dst_port->connected_to(src_port);
- CountedPtr<PatchModel> patch = PtrCast<PatchModel>(this->object(cm->patch_path()));
+ patch->add_connection(cm);
- CountedPtr<ObjectModel> src_obj = this->object(src_port_path);
- CountedPtr<ObjectModel> dst_obj = this->object(dst_port_path);
-
- if (!src_obj || !dst_obj || !patch) {
- add_connection_orphan(cm);
} else {
- CountedPtr<PortModel> src_port = PtrCast<PortModel>(src_obj);
- CountedPtr<PortModel> dst_port = PtrCast<PortModel>(dst_obj);
- assert(src_port && dst_port);
- cm->set_src_port(src_port);
- cm->set_dst_port(dst_port);
+ add_connection_orphan(dangling_cm);
- patch->add_connection(cm);
}
}
diff --git a/src/libs/client/Store.h b/src/libs/client/Store.h
index ff617d37..a2083ba2 100644
--- a/src/libs/client/Store.h
+++ b/src/libs/client/Store.h
@@ -25,7 +25,9 @@
#include <sigc++/sigc++.h>
#include "util/Path.h"
#include "util/Atom.h"
+#include "interface/EngineInterface.h"
using std::string; using std::map; using std::list;
+using Ingen::Shared::EngineInterface;
namespace Ingen {
namespace Client {
@@ -45,7 +47,7 @@ class ConnectionModel;
*/
class Store : public sigc::trackable { // FIXME: is trackable necessary?
public:
- Store(CountedPtr<SigClientInterface> emitter);
+ Store(CountedPtr<EngineInterface> engine, CountedPtr<SigClientInterface> emitter);
CountedPtr<PluginModel> plugin(const string& uri);
CountedPtr<ObjectModel> object(const Path& path);
@@ -74,12 +76,15 @@ private:
void add_plugin_orphan(CountedPtr<NodeModel> orphan);
void resolve_plugin_orphans(CountedPtr<PluginModel> plugin);
+
+ void add_metadata_orphan(const Path& subject, const string& predicate, const Atom& value);
+ void resolve_metadata_orphans(CountedPtr<ObjectModel> subject);
// Slots for SigClientInterface signals
void destruction_event(const Path& path);
- void new_plugin_event(const string& type, const string& uri, const string& name);
+ void new_plugin_event(const string& uri, const string& name);
void new_patch_event(const Path& path, uint32_t poly);
- void new_node_event(const string& plugin_type, const string& plugin_uri, const Path& node_path, bool is_polyphonic, uint32_t num_ports);
+ void new_node_event(const string& plugin_uri, const Path& node_path, bool is_polyphonic, uint32_t num_ports);
void new_port_event(const Path& path, const string& data_type, bool is_output);
void patch_enabled_event(const Path& path);
void patch_disabled_event(const Path& path);
@@ -89,6 +94,9 @@ private:
void connection_event(const Path& src_port_path, const Path& dst_port_path);
void disconnection_event(const Path& src_port_path, const Path& dst_port_path);
+ CountedPtr<EngineInterface> _engine;
+ CountedPtr<SigClientInterface> _emitter;
+
typedef map<Path, CountedPtr<ObjectModel> > ObjectMap;
ObjectMap m_objects; ///< Keyed by Ingen path
@@ -101,6 +109,12 @@ private:
/** Same idea, except with plugins instead of parents.
* It's unfortunate everything doesn't just have a URI and this was the same.. ahem.. */
map<string, list<CountedPtr<NodeModel> > > m_plugin_orphans;
+
+ /** Not orphans OF metadata like the above, but orphans which are metadata */
+ map<Path, list<std::pair<string, Atom> > > m_metadata_orphans;
+
+ /** Ditto */
+ list<CountedPtr<ConnectionModel> > m_connection_orphans;
};
diff --git a/src/libs/client/ThreadedSigClientInterface.h b/src/libs/client/ThreadedSigClientInterface.h
index 981b038d..f29d3cc4 100644
--- a/src/libs/client/ThreadedSigClientInterface.h
+++ b/src/libs/client/ThreadedSigClientInterface.h
@@ -82,14 +82,14 @@ public:
void error(string msg)
{ push_sig(sigc::bind(error_slot, msg)); }
- void new_plugin(string type, string uri, string name)
- { push_sig(sigc::bind(new_plugin_slot, type, uri, name)); }
+ void new_plugin(string uri, string name)
+ { push_sig(sigc::bind(new_plugin_slot, uri, name)); }
void new_patch(string path, uint32_t poly)
{ push_sig(sigc::bind(new_patch_slot, path, poly)); }
- void new_node(string plugin_type, string plugin_uri, string node_path, bool is_polyphonic, uint32_t num_ports)
- { push_sig(sigc::bind(new_node_slot, plugin_type, plugin_uri, node_path, is_polyphonic, num_ports)); }
+ void new_node(string plugin_uri, string node_path, bool is_polyphonic, uint32_t num_ports)
+ { push_sig(sigc::bind(new_node_slot, plugin_uri, node_path, is_polyphonic, num_ports)); }
void new_port(string path, string data_type, bool is_output)
{ push_sig(sigc::bind(new_port_slot, path, data_type, is_output)); }
@@ -141,9 +141,9 @@ private:
sigc::slot<void, uint32_t> num_plugins_slot;
sigc::slot<void, int32_t, bool, string> response_slot;
sigc::slot<void, string> error_slot;
- sigc::slot<void, string, string, string> new_plugin_slot;
+ sigc::slot<void, string, string> new_plugin_slot;
sigc::slot<void, string, uint32_t> new_patch_slot;
- sigc::slot<void, string, string, string, bool, int> new_node_slot;
+ sigc::slot<void, string, string, bool, int> new_node_slot;
sigc::slot<void, string, string, bool> new_port_slot;
sigc::slot<void, string, string> connection_slot;
sigc::slot<void, string> patch_enabled_slot;
diff --git a/src/libs/engine/ClientBroadcaster.cpp b/src/libs/engine/ClientBroadcaster.cpp
index 7a21c38b..a214131a 100644
--- a/src/libs/engine/ClientBroadcaster.cpp
+++ b/src/libs/engine/ClientBroadcaster.cpp
@@ -175,7 +175,7 @@ ClientBroadcaster::send_plugins_to(CountedPtr<ClientInterface> client, const lis
for (list<Plugin*>::const_iterator i = plugin_list.begin(); i != plugin_list.end(); ++i) {
const Plugin* const plugin = *i;
- client->new_plugin(plugin->type_string(), plugin->uri(), plugin->name());
+ client->new_plugin(plugin->uri(), plugin->name());
}
client->transfer_end();
@@ -191,10 +191,10 @@ ClientBroadcaster::send_plugins(const list<Plugin*>& plugin_list)
void
-ClientBroadcaster::send_node(const Node* node)
+ClientBroadcaster::send_node(const Node* node, bool recursive)
{
for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i)
- ObjectSender::send_node((*i).second.get(), node);
+ ObjectSender::send_node((*i).second.get(), node, recursive);
}
@@ -300,10 +300,10 @@ ClientBroadcaster::send_program_remove(const string& node_path, int bank, int pr
* Sends all objects underneath Patch - contained Nodes, etc.
*/
void
-ClientBroadcaster::send_patch(const Patch* const p)
+ClientBroadcaster::send_patch(const Patch* const p, bool recursive)
{
for (ClientList::const_iterator i = _clients.begin(); i != _clients.end(); ++i)
- ObjectSender::send_patch((*i).second.get(), p);
+ ObjectSender::send_patch((*i).second.get(), p, recursive);
}
diff --git a/src/libs/engine/ClientBroadcaster.h b/src/libs/engine/ClientBroadcaster.h
index 47ad75b4..97f2abf2 100644
--- a/src/libs/engine/ClientBroadcaster.h
+++ b/src/libs/engine/ClientBroadcaster.h
@@ -41,6 +41,7 @@ namespace Shared { class ClientKey; }
using Shared::ClientKey;
using Shared::ClientInterface;
+
/** Broadcaster for all clients.
*
* This sends messages to all client simultaneously through the opaque
@@ -71,8 +72,8 @@ public:
//void send_node_creation_messages(const Node* const node);
void send_plugins(const list<Plugin*>& plugin_list);
- void send_patch(const Patch* const p);
- void send_node(const Node* const node);
+ void send_patch(const Patch* const p, bool recursive);
+ void send_node(const Node* const node, bool recursive);
void send_port(const Port* port);
void send_destroyed(const string& path);
void send_patch_cleared(const string& patch_path);
diff --git a/src/libs/engine/Engine.h b/src/libs/engine/Engine.h
index 1f84d867..a8d110ca 100644
--- a/src/libs/engine/Engine.h
+++ b/src/libs/engine/Engine.h
@@ -72,7 +72,7 @@ public:
MidiDriver* midi_driver() const { return m_midi_driver; }
Maid* maid() const { return m_maid; }
PostProcessor* post_processor() const { return m_post_processor; }
- ClientBroadcaster* broadcaster() const { return m_broadcaster; }
+ ClientBroadcaster* broadcaster() const { return m_broadcaster; }
ObjectStore* object_store() const { return m_object_store; }
NodeFactory* node_factory() const { return m_node_factory; }
LashDriver* lash_driver() const { return m_lash_driver; }
diff --git a/src/libs/engine/Makefile.am b/src/libs/engine/Makefile.am
index 99679932..3747515b 100644
--- a/src/libs/engine/Makefile.am
+++ b/src/libs/engine/Makefile.am
@@ -72,9 +72,6 @@ libingen_la_SOURCES = \
Plugin.cpp \
Array.h \
List.h \
- Slave.h \
- Thread.h \
- Thread.cpp \
PostProcessor.h \
PostProcessor.cpp \
Connection.h \
@@ -133,6 +130,10 @@ libingen_la_SOURCES = \
events/SetMetadataEvent.cpp \
events/RequestMetadataEvent.h \
events/RequestMetadataEvent.cpp \
+ events/RequestPluginEvent.h \
+ events/RequestPluginEvent.cpp \
+ events/RequestObjectEvent.h \
+ events/RequestObjectEvent.cpp \
events/RequestPortValueEvent.h \
events/RequestPortValueEvent.cpp \
events/RequestAllObjectsEvent.h \
diff --git a/src/libs/engine/NodeFactory.cpp b/src/libs/engine/NodeFactory.cpp
index ca762678..1cbabaeb 100644
--- a/src/libs/engine/NodeFactory.cpp
+++ b/src/libs/engine/NodeFactory.cpp
@@ -95,7 +95,6 @@ NodeFactory::~NodeFactory()
const Plugin*
NodeFactory::plugin(const string& uri)
{
- // FIXME: this needs.. well, fixing
for (list<Plugin*>::iterator i = _plugins.begin(); i != _plugins.end(); ++i)
if ((*i)->uri() == uri)
return (*i);
@@ -104,6 +103,24 @@ NodeFactory::plugin(const string& uri)
}
+/** DEPRECATED: Find a plugin by type, lib, label.
+ *
+ * Do not use.
+ */
+const Plugin*
+NodeFactory::plugin(const string& type, const string& lib, const string& label)
+{
+ if (type == "" || lib == "" || label == "")
+ return NULL;
+
+ for (list<Plugin*>::iterator i = _plugins.begin(); i != _plugins.end(); ++i)
+ if ((*i)->type_string() == type && (*i)->lib_name() == lib && (*i)->plug_label() == label)
+ return (*i);
+
+ return NULL;
+}
+
+
void
NodeFactory::load_plugins()
{
diff --git a/src/libs/engine/NodeFactory.h b/src/libs/engine/NodeFactory.h
index 1fd6c2d4..573c6808 100644
--- a/src/libs/engine/NodeFactory.h
+++ b/src/libs/engine/NodeFactory.h
@@ -57,6 +57,7 @@ public:
const list<Plugin*>& plugins() { return _plugins; }
const Plugin* plugin(const string& uri);
+ const Plugin* plugin(const string& type, const string& lib, const string& label); // DEPRECATED
private:
#ifdef HAVE_LADSPA
diff --git a/src/libs/engine/OSCClientSender.cpp b/src/libs/engine/OSCClientSender.cpp
index 538630c0..17b730fb 100644
--- a/src/libs/engine/OSCClientSender.cpp
+++ b/src/libs/engine/OSCClientSender.cpp
@@ -217,13 +217,14 @@ OSCClientSender::plugins()
* this one (/om/new_node), followed by a series of /om/new_port commands,
* followed by /om/new_node_end. </p> \n \n
*/
-void OSCClientSender::new_node(string plugin_type,
- string plugin_uri,
- string node_path,
- bool is_polyphonic,
- uint32_t num_ports)
+void OSCClientSender::new_node(string plugin_uri,
+ string node_path,
+ bool is_polyphonic,
+ uint32_t num_ports)
{
- lo_send(_address, "/om/new_node", "sssii", plugin_type.c_str(), plugin_uri.c_str(),
+ //cerr << "Sending node " << node_path << endl;
+
+ lo_send(_address, "/om/new_node", "ssii", plugin_uri.c_str(),
node_path.c_str(), is_polyphonic ? 1 : 0, num_ports);
#if 0
/*
@@ -453,10 +454,9 @@ OSCClientSender::control_change(string port_path, float value)
* \arg \b name (string) - Descriptive human-readable name of plugin (ie "ADSR Envelope")
*/
void
-OSCClientSender::new_plugin(string type, string uri, string name)
+OSCClientSender::new_plugin(string uri, string name)
{
lo_message m = lo_message_new();
- lo_message_add_string(m, type.c_str());
lo_message_add_string(m, uri.c_str());
lo_message_add_string(m, name.c_str());
diff --git a/src/libs/engine/OSCClientSender.h b/src/libs/engine/OSCClientSender.h
index 260dba63..a2ee9e26 100644
--- a/src/libs/engine/OSCClientSender.h
+++ b/src/libs/engine/OSCClientSender.h
@@ -72,14 +72,12 @@ public:
void error(string msg);
- virtual void new_plugin(string type,
- string uri,
+ virtual void new_plugin(string uri,
string name);
virtual void new_patch(string path, uint32_t poly);
- virtual void new_node(string plugin_type,
- string plugin_uri,
+ virtual void new_node(string plugin_uri,
string node_path,
bool is_polyphonic,
uint32_t num_ports);
diff --git a/src/libs/engine/OSCEngineReceiver.cpp b/src/libs/engine/OSCEngineReceiver.cpp
index 92ab08f0..50876850 100644
--- a/src/libs/engine/OSCEngineReceiver.cpp
+++ b/src/libs/engine/OSCEngineReceiver.cpp
@@ -88,7 +88,7 @@ OSCEngineReceiver::OSCEngineReceiver(CountedPtr<Engine> engine, size_t queue_siz
lo_server_add_method(_server, "/om/synth/disable_patch", "is", disable_patch_cb, this);
lo_server_add_method(_server, "/om/synth/clear_patch", "is", clear_patch_cb, this);
lo_server_add_method(_server, "/om/synth/create_port", "issi", create_port_cb, this);
- lo_server_add_method(_server, "/om/synth/create_node", "isssi", create_node_cb, this);
+ lo_server_add_method(_server, "/om/synth/create_node", "issssi", create_node_cb, this);
lo_server_add_method(_server, "/om/synth/create_node", "issi", create_node_by_uri_cb, this);
lo_server_add_method(_server, "/om/synth/destroy", "is", destroy_cb, this);
lo_server_add_method(_server, "/om/synth/rename", "iss", rename_cb, this);
@@ -110,9 +110,12 @@ OSCEngineReceiver::OSCEngineReceiver(CountedPtr<Engine> engine, size_t queue_siz
lo_server_add_method(_server, "/om/metadata/set", NULL, metadata_set_cb, this);
// Queries
+ lo_server_add_method(_server, "/om/request/plugin", "is", request_plugin_cb, this);
+ lo_server_add_method(_server, "/om/request/object", "is", request_object_cb, this);
+ lo_server_add_method(_server, "/om/request/port_value", "is", request_port_value_cb, this);
lo_server_add_method(_server, "/om/request/plugins", "i", request_plugins_cb, this);
lo_server_add_method(_server, "/om/request/all_objects", "i", request_all_objects_cb, this);
- lo_server_add_method(_server, "/om/request/port_value", "is", request_port_value_cb, this);
+
// DSSI support
#ifdef HAVE_DSSI
@@ -799,29 +802,37 @@ OSCEngineReceiver::m_metadata_get_cb(const char* path, const char* types, lo_arg
/** \page engine_osc_namespace
- * <p> \b /om/responder/plugins - Requests the engine send a list of all known plugins.
+ * <p> \b /om/responder/plugin - Requests the engine send the value of a port.
* \arg \b response-id (integer)
+ * \arg \b port-path (string) - Full path of port to send the value of </p> \n \n
*
* \li Reply will be sent to client registered with the source address of this message.</p> \n \n
*/
int
-OSCEngineReceiver::m_request_plugins_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+OSCEngineReceiver::m_request_plugin_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
{
- request_plugins();
+ const char* uri = &argv[1]->s;
+
+ request_plugin(uri);
+
return 0;
}
/** \page engine_osc_namespace
- * <p> \b /om/responder/all_objects - Requests the engine send information about \em all objects (patches, nodes, etc)
+ * <p> \b /om/responder/object - Requests the engine send the value of a port.
* \arg \b response-id (integer)
- *
+ * \arg \b port-path (string) - Full path of port to send the value of </p> \n \n
+ *
* \li Reply will be sent to client registered with the source address of this message.</p> \n \n
*/
int
-OSCEngineReceiver::m_request_all_objects_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+OSCEngineReceiver::m_request_object_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
{
- request_all_objects();
+ const char* object_path = &argv[1]->s;
+
+ request_object(object_path);
+
return 0;
}
@@ -843,6 +854,34 @@ OSCEngineReceiver::m_request_port_value_cb(const char* path, const char* types,
}
+/** \page engine_osc_namespace
+ * <p> \b /om/responder/plugins - Requests the engine send a list of all known plugins.
+ * \arg \b response-id (integer)
+ *
+ * \li Reply will be sent to client registered with the source address of this message.</p> \n \n
+ */
+int
+OSCEngineReceiver::m_request_plugins_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ request_plugins();
+ return 0;
+}
+
+
+/** \page engine_osc_namespace
+ * <p> \b /om/responder/all_objects - Requests the engine send information about \em all objects (patches, nodes, etc)
+ * \arg \b response-id (integer)
+ *
+ * \li Reply will be sent to client registered with the source address of this message.</p> \n \n
+ */
+int
+OSCEngineReceiver::m_request_all_objects_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
+{
+ request_all_objects();
+ return 0;
+}
+
+
#ifdef HAVE_DSSI
int
OSCEngineReceiver::m_dssi_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg)
diff --git a/src/libs/engine/OSCEngineReceiver.h b/src/libs/engine/OSCEngineReceiver.h
index 793286d4..c31587e6 100644
--- a/src/libs/engine/OSCEngineReceiver.h
+++ b/src/libs/engine/OSCEngineReceiver.h
@@ -107,9 +107,12 @@ private:
LO_HANDLER(midi_learn);
LO_HANDLER(metadata_get);
LO_HANDLER(metadata_set);
+ LO_HANDLER(request_plugin);
+ LO_HANDLER(request_object);
+ LO_HANDLER(request_port_value);
LO_HANDLER(request_plugins);
LO_HANDLER(request_all_objects);
- LO_HANDLER(request_port_value);
+
#ifdef HAVE_DSSI
LO_HANDLER(dssi);
#endif
diff --git a/src/libs/engine/ObjectSender.cpp b/src/libs/engine/ObjectSender.cpp
index 1e6b93c5..f7b4790f 100644
--- a/src/libs/engine/ObjectSender.cpp
+++ b/src/libs/engine/ObjectSender.cpp
@@ -28,41 +28,35 @@ namespace Ingen {
void
-ObjectSender::send_patch(ClientInterface* client, const Patch* patch)
+ObjectSender::send_patch(ClientInterface* client, const Patch* patch, bool recursive)
{
client->new_patch(patch->path(), patch->internal_poly());
- for (List<Node*>::const_iterator j = patch->nodes().begin();
- j != patch->nodes().end(); ++j) {
- const Node* const node = (*j);
+ if (recursive) {
- send_node(client, node);
- }
-
- // Send port information
- for (size_t i=0; i < patch->num_ports(); ++i) {
- Port* const port = patch->ports().at(i);
- send_port(client, port);
-/*
- // Send metadata
- const GraphObject::MetadataMap& data = port->metadata();
- for (GraphObject::MetadataMap::const_iterator i = data.begin(); i != data.end(); ++i)
- client->metadata_update(port->path(), (*i).first, (*i).second);
-
- // Control port, send value
- if (port->type() == DataType::FLOAT && port->buffer_size() == 1)
- client->control_change(port->path(),
- dynamic_cast<TypedPort<Sample>*>(port)->buffer(0)->value_at(0));
-*/
- }
+ // Send nodes
+ for (List<Node*>::const_iterator j = patch->nodes().begin();
+ j != patch->nodes().end(); ++j) {
+
+ const Node* const node = (*j);
+ send_node(client, node, true);
+ }
+ // Send ports
+ for (size_t i=0; i < patch->num_ports(); ++i) {
+
+ Port* const port = patch->ports().at(i);
+ send_port(client, port);
+
+ }
+
+ // Send connections
+ for (List<Connection*>::const_iterator j = patch->connections().begin();
+ j != patch->connections().end(); ++j)
+ client->connection((*j)->src_port()->path(), (*j)->dst_port()->path());
+
+ }
- // Send connections
- for (List<Connection*>::const_iterator j = patch->connections().begin();
- j != patch->connections().end(); ++j)
- client->connection((*j)->src_port()->path(), (*j)->dst_port()->path());
-
-
// Send metadata
const GraphObject::MetadataMap& data = patch->metadata();
for (GraphObject::MetadataMap::const_iterator j = data.begin(); j != data.end(); ++j)
@@ -75,7 +69,7 @@ ObjectSender::send_patch(ClientInterface* client, const Patch* patch)
/** Sends a node or a patch */
void
-ObjectSender::send_node(ClientInterface* client, const Node* node)
+ObjectSender::send_node(ClientInterface* client, const Node* node, bool recursive)
{
const Plugin* const plugin = node->plugin();
@@ -87,7 +81,7 @@ ObjectSender::send_node(ClientInterface* client, const Node* node)
assert(node->path().length() > 0);
if (plugin->type() == Plugin::Patch) {
- send_patch(client, (Patch*)node);
+ send_patch(client, (Patch*)node, recursive);
return;
}
@@ -95,32 +89,30 @@ ObjectSender::send_node(ClientInterface* client, const Node* node)
cerr << "Node " << node->path() << " plugin has no URI! Not sending." << endl;
return;
}
-
- client->bundle_begin();
-
// FIXME: bundleify
+ //client->bundle_begin();
const Array<Port*>& ports = node->ports();
- client->new_node(node->plugin()->type_string(), node->plugin()->uri(),
- node->path(), polyphonic, ports.size());
+ client->new_node(node->plugin()->uri(), node->path(), polyphonic, ports.size());
- // Send ports
- for (size_t j=0; j < ports.size(); ++j) {
- Port* const port = ports.at(j);
- assert(port);
-
- send_port(client, port);
- //client->new_port(port->path(), port->type().uri(), port->is_output());
+ if (recursive) {
+ // Send ports
+ for (size_t j=0; j < ports.size(); ++j) {
+ Port* const port = ports.at(j);
+ assert(port);
+
+ send_port(client, port);
+ }
}
- client->bundle_end();
-
// Send metadata
const GraphObject::MetadataMap& data = node->metadata();
for (GraphObject::MetadataMap::const_iterator j = data.begin(); j != data.end(); ++j)
client->metadata_update(node->path(), (*j).first, (*j).second);
+
+ //client->bundle_end();
}
@@ -128,6 +120,8 @@ void
ObjectSender::send_port(ClientInterface* client, const Port* port)
{
assert(port);
+
+ //cerr << "Sending port " << port->path();
// FIXME: temporary compatibility hack
string type = port->type().uri();
@@ -137,7 +131,9 @@ ObjectSender::send_port(ClientInterface* client, const Port* port)
else
type = "AUDIO";
}
-
+
+ //cerr << ", type = " << type << endl;
+
client->new_port(port->path(), type, port->is_output());
// Send control value
@@ -171,7 +167,7 @@ ObjectSender::send_plugins(ClientInterface* client, const list<Plugin*>& plugs)
*/
for (list<Plugin*>::const_iterator j = plugs.begin(); j != plugs.end(); ++j) {
const Plugin* const p = *j;
- client->new_plugin(p->type_string(), p->uri(), p->name());
+ client->new_plugin(p->uri(), p->name());
}
/*
plugin = (*j);
diff --git a/src/libs/engine/ObjectSender.h b/src/libs/engine/ObjectSender.h
index 38b1577f..ddd72dd7 100644
--- a/src/libs/engine/ObjectSender.h
+++ b/src/libs/engine/ObjectSender.h
@@ -45,8 +45,8 @@ public:
// FIXME: Make all object parameters const
- static void send_patch(ClientInterface* client, const Patch* patch);
- static void send_node(ClientInterface* client, const Node* node);
+ static void send_patch(ClientInterface* client, const Patch* patch, bool recursive);
+ static void send_node(ClientInterface* client, const Node* node, bool recursive);
static void send_port(ClientInterface* client, const Port* port);
static void send_plugins(ClientInterface* client, const std::list<Plugin*>& plugs);
};
diff --git a/src/libs/engine/Plugin.h b/src/libs/engine/Plugin.h
index bdb5a748..a841d6ee 100644
--- a/src/libs/engine/Plugin.h
+++ b/src/libs/engine/Plugin.h
@@ -53,6 +53,11 @@ public:
Plugin(Type type, const string& uri)
: _type(type)
, _uri(uri)
+ , _id(0)
+ , _library(NULL)
+#ifdef HAVE_SLV2
+ , _slv2_plugin(NULL)
+#endif
{}
// FIXME: remove
@@ -71,10 +76,12 @@ public:
if (copy->_type != Internal)
exit(EXIT_FAILURE);
_type = copy->_type;
- _lib_path = copy->_lib_path;
_uri = copy->_uri;
+ _lib_path = copy->_lib_path;
+ _lib_name = copy->_lib_name;
_plug_label = copy->_plug_label;
_name = copy->_name;
+ _id = _id;
_library = copy->_library;
}
diff --git a/src/libs/engine/PostProcessor.h b/src/libs/engine/PostProcessor.h
index e29175ee..212e3797 100644
--- a/src/libs/engine/PostProcessor.h
+++ b/src/libs/engine/PostProcessor.h
@@ -20,7 +20,7 @@
#include <pthread.h>
#include "types.h"
#include "util/Queue.h"
-#include "Slave.h"
+#include "util/Slave.h"
class Maid;
diff --git a/src/libs/engine/QueuedEngineInterface.cpp b/src/libs/engine/QueuedEngineInterface.cpp
index f8fc4827..53c5668c 100644
--- a/src/libs/engine/QueuedEngineInterface.cpp
+++ b/src/libs/engine/QueuedEngineInterface.cpp
@@ -135,7 +135,7 @@ void QueuedEngineInterface::create_port(const string& path,
const string& data_type,
bool direction)
{
- push_queued(new AddPortEvent(*_engine.get(), _responder, now(), path, data_type, direction));
+ push_queued(new AddPortEvent(*_engine.get(), _responder, now(), path, data_type, direction, this));
}
@@ -144,7 +144,8 @@ QueuedEngineInterface::create_node(const string& path,
const string& plugin_uri,
bool polyphonic)
{
- push_queued(new AddNodeEvent(*_engine.get(), _responder, now(), path, plugin_uri, polyphonic));
+ push_queued(new AddNodeEvent(*_engine.get(), _responder, now(),
+ path, plugin_uri, polyphonic));
}
@@ -155,18 +156,8 @@ QueuedEngineInterface::create_node(const string& path,
const string& plugin_label,
bool polyphonic)
{
- cerr << "FIXME: deprecated create_node\n";
- throw;
-#if 0
- // FIXME: ew
-
- Plugin* plugin = new Plugin();
- plugin->set_type(plugin_type);
- plugin->lib_name(plugin_lib);
- plugin->plug_label(plugin_label);
-
- push_queued(new AddNodeEvent(*_engine.get(), _responder, now(), path, plugin, polyphonic));
-#endif
+ push_queued(new AddNodeEvent(*_engine.get(), _responder, now(),
+ path, plugin_type, plugin_lib, plugin_label, polyphonic));
}
void
@@ -295,6 +286,20 @@ QueuedEngineInterface::ping()
void
+QueuedEngineInterface::request_plugin(const string& uri)
+{
+ push_queued(new RequestPluginEvent(*_engine.get(), _responder, now(), uri));
+}
+
+
+void
+QueuedEngineInterface::request_object(const string& path)
+{
+ push_queued(new RequestObjectEvent(*_engine.get(), _responder, now(), path));
+}
+
+
+void
QueuedEngineInterface::request_port_value(const string& port_path)
{
push_queued(new RequestPortValueEvent(*_engine.get(), _responder, now(), port_path));
diff --git a/src/libs/engine/QueuedEngineInterface.h b/src/libs/engine/QueuedEngineInterface.h
index 10b120e8..2a922acd 100644
--- a/src/libs/engine/QueuedEngineInterface.h
+++ b/src/libs/engine/QueuedEngineInterface.h
@@ -142,6 +142,10 @@ public:
virtual void ping();
+ virtual void request_plugin(const string& uri);
+
+ virtual void request_object(const string& path);
+
virtual void request_port_value(const string& port_path);
virtual void request_plugins();
diff --git a/src/libs/engine/QueuedEventSource.h b/src/libs/engine/QueuedEventSource.h
index f6be92d7..fddb61ab 100644
--- a/src/libs/engine/QueuedEventSource.h
+++ b/src/libs/engine/QueuedEventSource.h
@@ -22,7 +22,7 @@
#include "types.h"
#include "util/Semaphore.h"
#include "util/Queue.h"
-#include "Slave.h"
+#include "util/Slave.h"
#include "Event.h"
#include "EventSource.h"
diff --git a/src/libs/engine/Thread.cpp b/src/libs/engine/Thread.cpp
deleted file mode 100644
index 45c27ec4..00000000
--- a/src/libs/engine/Thread.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
- *
- * Ingen is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "Thread.h"
-#include <cassert>
-#include <iostream>
-#include <pthread.h>
-
-using std::cerr; using std::cout; using std::endl;
-
-namespace Ingen {
-
-
-Thread::Thread()
-: _pthread_exists(false)
-{
-}
-
-
-Thread::~Thread()
-{
- stop();
-}
-
-
-/** Start the process thread.
- */
-void
-Thread::start()
-{
- cout << "[" << _name << " Thread] Starting." << endl;
-
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setstacksize(&attr, 1500000);
-
- pthread_create(&_pthread, &attr, _static_run, this);
- _pthread_exists = true;
-}
-
-
-/** Stop the process thread.
- */
-void
-Thread::stop()
-{
- if (_pthread_exists) {
- pthread_cancel(_pthread);
- pthread_join(_pthread, NULL);
- _pthread_exists = false;
- }
-}
-
-
-/** Set the scheduling policy for this thread.
- *
- * @param must be one of SCHED_FIFO, SCHED_RR, or SCHED_OTHER.
- */
-void
-Thread::set_scheduling(int policy, unsigned int priority)
-{
- sched_param sp;
- sp.sched_priority = priority;
- int result = pthread_setschedparam(_pthread, SCHED_FIFO, &sp);
- if (!result) {
- cout << "[" << _name << " Thread] Set scheduling policy to ";
- switch (policy) {
- case SCHED_FIFO: cout << "SCHED_FIFO"; break;
- case SCHED_RR: cout << "SCHED_RR"; break;
- case SCHED_OTHER: cout << "SCHED_OTHER"; break;
- default: cout << "UNKNOWN"; break;
- }
- cout << ", priority " << sp.sched_priority << endl;
- } else {
- cout << "[" << _name << " Thread] Unable to set scheduling policy ("
- << strerror(result) << ")" << endl;
- }
-}
-
-
-void*
-Thread::_static_run(void* me)
-{
- Thread* myself = (Thread*)me;
- myself->_run();
- // and I
- return NULL;
-}
-
-} // namespace Ingen
-
diff --git a/src/libs/engine/events.h b/src/libs/engine/events.h
index 9db13bc7..056c302d 100644
--- a/src/libs/engine/events.h
+++ b/src/libs/engine/events.h
@@ -34,6 +34,8 @@
#include "DestroyEvent.h"
#include "SetMetadataEvent.h"
#include "RequestMetadataEvent.h"
+#include "RequestObjectEvent.h"
+#include "RequestPluginEvent.h"
#include "RequestPortValueEvent.h"
#include "RequestAllObjectsEvent.h"
#include "RequestPluginsEvent.h"
diff --git a/src/libs/engine/events/AddNodeEvent.cpp b/src/libs/engine/events/AddNodeEvent.cpp
index 6e42ef82..1a317e39 100644
--- a/src/libs/engine/events/AddNodeEvent.cpp
+++ b/src/libs/engine/events/AddNodeEvent.cpp
@@ -33,23 +33,31 @@
namespace Ingen {
-/*AddNodeEvent::AddNodeEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, Plugin* plugin, bool poly)
+AddNodeEvent::AddNodeEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path,
+ const string& plugin_uri, bool poly)
: QueuedEvent(engine, responder, timestamp),
m_path(path),
- m_plugin(plugin),
+ m_plugin_uri(plugin_uri),
m_poly(poly),
m_patch(NULL),
m_node(NULL),
m_process_order(NULL),
m_node_already_exists(false)
{
-}*/
+}
+
+/** DEPRECATED: Construct from type, library name, and plugin label.
+ *
+ * Do not use.
+ */
AddNodeEvent::AddNodeEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path,
- const string& plugin_uri, bool poly)
+ const string& plugin_type, const string& plugin_lib, const string& plugin_label, bool poly)
: QueuedEvent(engine, responder, timestamp),
m_path(path),
- m_plugin_uri(plugin_uri),
+ m_plugin_type(plugin_type),
+ m_plugin_lib(plugin_lib),
+ m_plugin_label(plugin_label),
m_poly(poly),
m_patch(NULL),
m_node(NULL),
@@ -59,11 +67,6 @@ AddNodeEvent::AddNodeEvent(Engine& engine, CountedPtr<Responder> responder, Samp
}
-AddNodeEvent::~AddNodeEvent()
-{
-}
-
-
void
AddNodeEvent::pre_process()
{
@@ -74,7 +77,10 @@ AddNodeEvent::pre_process()
}
m_patch = _engine.object_store()->find_patch(m_path.parent());
- const Plugin* plugin = _engine.node_factory()->plugin(m_plugin_uri);
+
+ const Plugin* plugin = (m_plugin_uri != "")
+ ? _engine.node_factory()->plugin(m_plugin_uri)
+ : _engine.node_factory()->plugin(m_plugin_type, m_plugin_lib, m_plugin_label);
if (m_patch && plugin) {
if (m_poly)
@@ -130,8 +136,7 @@ AddNodeEvent::post_process()
_responder->respond_error(msg);
} else {
_responder->respond_ok();
- //_engine.broadcaster()->send_node_creation_messages(m_node);
- _engine.broadcaster()->send_node(m_node);
+ _engine.broadcaster()->send_node(m_node, true); // yes, send ports
}
}
diff --git a/src/libs/engine/events/AddNodeEvent.h b/src/libs/engine/events/AddNodeEvent.h
index b4345f90..22e164ea 100644
--- a/src/libs/engine/events/AddNodeEvent.h
+++ b/src/libs/engine/events/AddNodeEvent.h
@@ -39,15 +39,22 @@ class Plugin;
class AddNodeEvent : public QueuedEvent
{
public:
- //AddNodeEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, Plugin* plugin, bool poly);
AddNodeEvent(Engine& engine,
CountedPtr<Responder> responder,
SampleCount timestamp,
const string& node_path,
const string& plugin_uri,
bool poly);
-
- ~AddNodeEvent();
+
+ // DEPRECATED
+ AddNodeEvent(Engine& engine,
+ CountedPtr<Responder> responder,
+ SampleCount timestamp,
+ const string& node_path,
+ const string& plugin_type,
+ const string& lib_name,
+ const string& plugin_label,
+ bool poly);
void pre_process();
void execute(SampleCount nframes, FrameTime start, FrameTime end);
@@ -56,7 +63,10 @@ public:
private:
string m_patch_name;
Path m_path;
- string m_plugin_uri;
+ string m_plugin_uri; ///< If nonempty then type, library, label, are ignored
+ string m_plugin_type;
+ string m_plugin_lib;
+ string m_plugin_label;
bool m_poly;
Patch* m_patch;
Node* m_node;
diff --git a/src/libs/engine/events/AddPortEvent.cpp b/src/libs/engine/events/AddPortEvent.cpp
index 06ddae94..ae692b1b 100644
--- a/src/libs/engine/events/AddPortEvent.cpp
+++ b/src/libs/engine/events/AddPortEvent.cpp
@@ -23,6 +23,7 @@
#include "Patch.h"
#include "Maid.h"
#include "util/Path.h"
+#include "QueuedEventSource.h"
#include "ObjectStore.h"
#include "ClientBroadcaster.h"
#include "util/Path.h"
@@ -32,12 +33,13 @@
#include "List.h"
#include "Driver.h"
#include "DuplexPort.h"
+#include "Array.h"
namespace Ingen {
-AddPortEvent::AddPortEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& type, bool is_output)
-: QueuedEvent(engine, responder, timestamp),
+AddPortEvent::AddPortEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& type, bool is_output, QueuedEventSource* source)
+: QueuedEvent(engine, responder, timestamp, true, source),
_path(path),
_type(type),
_is_output(is_output),
@@ -46,6 +48,14 @@ AddPortEvent::AddPortEvent(Engine& engine, CountedPtr<Responder> responder, Samp
_patch_port(NULL),
_driver_port(NULL)
{
+ /* This is blocking because of the two different sets of Patch ports, the array used in the
+ * audio thread (inherited from NodeBase), and the arrays used in the pre processor thread.
+ * If two add port events arrive in the same cycle and the second pre processes before the
+ * first executes, bad things happen (ports are lost).
+ *
+ * FIXME: fix this using RCU
+ */
+
string type_str;
if (type == "CONTROL" || type == "AUDIO")
_data_type = DataType::FLOAT;
@@ -73,17 +83,22 @@ AddPortEvent::pre_process()
if (_type == "AUDIO" || _type == "MIDI")
buffer_size = _engine.audio_driver()->buffer_size();
+ const size_t old_num_ports = _patch->num_ports();
+
_patch_port = _patch->create_port(_path.name(), _data_type, buffer_size, _is_output);
+
if (_patch_port) {
+
if (_is_output)
_patch->add_output(new ListNode<Port*>(_patch_port));
else
_patch->add_input(new ListNode<Port*>(_patch_port));
if (_patch->external_ports())
- _ports_array = new Array<Port*>(_patch->num_ports() + 1, *_patch->external_ports());
+ _ports_array = new Array<Port*>(old_num_ports + 1, *_patch->external_ports());
else
- _ports_array = new Array<Port*>(_patch->num_ports() + 1, NULL);
+ _ports_array = new Array<Port*>(old_num_ports + 1, NULL);
+
_ports_array->at(_patch->num_ports()) = _patch_port;
_engine.object_store()->add(_patch_port);
@@ -96,6 +111,9 @@ AddPortEvent::pre_process()
_driver_port = _engine.midi_driver()->create_port(
dynamic_cast<DuplexPort<MidiMessage>*>(_patch_port));
}
+
+ assert(_patch->num_ports() == old_num_ports);
+ assert(_ports_array->size() == _patch->num_ports() + 1);
}
}
QueuedEvent::pre_process();
@@ -108,8 +126,10 @@ AddPortEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
QueuedEvent::execute(nframes, start, end);
if (_patch_port) {
+
_engine.maid()->push(_patch->external_ports());
//_patch->add_port(_port);
+
_patch->external_ports(_ports_array);
}
@@ -121,6 +141,9 @@ AddPortEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
void
AddPortEvent::post_process()
{
+ if (_source)
+ _source->unblock();
+
if (!_patch_port) {
const string msg = string("Could not create port - ").append(_path);
_responder->respond_error(msg);
diff --git a/src/libs/engine/events/AddPortEvent.h b/src/libs/engine/events/AddPortEvent.h
index 070d07df..0ef33515 100644
--- a/src/libs/engine/events/AddPortEvent.h
+++ b/src/libs/engine/events/AddPortEvent.h
@@ -41,7 +41,7 @@ class DriverPort;
class AddPortEvent : public QueuedEvent
{
public:
- AddPortEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& type, bool is_output);
+ AddPortEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path, const string& type, bool is_output, QueuedEventSource* source);
void pre_process();
void execute(SampleCount nframes, FrameTime start, FrameTime end);
diff --git a/src/libs/engine/events/CreatePatchEvent.cpp b/src/libs/engine/events/CreatePatchEvent.cpp
index 7532291b..97be5557 100644
--- a/src/libs/engine/events/CreatePatchEvent.cpp
+++ b/src/libs/engine/events/CreatePatchEvent.cpp
@@ -120,11 +120,9 @@ CreatePatchEvent::post_process()
_responder->respond_ok();
- // Don't want to send nodes that have been added since prepare()
- //_engine.broadcaster()->send_node_creation_messages(m_patch);
-
- // Patches are always empty on creation, so this is fine
- _engine.broadcaster()->send_patch(m_patch);
+ // Don't send ports/nodes that have been added since prepare()
+ // (otherwise they would be sent twice)
+ _engine.broadcaster()->send_patch(m_patch, false);
} else if (m_error == OBJECT_EXISTS) {
string msg = "Unable to create patch: ";
diff --git a/src/libs/engine/events/Makefile.am b/src/libs/engine/events/Makefile.am
index 5b29e12b..a1760738 100644
--- a/src/libs/engine/events/Makefile.am
+++ b/src/libs/engine/events/Makefile.am
@@ -36,6 +36,10 @@ EXTRA_DIST = \
events/SetMetadataEvent.cpp \
events/RequestMetadataEvent.h \
events/RequestMetadataEvent.cpp \
+ events/RequestPluginEvent.h \
+ events/RequestPluginEvent.cpp \
+ events/RequestObjectEvent.h \
+ events/RequestObjectEvent.cpp \
events/RequestPortValueEvent.h \
events/RequestPortValueEvent.cpp \
events/RequestAllObjectsEvent.h \
diff --git a/src/libs/engine/events/RequestAllObjectsEvent.cpp b/src/libs/engine/events/RequestAllObjectsEvent.cpp
index f51a514e..893aa5df 100644
--- a/src/libs/engine/events/RequestAllObjectsEvent.cpp
+++ b/src/libs/engine/events/RequestAllObjectsEvent.cpp
@@ -48,7 +48,7 @@ RequestAllObjectsEvent::post_process()
// Everything is a child of the root patch, so this sends it all
Patch* root = _engine.object_store()->find_patch("/");
if (root)
- ObjectSender::send_patch(m_client.get(), root);
+ ObjectSender::send_patch(m_client.get(), root, true);
} else {
_responder->respond_error("Unable to find client to send all objects");
diff --git a/src/libs/engine/events/RequestObjectEvent.cpp b/src/libs/engine/events/RequestObjectEvent.cpp
new file mode 100644
index 00000000..3b0dc6fd
--- /dev/null
+++ b/src/libs/engine/events/RequestObjectEvent.cpp
@@ -0,0 +1,97 @@
+/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "RequestObjectEvent.h"
+#include <string>
+#include "Responder.h"
+#include "Engine.h"
+#include "interface/ClientInterface.h"
+#include "TypedPort.h"
+#include "ObjectStore.h"
+#include "ClientBroadcaster.h"
+#include "Patch.h"
+#include "Node.h"
+#include "ObjectSender.h"
+
+using std::string;
+
+namespace Ingen {
+
+
+RequestObjectEvent::RequestObjectEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& path)
+: QueuedEvent(engine, responder, timestamp),
+ m_path(path),
+ m_object(NULL)
+{
+}
+
+
+void
+RequestObjectEvent::pre_process()
+{
+ m_client = _engine.broadcaster()->client(_responder->client_key());
+ m_object = _engine.object_store()->find(m_path);
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+RequestObjectEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
+{
+ QueuedEvent::execute(nframes, start, end);
+ assert(_time >= start && _time <= end);
+}
+
+
+void
+RequestObjectEvent::post_process()
+{
+ if (!m_object) {
+ _responder->respond_error("Unable to find object requested.");
+
+ } else if (m_client) {
+ Patch* const patch = dynamic_cast<Patch*>(m_object);
+ if (patch) {
+ _responder->respond_ok();
+ ObjectSender::send_patch(m_client.get(), patch, true);
+ return;
+ }
+
+ Node* const node = dynamic_cast<Node*>(m_object);
+ if (node) {
+ _responder->respond_ok();
+ ObjectSender::send_node(m_client.get(), node, true);
+ return;
+ }
+
+ Port* const port = dynamic_cast<Port*>(m_object);
+ if (port) {
+ _responder->respond_ok();
+ ObjectSender::send_port(m_client.get(), port);
+ return;
+ }
+
+ _responder->respond_error("Object of unknown type requested.");
+
+ } else {
+ _responder->respond_error("Unable to find client to send object.");
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/libs/engine/events/RequestObjectEvent.h b/src/libs/engine/events/RequestObjectEvent.h
new file mode 100644
index 00000000..276b60fa
--- /dev/null
+++ b/src/libs/engine/events/RequestObjectEvent.h
@@ -0,0 +1,55 @@
+/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef REQUESTOBJECTEVENT_H
+#define REQUESTOBJECTEVENT_H
+
+#include <string>
+#include "QueuedEvent.h"
+#include "types.h"
+
+using std::string;
+
+namespace Ingen {
+
+class GraphObject;
+namespace Shared { class ClientInterface; }
+using Shared::ClientInterface;
+
+
+/** A request from a client to send the value of a port.
+ *
+ * \ingroup engine
+ */
+class RequestObjectEvent : public QueuedEvent
+{
+public:
+ RequestObjectEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& port_path);
+
+ void pre_process();
+ void execute(SampleCount nframes, FrameTime start, FrameTime end);
+ void post_process();
+
+private:
+ string m_path;
+ GraphObject* m_object;
+ CountedPtr<ClientInterface> m_client;
+};
+
+
+} // namespace Ingen
+
+#endif // REQUESTOBJECTEVENT_H
diff --git a/src/libs/engine/events/RequestPluginEvent.cpp b/src/libs/engine/events/RequestPluginEvent.cpp
new file mode 100644
index 00000000..95141226
--- /dev/null
+++ b/src/libs/engine/events/RequestPluginEvent.cpp
@@ -0,0 +1,78 @@
+/* This file is part of Ingen. Copyright (C) 2006 Dave Robillard.
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "RequestPluginEvent.h"
+#include <string>
+#include "Responder.h"
+#include "Engine.h"
+#include "interface/ClientInterface.h"
+#include "TypedPort.h"
+#include "ObjectStore.h"
+#include "ClientBroadcaster.h"
+#include "NodeFactory.h"
+#include "Plugin.h"
+
+using std::string;
+
+namespace Ingen {
+
+
+RequestPluginEvent::RequestPluginEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& uri)
+: QueuedEvent(engine, responder, timestamp),
+ m_uri(uri),
+ m_plugin(NULL)
+{
+}
+
+
+void
+RequestPluginEvent::pre_process()
+{
+ m_client = _engine.broadcaster()->client(_responder->client_key());
+ m_plugin = _engine.node_factory()->plugin(m_uri);
+
+ QueuedEvent::pre_process();
+}
+
+
+void
+RequestPluginEvent::execute(SampleCount nframes, FrameTime start, FrameTime end)
+{
+ QueuedEvent::execute(nframes, start, end);
+ assert(_time >= start && _time <= end);
+}
+
+
+void
+RequestPluginEvent::post_process()
+{
+ if (!m_plugin) {
+ _responder->respond_error("Unable to find plugin requested.");
+
+ } else if (m_client) {
+
+ _responder->respond_ok();
+ assert(m_plugin->uri() == m_uri);
+ m_client->new_plugin(m_uri, m_plugin->name());
+
+ } else {
+ _responder->respond_error("Unable to find client to send plugin.");
+ }
+}
+
+
+} // namespace Ingen
+
diff --git a/src/libs/engine/Thread.h b/src/libs/engine/events/RequestPluginEvent.h
index 52423844..1c12c78e 100644
--- a/src/libs/engine/Thread.h
+++ b/src/libs/engine/events/RequestPluginEvent.h
@@ -14,50 +14,42 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef THREAD_H
-#define THREAD_H
+#ifndef REQUESTPLUGINEVENT_H
+#define REQUESTPLUGINEVENT_H
#include <string>
-#include <pthread.h>
-
-namespace Ingen {
+#include "QueuedEvent.h"
+#include "types.h"
+using std::string;
-/* FIXME: This isn't Ingen specific at all. Move it to util. */
+namespace Ingen {
+
+class Plugin;
+namespace Shared { class ClientInterface; }
+using Shared::ClientInterface;
-/** Abstract base class for all threads.
+/** A request from a client to send the value of a port.
*
* \ingroup engine
*/
-class Thread
+class RequestPluginEvent : public QueuedEvent
{
public:
- Thread();
- virtual ~Thread();
-
- virtual void start();
- virtual void stop();
+ RequestPluginEvent(Engine& engine, CountedPtr<Responder> responder, SampleCount timestamp, const string& uri);
- void set_name(const std::string& name) { _name = name; }
- void set_scheduling(int policy, unsigned int priority);
-
-protected:
- virtual void _run() = 0;
-
- std::string _name;
- pthread_t _pthread;
- bool _pthread_exists;
+ void pre_process();
+ void execute(SampleCount nframes, FrameTime start, FrameTime end);
+ void post_process();
private:
- // Prevent copies
- Thread(const Thread&);
- Thread& operator=(const Thread&);
-
- static void* _static_run(void* me);
+ string m_uri;
+ const Plugin* m_plugin;
+ CountedPtr<ClientInterface> m_client;
};
} // namespace Ingen
-#endif // THREAD_H
+#endif // REQUESTPLUGINEVENT_H
diff --git a/src/progs/ingenuity/App.cpp b/src/progs/ingenuity/App.cpp
index a4b820d1..55cab815 100644
--- a/src/progs/ingenuity/App.cpp
+++ b/src/progs/ingenuity/App.cpp
@@ -99,7 +99,7 @@ App::attach(const CountedPtr<ModelEngineInterface>& engine, const CountedPtr<Sig
_engine = engine;
_client = client;
- _store = new Store(client);
+ _store = new Store(engine, client);
_loader = new Loader(engine);
_patch_tree_window->init(*_store);
diff --git a/src/progs/ingenuity/BreadCrumbBox.cpp b/src/progs/ingenuity/BreadCrumbBox.cpp
index c4234e8a..5fa5eb6e 100644
--- a/src/progs/ingenuity/BreadCrumbBox.cpp
+++ b/src/progs/ingenuity/BreadCrumbBox.cpp
@@ -28,6 +28,17 @@ BreadCrumbBox::BreadCrumbBox()
}
+CountedPtr<PatchView>
+BreadCrumbBox::view(const Path& path)
+{
+ for (std::list<BreadCrumb*>::const_iterator i = _breadcrumbs.begin(); i != _breadcrumbs.end(); ++i)
+ if ((*i)->path() == path)
+ return (*i)->view();
+
+ return CountedPtr<PatchView>();
+}
+
+
/** Sets up the crumbs to display a @a path.
*
* If @a path is already part of the shown path, it will be selected and the
@@ -45,7 +56,12 @@ BreadCrumbBox::build(Path path, CountedPtr<PatchView> view)
for (std::list<BreadCrumb*>::iterator i = _breadcrumbs.begin(); i != _breadcrumbs.end(); ++i) {
if ((*i)->path() == path) {
(*i)->set_active(true);
- (*i)->set_view(view);
+ if (!(*i)->view())
+ (*i)->set_view(view);
+
+ // views are expensive, having two around for the same patch is a bug
+ assert((*i)->view() == view);
+
} else {
(*i)->set_active(false);
}
diff --git a/src/progs/ingenuity/BreadCrumbBox.h b/src/progs/ingenuity/BreadCrumbBox.h
index e38d8e49..93af05a3 100644
--- a/src/progs/ingenuity/BreadCrumbBox.h
+++ b/src/progs/ingenuity/BreadCrumbBox.h
@@ -32,6 +32,8 @@ class BreadCrumb;
/** Collection of breadcrumb buttons forming a path.
*
+ * This doubles as a cache for PatchViews.
+ *
* \ingroup Ingenuity
*/
class BreadCrumbBox : public Gtk::HBox
@@ -39,6 +41,8 @@ class BreadCrumbBox : public Gtk::HBox
public:
BreadCrumbBox();
+ CountedPtr<PatchView> view(const Path& path);
+
void build(Path path, CountedPtr<PatchView> view);
sigc::signal<void, const Path&, CountedPtr<PatchView> > signal_patch_selected;
diff --git a/src/progs/ingenuity/LoadPluginWindow.cpp b/src/progs/ingenuity/LoadPluginWindow.cpp
index e99550e5..01a2accd 100644
--- a/src/progs/ingenuity/LoadPluginWindow.cpp
+++ b/src/progs/ingenuity/LoadPluginWindow.cpp
@@ -263,7 +263,7 @@ LoadPluginWindow::generate_module_name(int offset)
CountedPtr<PluginModel> plugin = row.get_value(m_plugins_columns.m_col_plugin_model);
char num_buf[3];
for (uint i=0; i < 99; ++i) {
- name = plugin->plug_label();
+ name = plugin->default_node_name();
if (name == "")
name = plugin->name().substr(0, plugin->name().find(' '));
if (i+offset != 0) {
@@ -381,8 +381,6 @@ LoadPluginWindow::filter_changed()
//model_row[m_plugins_columns.m_col_label] = plugin->plug_label();
model_row[m_plugins_columns.m_col_type] = plugin->type_string();
model_row[m_plugins_columns.m_col_uri] = plugin->uri();
- model_row[m_plugins_columns.m_col_label] = plugin->plug_label();
- //model_row[m_plugins_columns.m_col_library] = plugin->lib_name();
model_row[m_plugins_columns.m_col_plugin_model] = plugin;
++num_visible;
diff --git a/src/progs/ingenuity/LoadSubpatchWindow.cpp b/src/progs/ingenuity/LoadSubpatchWindow.cpp
index 07b51716..453d874e 100644
--- a/src/progs/ingenuity/LoadSubpatchWindow.cpp
+++ b/src/progs/ingenuity/LoadSubpatchWindow.cpp
@@ -138,8 +138,7 @@ LoadSubpatchWindow::ok_clicked()
const string filename = get_filename();
- // FIXME
- string name = filename.substr(filename.find_last_of("/")+1);
+ string name = "";
int poly = 1;
if (m_name_from_user_radio->get_active())
@@ -150,17 +149,7 @@ LoadSubpatchWindow::ok_clicked()
else if (m_poly_from_parent_radio->get_active())
poly = m_patch->poly();
- /*CountedPtr<PatchModel> pm(new PatchModel(m_patch->path().base() + name, poly));
- pm->filename(filename);
-
- pm->set_metadata("module-x", Atom((float)m_new_module_x));
- pm->set_metadata("module-y", Atom((float)m_new_module_y));
-
- App::instance().loader()->load_patch(pm, true, false);
-
- App::instance().configuration()->set_patch_folder(pm->filename().substr(0, pm->filename().find_last_of("/")));
- */
- cerr << "FIXME: load subpatch" << endl;
+ App::instance().loader()->load_patch(filename, m_patch->path(), name, poly, m_initial_data);
hide();
}
diff --git a/src/progs/ingenuity/Loader.cpp b/src/progs/ingenuity/Loader.cpp
index a0f099c2..59d718c7 100644
--- a/src/progs/ingenuity/Loader.cpp
+++ b/src/progs/ingenuity/Loader.cpp
@@ -25,219 +25,63 @@ using std::cout; using std::endl;
namespace Ingenuity {
-// LoadPatchEvent //
-
-void
-LoadPatchEvent::execute()
-{
- assert(m_patch_librarian != NULL);
- m_patch_librarian->load_patch(m_patch_model, m_wait, m_merge);
-}
-
-
-
-// SavePatchEvent //
-
-void
-SavePatchEvent::execute()
-{
- assert(m_patch_librarian != NULL);
- m_patch_librarian->save_patch(m_patch_model, m_filename, m_recursive);
-}
-
-/*
-void
-LoadSessionEvent::execute()
-{
- std::ifstream is;
- is.open(m_filename.c_str(), std::ios::in);
-
- if ( ! is.good()) {
- cout << "[Loader] Unable to open session file " << m_filename << endl;
- return;
- } else {
- cout << "[Loader] Loading session from " << m_filename << endl;
- }
- string s;
-
- is >> s;
- if (s != "version") {
- cout << "[Loader] Corrupt session file." << endl;
- is.close();
- return;
- }
-
- is >> s;
- if (s != "1") {
- cout << "[Loader] Unrecognised session file version." << endl;
- is.close();
- return;
- }
-
- while (!is.eof()) {
- is >> s;
- if (s == "") continue;
-
- if (s != "patch") {
- //cerr << "[Loader] Corrupt session file, aborting session load." << endl;
- break;
- } else {
- is >> s;
- PatchModel* pm = new PatchModel("", 0);
- if (s.substr(0, 1) != "/")
- s = m_filename.substr(0, m_filename.find_last_of("/")+1) + s;
- pm->filename(s);
- pm->parent(NULL);
- m_patch_librarian->load_patch(pm);
- }
- }
-
- is.close();
-}
-
-
-void
-SaveSessionEvent::execute()
-{
- assert(m_filename != "");
- string dir = m_filename.substr(0, m_filename.find_last_of("/"));
-
- string patch_filename;
-
- std::ofstream os;
- os.open(m_filename.c_str(), std::ios::out);
-
- if ( ! os.good()) {
- cout << "[Loader] Unable to write to session file " << m_filename << endl;
- return;
- } else {
- cout << "[Loader] Saving session to " << m_filename << endl;
- }
-
- os << "version 1" << endl;
-
- for (map<string,PatchController*>::iterator i = app->patches().begin();
- i != app->patches().end(); ++i)
- {
- if ((*i).second->model()->parent() == NULL) {
- patch_filename = (*i).second->model()->filename();
-
- // Make path relative if possible
- if (patch_filename.length() > dir.length() &&
- patch_filename.substr(0, dir.length()) == dir)
- patch_filename = patch_filename.substr(dir.length()+1);
-
- os << "patch " << patch_filename << endl;
- }
- }
-
- os.close();
-}
-*/
-
-
-//////// Loader //////////
-
-
Loader::Loader(CountedPtr<ModelEngineInterface> engine)
-: m_patch_librarian(new PatchLibrarian(engine)),
- m_event(NULL),
- m_thread_exit_flag(false)
+: _patch_librarian(new PatchLibrarian(engine))
{
- assert(m_patch_librarian != NULL);
- pthread_mutex_init(&m_mutex, NULL);
- pthread_cond_init(&m_cond, NULL);
-
+ assert(_patch_librarian != NULL);
+
// FIXME: rework this so the thread is only present when it's doing something (save mem)
- launch();
+ start();
}
Loader::~Loader()
{
- m_thread_exit_flag = true;
- pthread_join(m_thread, NULL);
- delete m_patch_librarian;
-}
-
-
-void
-Loader::set_event(LoaderEvent* ev)
-{
- assert(ev != NULL);
-
- pthread_mutex_lock(&m_mutex);
- assert(m_event == NULL);
- m_event = ev;
- pthread_cond_signal(&m_cond);
- pthread_mutex_unlock(&m_mutex);
+ delete _patch_librarian;
}
void
-Loader::launch()
+Loader::_whipped()
{
- pthread_create(&m_thread, NULL, Loader::thread_function, this);
-}
+ _mutex.lock();
+ Closure& ev = _event;
+ ev();
+ ev.disconnect();
-void*
-Loader::thread_function(void* me)
-{
- Loader* ct = static_cast<Loader*>(me);
- return ct->m_thread_function(NULL);
-}
-
-
-void*
-Loader::m_thread_function(void *)
-{
- while ( ! m_thread_exit_flag) {
- pthread_mutex_lock(&m_mutex);
- pthread_cond_wait(&m_cond, &m_mutex);
-
- LoaderEvent* ev = m_event;
- ev->execute();
- delete ev;
- m_event = NULL;
-
- pthread_mutex_unlock(&m_mutex);
- }
-
- pthread_exit(NULL);
- return NULL;
+ _cond.signal();
+ _mutex.unlock();
}
void
-Loader::load_patch(CountedPtr<PatchModel> model, bool wait, bool merge)
+Loader::load_patch(const string& filename,
+ const string& parent_path,
+ const string& name,
+ size_t poly,
+ const MetadataMap& initial_data,
+ bool existing)
{
- set_event(new LoadPatchEvent(m_patch_librarian, model, wait, merge));
-}
-
-
-void
-Loader::save_patch(CountedPtr<PatchModel> model, const string& filename, bool recursive)
-{
- cout << "[Loader] Saving patch " << filename << endl;
- set_event(new SavePatchEvent(m_patch_librarian, model, filename, recursive));
-}
+ _mutex.lock();
+ _event = sigc::hide_return(sigc::bind(
+ sigc::mem_fun(_patch_librarian, &PatchLibrarian::load_patch),
+ filename, parent_path, name, poly, initial_data, existing));
+
+ whip();
-/*
-void
-Loader::load_session(const string& filename)
-{
- set_event(new LoadSessionEvent(m_patch_librarian, filename));
+ _cond.wait(_mutex);
+ _mutex.unlock();
}
void
-Loader::save_session(const string& filename)
+Loader::save_patch(CountedPtr<PatchModel> model, const string& filename, bool recursive)
{
- cout << "Saving session..." << endl;
- set_event(new SaveSessionEvent(m_patch_librarian, filename));
+ cerr << "FIXME: (loader) save patch\n";
+ //cout << "[Loader] Saving patch " << filename << endl;
+ //set_event(new SavePatchEvent(m_patch_librarian, model, filename, recursive));
}
-*/
} // namespace Ingenuity
diff --git a/src/progs/ingenuity/Loader.h b/src/progs/ingenuity/Loader.h
index 58c301af..a33945a1 100644
--- a/src/progs/ingenuity/Loader.h
+++ b/src/progs/ingenuity/Loader.h
@@ -19,97 +19,23 @@
#include <string>
#include <cassert>
+#include "util/Thread.h"
+#include "util/Slave.h"
+#include "util/Mutex.h"
+#include "util/Condition.h"
#include "ModelEngineInterface.h"
+#include "ObjectModel.h"
using std::string;
namespace Ingen { namespace Client {
class PatchLibrarian;
class PatchModel;
- class ModelEngineInterface;
} }
using namespace Ingen::Client;
namespace Ingenuity {
-/** Event to run in the Loader thread.
- *
- * \ingroup Ingenuity
- */
-class LoaderEvent
-{
-public:
- virtual void execute() = 0;
- virtual ~LoaderEvent() {}
-protected:
- LoaderEvent() {}
-};
-
-
-/** Loader thread patch loading event.
- *
- * \ingroup Ingenuity
- */
-class LoadPatchEvent : public LoaderEvent
-{
-public:
- LoadPatchEvent(PatchLibrarian* pl, CountedPtr<PatchModel> model, bool wait, bool merge)
- : m_patch_librarian(pl), m_patch_model(model), m_wait(wait), m_merge(merge) {}
- virtual ~LoadPatchEvent() {}
- void execute();
-private:
- PatchLibrarian* m_patch_librarian;
- CountedPtr<PatchModel> m_patch_model;
- bool m_wait;
- bool m_merge;
-};
-
-
-/** Loader thread patch loading event.
- *
- * \ingroup Ingenuity
- */
-class SavePatchEvent : public LoaderEvent
-{
-public:
- SavePatchEvent(PatchLibrarian* pl, CountedPtr<PatchModel> pm, const string& filename, bool recursive)
- : m_patch_librarian(pl), m_patch_model(pm), m_filename(filename), m_recursive(recursive) {}
- virtual ~SavePatchEvent() {}
- void execute();
-private:
- PatchLibrarian* m_patch_librarian;
- CountedPtr<PatchModel> m_patch_model;
- string m_filename;
- bool m_recursive;
-};
-
-/*
-class LoadSessionEvent : public LoaderEvent
-{
-public:
- LoadSessionEvent(PatchLibrarian* pl, const string& filename)
- : m_patch_librarian(pl), m_filename(filename) {}
- virtual ~LoadSessionEvent() {}
- void execute();
-private:
- PatchLibrarian* m_patch_librarian;
- string m_filename;
-};
-
-
-class SaveSessionEvent : public LoaderEvent
-{
-public:
- SaveSessionEvent(PatchLibrarian* pl, const string& filename)
- : m_patch_librarian(pl), m_filename(filename) {}
- virtual ~SaveSessionEvent() {}
- void execute();
-private:
- PatchLibrarian* m_patch_librarian;
- string m_filename;
-};
-*/
-
/** Thread for loading patch files.
*
* This is a seperate thread so it can send all the loading message without
@@ -118,37 +44,35 @@ private:
*
* \ingroup Ingenuity
*/
-class Loader
+class Loader : public Slave
{
public:
Loader(CountedPtr<ModelEngineInterface> engine);
~Loader();
- PatchLibrarian& librarian() { return *m_patch_librarian; }
+ PatchLibrarian& librarian() { return *_patch_librarian; }
- void launch();
- void exit() { m_thread_exit_flag = true; }
+ void load_patch(const string& filename,
+ const string& parent_path,
+ const string& name,
+ size_t poly,
+ const MetadataMap& initial_data,
+ bool merge = false);
- void load_patch(CountedPtr<PatchModel> model, bool wait, bool merge);
void save_patch(CountedPtr<PatchModel> model, const string& filename, bool recursive);
-
- //void load_session(const string& filename);
- //void save_session(const string& filename);
-
- static void* thread_function(void* me);
+
private:
- void* m_thread_function(void*);
-
- void set_event(LoaderEvent* ev);
- PatchLibrarian* const m_patch_librarian;
- LoaderEvent* m_event;
- bool m_thread_exit_flag;
- pthread_t m_thread;
- pthread_mutex_t m_mutex;
- pthread_cond_t m_cond;
+ /** Returns nothing and takes no parameters (because they have all been bound) */
+ typedef sigc::slot<void> Closure;
+
+ void _whipped();
+ PatchLibrarian* const _patch_librarian;
+ Mutex _mutex;
+ Condition _cond;
+ Closure _event;
};
diff --git a/src/progs/ingenuity/NodeMenu.cpp b/src/progs/ingenuity/NodeMenu.cpp
index c3ee7a5b..9f2a9ea5 100644
--- a/src/progs/ingenuity/NodeMenu.cpp
+++ b/src/progs/ingenuity/NodeMenu.cpp
@@ -65,11 +65,14 @@ NodeMenu::NodeMenu(CountedPtr<NodeModel> node)
//m_controls_menuitem->property_sensitive() = false;
+ cerr << "FIXME: MIDI learn menu\n";
+ /*
if (_node->plugin() && _node->plugin()->type() == PluginModel::Internal
&& _node->plugin()->plug_label() == "midi_control_in") {
items().push_back(Gtk::Menu_Helpers::MenuElem("Learn",
sigc::mem_fun(this, &NodeMenu::on_menu_learn)));
}
+ */
//model->new_port_sig.connect(sigc::mem_fun(this, &NodeMenu::add_port));
//model->destroyed_sig.connect(sigc::mem_fun(this, &NodeMenu::destroy));
diff --git a/src/progs/ingenuity/NodeModule.cpp b/src/progs/ingenuity/NodeModule.cpp
index 9384917b..8545e493 100644
--- a/src/progs/ingenuity/NodeModule.cpp
+++ b/src/progs/ingenuity/NodeModule.cpp
@@ -43,16 +43,7 @@ NodeModule::NodeModule(PatchCanvas* canvas, CountedPtr<NodeModel> node)
}
create_all_ports();
-
- const Atom& x = node->get_metadata("module-x");
- const Atom& y = node->get_metadata("module-y");
-
- if (x.type() == Atom::FLOAT && y.type() == Atom::FLOAT) {
- move_to(x.get_float(), y.get_float());
- } else {
- double x, y;
- ((PatchCanvas*)m_canvas)->get_new_module_location(x, y);
- }
+ set_all_metadata();
node->new_port_sig.connect(sigc::mem_fun(this, &NodeModule::add_port));
node->removed_port_sig.connect(sigc::mem_fun(this, &NodeModule::remove_port));
@@ -77,10 +68,17 @@ NodeModule::create_all_ports()
void
+NodeModule::set_all_metadata()
+{
+ for (MetadataMap::const_iterator i = m_node->metadata().begin(); i != m_node->metadata().end(); ++i)
+ metadata_update(i->first, i->second);
+}
+
+
+void
NodeModule::add_port(CountedPtr<PortModel> port)
{
- cerr << "FIXME: port leak\n";
- new Port(this, port);
+ manage(new Port(this, port));
resize();
}
diff --git a/src/progs/ingenuity/NodeModule.h b/src/progs/ingenuity/NodeModule.h
index 5b4ec922..6f7460bf 100644
--- a/src/progs/ingenuity/NodeModule.h
+++ b/src/progs/ingenuity/NodeModule.h
@@ -68,6 +68,7 @@ protected:
virtual void on_double_click(GdkEventButton* ev) { show_control_window(); }
virtual void on_middle_click(GdkEventButton* ev) { show_control_window(); }
+ void set_all_metadata();
void metadata_update(const string& key, const Atom& value);
void create_all_ports();
diff --git a/src/progs/ingenuity/PatchCanvas.cpp b/src/progs/ingenuity/PatchCanvas.cpp
index 5dc39a2b..9419b252 100644
--- a/src/progs/ingenuity/PatchCanvas.cpp
+++ b/src/progs/ingenuity/PatchCanvas.cpp
@@ -103,8 +103,7 @@ PatchCanvas::build_canvas() {
// Create pseudo modules for ports (ports on this canvas, not on our module)
for (PortModelList::const_iterator i = m_patch->ports().begin();
i != m_patch->ports().end(); ++i) {
- cerr << "FIXME: PORT MODULE LEAK!" << endl;
- new PatchPortModule(this, *i);
+ manage(new PatchPortModule(this, *i));
}
// Create connections
@@ -118,13 +117,11 @@ PatchCanvas::build_canvas() {
void
PatchCanvas::add_node(CountedPtr<NodeModel> nm)
{
- cerr << "FIXME: MODULE LEAK!" << endl;
-
CountedPtr<PatchModel> pm = PtrCast<PatchModel>(nm);
if (pm)
- new SubpatchModule(this, pm);
+ manage(new SubpatchModule(this, pm));
else
- new NodeModule(this, nm);
+ manage(new NodeModule(this, nm));
}
@@ -139,9 +136,7 @@ PatchCanvas::remove_node(CountedPtr<NodeModel> nm)
void
PatchCanvas::add_port(CountedPtr<PortModel> pm)
{
- cerr << "FIXME: PORT MODULE LEAK!" << endl;
-
- new PatchPortModule(this, pm);
+ manage(new PatchPortModule(this, pm));
}
diff --git a/src/progs/ingenuity/PatchView.cpp b/src/progs/ingenuity/PatchView.cpp
index e8cf9e5f..fbebd886 100644
--- a/src/progs/ingenuity/PatchView.cpp
+++ b/src/progs/ingenuity/PatchView.cpp
@@ -77,6 +77,7 @@ PatchView::set_patch(CountedPtr<PatchModel> patch)
// Connect widget signals to do things
_process_but->signal_toggled().connect(sigc::mem_fun(this, &PatchView::process_toggled));
_clear_but->signal_clicked().connect(sigc::mem_fun(this, &PatchView::clear_clicked));
+ _refresh_but->signal_clicked().connect(sigc::mem_fun(this, &PatchView::refresh_clicked));
_zoom_normal_but->signal_clicked().connect(sigc::bind(sigc::mem_fun(
static_cast<FlowCanvas*>(_canvas), &FlowCanvas::set_zoom), 1.0));
@@ -120,12 +121,21 @@ PatchView::process_toggled()
}
}
+
void
PatchView::clear_clicked()
{
App::instance().engine()->clear_patch(_patch->path());
}
+
+void
+PatchView::refresh_clicked()
+{
+ App::instance().engine()->request_object(_patch->path());
+}
+
+
void
PatchView::enable()
{
diff --git a/src/progs/ingenuity/PatchView.h b/src/progs/ingenuity/PatchView.h
index d0c9c4c4..a0225bda 100644
--- a/src/progs/ingenuity/PatchView.h
+++ b/src/progs/ingenuity/PatchView.h
@@ -68,6 +68,7 @@ private:
void process_toggled();
void clear_clicked();
+ void refresh_clicked();
void enable();
void disable();
diff --git a/src/progs/ingenuity/PatchWindow.cpp b/src/progs/ingenuity/PatchWindow.cpp
index edf2e9d0..e429d136 100644
--- a/src/progs/ingenuity/PatchWindow.cpp
+++ b/src/progs/ingenuity/PatchWindow.cpp
@@ -158,9 +158,15 @@ PatchWindow::set_patch(CountedPtr<PatchModel> patch, CountedPtr<PatchView> view)
m_patch = patch;
- m_view = view ? view : PatchView::create(patch);
- assert(m_view);
+ m_view = m_breadcrumb_box->view(patch->path());
+
+ if (!m_view)
+ m_view = PatchView::create(patch);
+ else
+ assert(!view || m_view == view);
+ assert(m_view);
+
// Add view to ourself
if (m_view->get_parent())
m_view->get_parent()->remove(*m_view);
@@ -196,8 +202,6 @@ PatchWindow::set_patch(CountedPtr<PatchModel> patch, CountedPtr<PatchView> view)
else
m_menu_destroy_patch->set_sensitive(true);
- m_patch->destroyed_sig.connect(sigc::mem_fun(this, &PatchWindow::patch_destroyed));
-
show_all();
m_enable_signal = true;
@@ -205,13 +209,6 @@ PatchWindow::set_patch(CountedPtr<PatchModel> patch, CountedPtr<PatchView> view)
void
-PatchWindow::patch_destroyed()
-{
- App::instance().window_factory()->remove_patch_window(this);
-}
-
-
-void
PatchWindow::event_show_engine()
{
if (m_patch)
diff --git a/src/progs/ingenuity/PatchWindow.h b/src/progs/ingenuity/PatchWindow.h
index 0ab5fe48..b957c420 100644
--- a/src/progs/ingenuity/PatchWindow.h
+++ b/src/progs/ingenuity/PatchWindow.h
@@ -68,7 +68,7 @@ public:
void set_patch_from_path(const Path& path, CountedPtr<PatchView> view);
void set_patch(CountedPtr<PatchModel> pc, CountedPtr<PatchView> view);
- CountedPtr<PatchModel> patch() const { return m_patch; }
+ CountedPtr<PatchModel> patch() const { return m_patch; }
Gtk::MenuItem* menu_view_control_window() { return m_menu_view_control_window; }
@@ -89,8 +89,6 @@ private:
void event_show_controls();
void event_show_engine();
- void patch_destroyed();
-
CountedPtr<PatchModel> m_patch;
CountedPtr<PatchView> m_view;