diff options
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; |