summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2006-09-18 06:24:53 +0000
committerDavid Robillard <d@drobilla.net>2006-09-18 06:24:53 +0000
commit6f93b3d7c80f9dee2d95fac1bbc4f781a6f45979 (patch)
tree82b27a4802198215546558c006f7ac4228ab0599
parentd520692eb49ff9e5aded38061a204713571b095b (diff)
downloadingen-6f93b3d7c80f9dee2d95fac1bbc4f781a6f45979.tar.gz
ingen-6f93b3d7c80f9dee2d95fac1bbc4f781a6f45979.tar.bz2
ingen-6f93b3d7c80f9dee2d95fac1bbc4f781a6f45979.zip
Work on loading old (deprecated) patches.
More error tolerance in Store, related bugfixes. Patch port adding (threading) bug fixed (made event blocking). Better PatchView cacheing. Moved generic things from engine to util (shared) Bug fixes, features, etc. git-svn-id: http://svn.drobilla.net/lad/ingen@142 a436a847-0d15-0410-975c-d299462d15a1
-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;