summaryrefslogtreecommitdiffstats
path: root/src/clients/new
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2006-06-09 15:07:31 +0000
committerDavid Robillard <d@drobilla.net>2006-06-09 15:07:31 +0000
commitacbda29f838280ba98cf9e9e539e9d8a6e8fc6ad (patch)
treee31b37a2456e6d1e564c9a7146c88be259d338b0 /src/clients/new
downloadingen-acbda29f838280ba98cf9e9e539e9d8a6e8fc6ad.tar.gz
ingen-acbda29f838280ba98cf9e9e539e9d8a6e8fc6ad.tar.bz2
ingen-acbda29f838280ba98cf9e9e539e9d8a6e8fc6ad.zip
Added Om aka Graph aka god knows what
git-svn-id: http://svn.drobilla.net/lad/grauph@9 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/clients/new')
-rw-r--r--src/clients/new/PatchLibrarian.cpp824
-rw-r--r--src/clients/new/PatchLibrarian.h66
-rw-r--r--src/clients/new/patch_loader/.deps/cmdline.Po53
-rw-r--r--src/clients/new/patch_loader/.deps/om_patch_loader-patch_loader.Po518
-rw-r--r--src/clients/new/patch_loader/Makefile.am13
-rw-r--r--src/clients/new/patch_loader/README5
-rw-r--r--src/clients/new/patch_loader/cmdline.c163
-rw-r--r--src/clients/new/patch_loader/cmdline.ggo7
-rw-r--r--src/clients/new/patch_loader/cmdline.h47
-rwxr-xr-xsrc/clients/new/patch_loader/om_patch_loaderbin0 -> 221068 bytes
-rw-r--r--src/clients/new/patch_loader/patch_loader.cpp76
11 files changed, 1772 insertions, 0 deletions
diff --git a/src/clients/new/PatchLibrarian.cpp b/src/clients/new/PatchLibrarian.cpp
new file mode 100644
index 00000000..66c013e5
--- /dev/null
+++ b/src/clients/new/PatchLibrarian.cpp
@@ -0,0 +1,824 @@
+/* This file is part of Om. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om 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.
+ *
+ * Om 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.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "PatchLibrarian.h"
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include "PatchModel.h"
+#include "NodeModel.h"
+#include "ConnectionModel.h"
+#include "PortModel.h"
+#include "PresetModel.h"
+#include "OSCModelEngineInterface.h"
+#include "PluginModel.h"
+#include "util/Path.h"
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <utility> // for pair, make_pair
+#include <cassert>
+#include <cstring>
+#include <string>
+#include <unistd.h> // for usleep
+#include <cstdlib> // for atof
+#include <cmath>
+
+using std::string; using std::vector; using std::pair;
+using std::cerr; using std::cout; using std::endl;
+using Om::Path;
+
+namespace LibOmClient {
+
+
+/** Load a patch in to the engine (and client) from a patch file.
+ *
+ * The name and poly from the passed PatchModel are used. If the name is
+ * the empty string, the name will be loaded from the file. If the poly
+ * is 0, it will be loaded from file. Otherwise the given values will
+ * be used.
+ *
+ * @param parent_path Path of the patch to create the new patch under.
+ *
+ * @param name Name to give the new Patch. If @a name is the empty string,
+ * the name stored in the patch file will be used.
+ *
+ * @param poly The polyphony of the new patch if nonzero, otherwise the
+ * polyphony value stored in the patch file will be used.
+ *
+ * @return true on success.
+ */
+bool
+PatchLibrarian::load_patch(EngineInterface* engine,
+ const string& filename,
+ const Path& parent_path,
+ string name,
+ uint32_t poly)
+{
+ cerr << "Loading patch " << filename << "" << endl;
+
+ //const size_t temp_buf_length = 255;
+ //char temp_buf[temp_buf_length];
+
+ xmlDocPtr doc = xmlParseFile(filename.c_str());
+
+ if (doc == NULL ) {
+ cerr << "Unable to parse patch file." << endl;
+ return false;
+ }
+
+ xmlNodePtr cur = xmlDocGetRootElement(doc);
+
+ if (cur == NULL) {
+ cerr << "Document has no root element." << endl;
+ xmlFreeDoc(doc);
+ return false;
+ }
+
+ if (xmlStrcmp(cur->name, (const xmlChar*) "patch")) {
+ cerr << "File is not an Om patch file (root node != patch)." << endl;
+ xmlFreeDoc(doc);
+ return false;
+ }
+
+ cur = cur->xmlChildrenNode;
+ string path;
+
+ map<string, string> metadata;
+
+ // Load Patch attributes
+ while (cur != NULL) {
+ xmlChar* const key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+
+ if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) {
+ if (name == "") {
+ assert(key);
+ name = (char*)key;
+ }
+ } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) {
+ if (poly == 0) {
+ assert(key);
+ poly = atoi((char*)key); // FIXME: error checking
+ }
+ /* Don't know what this tag is, add it as metadata without overwriting
+ * (so caller can set arbitrary metadata which will be preserved)
+ * FIXME: this is just plain filthy. XML is not RDF. */
+ } else if (key
+ && xmlStrcmp(cur->name, (const xmlChar*)"connection")
+ && xmlStrcmp(cur->name, (const xmlChar*)"node")
+ && xmlStrcmp(cur->name, (const xmlChar*)"subpatch")
+ && xmlStrcmp(cur->name, (const xmlChar*)"filename")
+ && xmlStrcmp(cur->name, (const xmlChar*)"preset")) {
+
+ metadata[(char*)cur->name] == (char*)key;
+ }
+
+ xmlFree(key);
+
+ cur = cur->next;
+ }
+
+
+ // Didn't find a polyphony value, set monophonic by default
+ if (poly == 0) poly = 1;
+
+
+ /* FIXME: This functionality needs to be implemented (elsewhere)
+ if (!existing) {
+ // Wait until the patch is created or the node creations may fail
+ if (wait) {
+ int id = m_osc_controller->get_next_request_id();
+ m_osc_controller->set_wait_response_id(id);
+ m_osc_controller->create_patch(pm, id);
+ bool succeeded = m_osc_controller->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 "";
+ }
+ } else {
+ m_osc_controller->create_patch(pm);
+ }
+ }
+ */
+ engine->create_patch(path, 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(path, "filename", filename);
+
+#if 0
+ // Load nodes
+ NodeModel* nm = NULL;
+ cur = xmlDocGetRootElement(doc)->xmlChildrenNode;
+
+ while (cur != NULL) {
+ if ((!xmlStrcmp(cur->name, (const xmlChar*)"node"))) {
+ nm = parse_node(pm, doc, cur);
+ if (nm != NULL) {
+ m_osc_controller->add_node(nm);
+ m_osc_controller->set_all_metadata(nm);
+ for (list<PortModel*>::const_iterator j = nm->ports().begin();
+ j != nm->ports().end(); ++j) {
+ // FIXME: ew
+ snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_min());
+ m_osc_controller->set_metadata((*j)->path(), "user-min", temp_buf);
+ snprintf(temp_buf, temp_buf_length, "%f", (*j)->user_max());
+ m_osc_controller->set_metadata((*j)->path(), "user-max", temp_buf);
+ }
+ nm = NULL;
+ usleep(10000);
+ }
+ }
+ cur = cur->next;
+ }
+
+ // Load subpatches
+ cur = xmlDocGetRootElement(doc)->xmlChildrenNode;
+ while (cur != NULL) {
+ if ((!xmlStrcmp(cur->name, (const xmlChar*)"subpatch"))) {
+ load_subpatch(pm, doc, cur);
+ }
+ cur = cur->next;
+ }
+
+ // Load connections
+ ConnectionModel* cm = NULL;
+ cur = xmlDocGetRootElement(doc)->xmlChildrenNode;
+ while (cur != NULL) {
+ if ((!xmlStrcmp(cur->name, (const xmlChar*)"connection"))) {
+ cm = parse_connection(pm, doc, cur);
+ if (cm != NULL) {
+ m_osc_controller->connect(cm->src_port_path(), cm->dst_port_path());
+ usleep(1000);
+ }
+ }
+ cur = cur->next;
+ }
+
+
+ // Load presets (control values)
+ PresetModel* preset_model = NULL;
+ cur = xmlDocGetRootElement(doc)->xmlChildrenNode;
+ while (cur != NULL) {
+ if ((!xmlStrcmp(cur->name, (const xmlChar*)"preset"))) {
+ preset_model = parse_preset(pm, doc, cur);
+ assert(preset_model != NULL);
+ if (preset_model->name() == "default")
+ m_osc_controller->set_preset(pm->path(), preset_model);
+ }
+ cur = cur->next;
+ }
+#endif
+ xmlFreeDoc(doc);
+ xmlCleanupParser();
+
+ //m_osc_controller->set_all_metadata(pm);
+
+ //if (!existing)
+ // m_osc_controller->enable_patch(pm->path());
+
+ return true;
+}
+
+
+#if 0
+/** Searches for the filename passed in the path, returning the full
+ * path of the file, or the empty string if not found.
+ *
+ * This function tries to be as friendly a black box as possible - if the path
+ * passed is an absolute path and the file is found there, it will return
+ * that path, etc.
+ *
+ * additional_path is a list (colon delimeted as usual) of additional
+ * directories to look in. ie the directory the parent patch resides in would
+ * be a good idea to pass as additional_path, in the case of a subpatch.
+ */
+string
+PatchLibrarian::find_file(const string& filename, const string& additional_path)
+{
+ string search_path = additional_path + ":" + m_patch_path;
+
+ // Try to open the raw filename first
+ std::ifstream is(filename.c_str(), std::ios::in);
+ if (is.good()) {
+ is.close();
+ return filename;
+ }
+
+ string directory;
+ string full_patch_path = "";
+
+ while (search_path != "") {
+ directory = search_path.substr(0, search_path.find(':'));
+ if (search_path.find(':') != string::npos)
+ search_path = search_path.substr(search_path.find(':')+1);
+ else
+ search_path = "";
+
+ full_patch_path = directory +"/"+ filename;
+
+ std::ifstream is;
+ is.open(full_patch_path.c_str(), std::ios::in);
+
+ if (is.good()) {
+ is.close();
+ return full_patch_path;
+ } else {
+ cerr << "[PatchLibrarian] Could not find patch file " << full_patch_path << endl;
+ }
+ }
+
+ return "";
+}
+
+
+/** Save a patch from a PatchModel to a filename.
+ *
+ * The filename passed is the true filename the patch will be saved to (with no prefixing or anything
+ * like that), and the patch_model's filename member will be set accordingly.
+ *
+ * This will break if:
+ * - The filename does not have an extension (ie contain a ".")
+ * - The patch_model has no (Om) path
+ */
+void
+PatchLibrarian::save_patch(PatchModel* patch_model, const string& filename, bool recursive)
+{
+ assert(filename != "");
+ assert(patch_model->path() != "");
+
+ cout << "Saving patch " << patch_model->path() << " to " << filename << endl;
+
+ patch_model->filename(filename);
+
+ string dir = filename.substr(0, filename.find_last_of("/"));
+
+ NodeModel* nm = NULL;
+ PatchModel* spm = NULL; // subpatch model
+
+ xmlDocPtr xml_doc = NULL;
+ xmlNodePtr xml_root_node = NULL;
+ xmlNodePtr xml_node = NULL;
+ xmlNodePtr xml_child_node = NULL;
+ xmlNodePtr xml_grandchild_node = NULL;
+
+ xml_doc = xmlNewDoc((xmlChar*)"1.0");
+ xml_root_node = xmlNewNode(NULL, (xmlChar*)"patch");
+ xmlDocSetRootElement(xml_doc, xml_root_node);
+
+ const size_t temp_buf_length = 255;
+ char temp_buf[temp_buf_length];
+
+ string patch_name;
+ if (patch_model->path() != "/") {
+ patch_name = patch_model->name();
+ } else {
+ patch_name = filename;
+ if (patch_name.find("/") != string::npos)
+ patch_name = patch_name.substr(patch_name.find_last_of("/") + 1);
+ if (patch_name.find(".") != string::npos)
+ patch_name = patch_name.substr(0, patch_name.find_last_of("."));
+ }
+
+ assert(patch_name.length() > 0);
+ xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"name",
+ (xmlChar*)patch_name.c_str());
+
+ snprintf(temp_buf, temp_buf_length, "%zd", patch_model->poly());
+ xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"polyphony", (xmlChar*)temp_buf);
+
+ // Write metadata
+ for (map<string, string>::const_iterator i = patch_model->metadata().begin();
+ i != patch_model->metadata().end(); ++i) {
+ // Dirty hack, don't save coordinates in patch file
+ if ((*i).first != "module-x" && (*i).first != "module-y"
+ && (*i).first != "filename")
+ xml_node = xmlNewChild(xml_root_node, NULL,
+ (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str());
+
+ assert((*i).first != "node");
+ assert((*i).first != "subpatch");
+ assert((*i).first != "name");
+ assert((*i).first != "polyphony");
+ assert((*i).first != "preset");
+ }
+
+ // Save nodes and subpatches
+ for (NodeModelMap::const_iterator i = patch_model->nodes().begin(); i != patch_model->nodes().end(); ++i) {
+ nm = i->second;
+
+ if (nm->plugin()->type() == PluginModel::Patch) { // Subpatch
+ spm = (PatchModel*)i->second;
+ xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"subpatch", NULL);
+
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)spm->name().c_str());
+
+ string ref_filename;
+ // No path
+ if (spm->filename() == "") {
+ ref_filename = spm->name() + ".om";
+ spm->filename(dir +"/"+ ref_filename);
+ // Absolute path
+ } else if (spm->filename().substr(0, 1) == "/") {
+ // Attempt to make it a relative path, if it's undernath this patch's dir
+ if (dir.substr(0, 1) == "/" && spm->filename().substr(0, dir.length()) == dir) {
+ ref_filename = spm->filename().substr(dir.length()+1);
+ } else { // FIXME: not good
+ ref_filename = spm->filename().substr(spm->filename().find_last_of("/")+1);
+ spm->filename(dir +"/"+ ref_filename);
+ }
+ } else {
+ ref_filename = spm->filename();
+ }
+
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"filename", (xmlChar*)ref_filename.c_str());
+
+ snprintf(temp_buf, temp_buf_length, "%zd", spm->poly());
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"polyphony", (xmlChar*)temp_buf);
+
+ // Write metadata
+ for (map<string, string>::const_iterator i = nm->metadata().begin();
+ i != nm->metadata().end(); ++i) {
+ // Dirty hack, don't save metadata that would be in patch file
+ if ((*i).first != "polyphony" && (*i).first != "filename"
+ && (*i).first != "author" && (*i).first != "description")
+ xml_child_node = xmlNewChild(xml_node, NULL,
+ (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str());
+ }
+
+ if (recursive)
+ save_patch(spm, spm->filename(), true);
+
+ } else { // Normal node
+ xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"node", NULL);
+
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)nm->name().c_str());
+
+ if (nm->plugin() == NULL) break;
+
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"polyphonic",
+ (xmlChar*)((nm->polyphonic()) ? "true" : "false"));
+
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"type",
+ (xmlChar*)nm->plugin()->type_string());
+ /*
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"plugin-label",
+ (xmlChar*)(nm->plugin()->plug_label().c_str()));
+
+ if (nm->plugin()->type() != PluginModel::Internal) {
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"library-name",
+ (xmlChar*)(nm->plugin()->lib_name().c_str()));
+ }*/
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"plugin-uri",
+ (xmlChar*)(nm->plugin()->uri().c_str()));
+
+ // Write metadata
+ for (map<string, string>::const_iterator i = nm->metadata().begin(); i != nm->metadata().end(); ++i) {
+ // DSSI _hack_ (FIXME: fix OSC to be more like this and not smash DSSI into metadata?)
+ if ((*i).first.substr(0, 16) == "dssi-configure--") {
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"dssi-configure", NULL);
+ xml_grandchild_node = xmlNewChild(xml_child_node, NULL,
+ (xmlChar*)"key", (xmlChar*)(*i).first.substr(16).c_str());
+ xml_grandchild_node = xmlNewChild(xml_child_node, NULL,
+ (xmlChar*)"value", (xmlChar*)(*i).second.c_str());
+ } else if ((*i).first == "dssi-program") {
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"dssi-program", NULL);
+ xml_grandchild_node = xmlNewChild(xml_child_node, NULL,
+ (xmlChar*)"bank", (xmlChar*)(*i).second.substr(0, (*i).second.find("/")).c_str());
+ xml_grandchild_node = xmlNewChild(xml_child_node, NULL,
+ (xmlChar*)"program", (xmlChar*)(*i).second.substr((*i).second.find("/")+1).c_str());
+ } else {
+ xml_child_node = xmlNewChild(xml_node, NULL,
+ (xmlChar*)(*i).first.c_str(), (xmlChar*)(*i).second.c_str());
+ }
+ }
+
+ PortModel* pm = NULL;
+ // Write port metadata, if necessary
+ for (list<PortModel*>::const_iterator i = nm->ports().begin(); i != nm->ports().end(); ++i) {
+ pm = (*i);
+ if (pm->is_input() && pm->user_min() != pm->min_val() || pm->user_max() != pm->max_val()) {
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port", NULL);
+ xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"name",
+ (xmlChar*)pm->path().name().c_str());
+ snprintf(temp_buf, temp_buf_length, "%f", pm->user_min());
+ xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"user-min", (xmlChar*)temp_buf);
+ snprintf(temp_buf, temp_buf_length, "%f", pm->user_max());
+ xml_grandchild_node = xmlNewChild(xml_child_node, NULL, (xmlChar*)"user-max", (xmlChar*)temp_buf);
+ }
+ }
+ }
+ }
+
+ // Save connections
+
+ const list<ConnectionModel*>& cl = patch_model->connections();
+ const ConnectionModel* c = NULL;
+
+ for (list<ConnectionModel*>::const_iterator i = cl.begin(); i != cl.end(); ++i) {
+ c = (*i);
+ xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"connection", NULL);
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"source-node",
+ (xmlChar*)c->src_port_path().parent().name().c_str());
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"source-port",
+ (xmlChar*)c->src_port_path().name().c_str());
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"destination-node",
+ (xmlChar*)c->dst_port_path().parent().name().c_str());
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"destination-port",
+ (xmlChar*)c->dst_port_path().name().c_str());
+ }
+
+ // Save control values (ie presets eventually, right now just current control vals)
+
+ xmlNodePtr xml_preset_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"preset", NULL);
+ xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"name", (xmlChar*)"default");
+
+ PortModel* pm = NULL;
+
+ // Save node port controls
+ for (NodeModelMap::const_iterator n = patch_model->nodes().begin(); n != patch_model->nodes().end(); ++n) {
+ nm = n->second;
+ for (PortModelList::const_iterator p = nm->ports().begin(); p != nm->ports().end(); ++p) {
+ pm = *p;
+ if (pm->is_input() && pm->is_control()) {
+ float val = pm->value();
+ xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"control", NULL);
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"node-name",
+ (xmlChar*)nm->name().c_str());
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name",
+ (xmlChar*)pm->path().name().c_str());
+ snprintf(temp_buf, temp_buf_length, "%f", val);
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"value",
+ (xmlChar*)temp_buf);
+ }
+ }
+ }
+
+ // Save patch port controls
+ for (PortModelList::const_iterator p = patch_model->ports().begin();
+ p != patch_model->ports().end(); ++p) {
+ pm = *p;
+ if (pm->is_input() && pm->is_control()) {
+ float val = pm->value();
+ xml_node = xmlNewChild(xml_preset_node, NULL, (xmlChar*)"control", NULL);
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"port-name",
+ (xmlChar*)pm->path().name().c_str());
+ snprintf(temp_buf, temp_buf_length, "%f", val);
+ xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"value",
+ (xmlChar*)temp_buf);
+ }
+ }
+
+ xmlSaveFormatFile(filename.c_str(), xml_doc, 1); // 1 == pretty print
+
+ xmlFreeDoc(xml_doc);
+ xmlCleanupParser();
+}
+
+
+/** Build a NodeModel given a pointer to a Node in a patch file.
+ */
+NodeModel*
+PatchLibrarian::parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr node)
+{
+ NodeModel* nm = new NodeModel("/UNINITIALIZED"); // FIXME: ew
+ PluginModel* plugin = new PluginModel();
+
+ xmlChar* key;
+ xmlNodePtr cur = node->xmlChildrenNode;
+
+ bool found_name = false;
+
+ while (cur != NULL) {
+ key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+
+ if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) {
+ nm->set_path(parent->base_path() + (char*)key);
+ found_name = true;
+ } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphonic"))) {
+ nm->polyphonic(!strcmp((char*)key, "true"));
+ } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"type"))) {
+ plugin->set_type((const char*)key);
+ } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"library-name"))) {
+ plugin->lib_name((char*)key);
+ } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-label"))) {
+ plugin->plug_label((char*)key);
+ } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"plugin-uri"))) {
+ plugin->uri((char*)key);
+ } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"port"))) {
+ xmlNodePtr child = cur->xmlChildrenNode;
+
+ string path;
+ float user_min = 0.0;
+ float user_max = 0.0;
+
+ while (child != NULL) {
+ key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
+
+ if ((!xmlStrcmp(child->name, (const xmlChar*)"name"))) {
+ path = nm->base_path() + (char*)key;
+ } else if ((!xmlStrcmp(child->name, (const xmlChar*)"user-min"))) {
+ user_min = atof((char*)key);
+ } else if ((!xmlStrcmp(child->name, (const xmlChar*)"user-max"))) {
+ user_max = atof((char*)key);
+ }
+
+ xmlFree(key);
+ key = NULL; // Avoid a (possible?) double free
+
+ child = child->next;
+ }
+
+ // FIXME: nasty assumptions
+ PortModel* pm = new PortModel(path,
+ PortModel::CONTROL, PortModel::INPUT, PortModel::NONE,
+ 0.0, user_min, user_max);
+ nm->add_port(pm);
+
+ // 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"))) {
+ xmlNodePtr child = cur->xmlChildrenNode;
+
+ string bank;
+ string program;
+
+ while (child != NULL) {
+ key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
+
+ if ((!xmlStrcmp(child->name, (const xmlChar*)"bank"))) {
+ bank = (char*)key;
+ } else if ((!xmlStrcmp(child->name, (const xmlChar*)"program"))) {
+ program = (char*)key;
+ }
+
+ xmlFree(key);
+ key = NULL; // Avoid a (possible?) double free
+ child = child->next;
+ }
+ nm->set_metadata("dssi-program", bank +"/"+ program);
+
+ } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"dssi-configure"))) {
+ xmlNodePtr child = cur->xmlChildrenNode;
+
+ string dssi_key;
+ string dssi_value;
+
+ while (child != NULL) {
+ key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
+
+ if ((!xmlStrcmp(child->name, (const xmlChar*)"key"))) {
+ dssi_key = (char*)key;
+ } else if ((!xmlStrcmp(child->name, (const xmlChar*)"value"))) {
+ dssi_value = (char*)key;
+ }
+
+ xmlFree(key);
+ key = NULL; // Avoid a (possible?) double free
+
+ child = child->next;
+ }
+ nm->set_metadata(string("dssi-configure--").append(dssi_key), dssi_value);
+
+ } 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);
+ }
+ xmlFree(key);
+ key = NULL;
+
+ cur = cur->next;
+ }
+
+ if (nm->path() == "") {
+ cerr << "[PatchLibrarian] Malformed patch file (node tag has empty children)" << endl;
+ cerr << "[PatchLibrarian] Node ignored." << endl;
+ delete nm;
+ return NULL;
+ } else {
+ nm->plugin(plugin);
+ return nm;
+ }
+}
+
+
+void
+PatchLibrarian::load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePtr subpatch)
+{
+ xmlChar *key;
+ xmlNodePtr cur = subpatch->xmlChildrenNode;
+
+ PatchModel* pm = new PatchModel("/UNINITIALIZED", 1); // FIXME: ew
+
+ 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->base_path() + (const char*)key);
+ } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"polyphony"))) {
+ pm->poly(atoi((const char*)key));
+ } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"filename"))) {
+ pm->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);
+ }
+ xmlFree(key);
+ key = NULL;
+
+ 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);
+}
+
+
+/** Build a ConnectionModel given a pointer to a connection in a patch file.
+ */
+ConnectionModel*
+PatchLibrarian::parse_connection(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr node)
+{
+ //cerr << "[PatchLibrarian] Parsing connection..." << endl;
+
+ xmlChar *key;
+ xmlNodePtr cur = node->xmlChildrenNode;
+
+ string source_node, source_port, dest_node, dest_port;
+
+ while (cur != NULL) {
+ key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+
+ if ((!xmlStrcmp(cur->name, (const xmlChar*)"source-node"))) {
+ source_node = (char*)key;
+ } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"source-port"))) {
+ source_port = (char*)key;
+ } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"destination-node"))) {
+ dest_node = (char*)key;
+ } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"destination-port"))) {
+ dest_port = (char*)key;
+ }
+
+ xmlFree(key);
+ key = NULL; // Avoid a (possible?) double free
+
+ cur = cur->next;
+ }
+
+ 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;
+ }
+
+ // FIXME: temporary compatibility, remove any slashes from port names
+ // remove this soon once patches have migrated
+ string::size_type slash_index;
+ while ((slash_index = source_port.find("/")) != string::npos)
+ source_port[slash_index] = '-';
+
+ while ((slash_index = dest_port.find("/")) != string::npos)
+ dest_port[slash_index] = '-';
+
+ ConnectionModel* cm = new ConnectionModel(parent->base_path() + source_node +"/"+ source_port,
+ parent->base_path() + dest_node +"/"+ dest_port);
+
+ return cm;
+}
+
+
+/** Build a PresetModel given a pointer to a preset in a patch file.
+ */
+PresetModel*
+PatchLibrarian::parse_preset(const PatchModel* patch, xmlDocPtr doc, const xmlNodePtr node)
+{
+ xmlNodePtr cur = node->xmlChildrenNode;
+ xmlChar* key;
+
+ PresetModel* pm = new PresetModel(patch->base_path());
+
+ while (cur != NULL) {
+ key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+
+ if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) {
+ assert(key != NULL);
+ pm->name((char*)key);
+ } else if ((!xmlStrcmp(cur->name, (const xmlChar*)"control"))) {
+ xmlNodePtr child = cur->xmlChildrenNode;
+
+ string node_name = "", port_name = "";
+ float val = 0.0;
+
+ while (child != NULL) {
+ key = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
+
+ if ((!xmlStrcmp(child->name, (const xmlChar*)"node-name"))) {
+ node_name = (char*)key;
+ } else if ((!xmlStrcmp(child->name, (const xmlChar*)"port-name"))) {
+ port_name = (char*)key;
+ } else if ((!xmlStrcmp(child->name, (const xmlChar*)"value"))) {
+ val = atof((char*)key);
+ }
+
+ xmlFree(key);
+ key = NULL; // Avoid a (possible?) double free
+
+ child = child->next;
+ }
+
+ if (port_name == "") {
+ string msg = "Unable to parse control in patch file ( node = ";
+ msg.append(node_name).append(", port = ").append(port_name).append(")");
+ m_client_hooks->error(msg);
+ } else {
+ // FIXME: temporary compatibility, remove any slashes from port name
+ // remove this soon once patches have migrated
+ string::size_type slash_index;
+ while ((slash_index = port_name.find("/")) != string::npos)
+ port_name[slash_index] = '-';
+ pm->add_control(node_name, port_name, val);
+ }
+ }
+ xmlFree(key);
+ key = NULL;
+ cur = cur->next;
+ }
+ if (pm->name() == "") {
+ m_client_hooks->error("Preset in patch file has no name.");
+ pm->name("Unnamed");
+ }
+
+ return pm;
+}
+#endif
+
+
+} // namespace LibOmClient
diff --git a/src/clients/new/PatchLibrarian.h b/src/clients/new/PatchLibrarian.h
new file mode 100644
index 00000000..ac69f0f5
--- /dev/null
+++ b/src/clients/new/PatchLibrarian.h
@@ -0,0 +1,66 @@
+/* This file is part of Om. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om 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.
+ *
+ * Om 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.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PATCHLIBRARIAN_H
+#define PATCHLIBRARIAN_H
+
+#include <string>
+#include <libxml/tree.h>
+#include "util/Path.h"
+#include "EngineInterface.h"
+using std::string;
+using Om::Path;
+using Om::Shared::EngineInterface;
+
+namespace LibOmClient {
+
+
+/** Loads patch files, sending the necessary messages to an EngineInterface
+ * to recreate the patch.
+ *
+ * Because this only uses EngineInterface, this same code can be used to load
+ * patches client side or server side.
+ *
+ * \ingroup libomclient
+ */
+class PatchLibrarian
+{
+public:
+
+ //static void save_patch(PatchModel* patch_model, const string& filename, bool recursive);
+
+ static bool
+ PatchLibrarian::load_patch(EngineInterface* engine,
+ const string& filename,
+ const Path& parent_path = "/",
+ string name = "",
+ uint32_t poly = 0);
+
+private:
+ PatchLibrarian() {}
+
+ /*
+ static NodeModel* parse_node(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur);
+ static ConnectionModel* parse_connection(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur);
+ static PresetModel* parse_preset(const PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur);
+ static void load_subpatch(PatchModel* parent, xmlDocPtr doc, const xmlNodePtr cur);
+ */
+};
+
+
+} // namespace LibOmClient
+
+#endif // PATCHLIBRARIAN_H
diff --git a/src/clients/new/patch_loader/.deps/cmdline.Po b/src/clients/new/patch_loader/.deps/cmdline.Po
new file mode 100644
index 00000000..6092089f
--- /dev/null
+++ b/src/clients/new/patch_loader/.deps/cmdline.Po
@@ -0,0 +1,53 @@
+cmdline.o cmdline.o: cmdline.c /usr/include/stdio.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/gnu/stubs.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/include/stddef.h \
+ /usr/include/bits/types.h /usr/include/bits/wordsize.h \
+ /usr/include/bits/typesizes.h /usr/include/libio.h \
+ /usr/include/_G_config.h /usr/include/wchar.h /usr/include/bits/wchar.h \
+ /usr/include/gconv.h /usr/lib/gcc/i486-linux-gnu/4.0.4/include/stdarg.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/stdlib.h /usr/include/string.h ../../../config.h \
+ /usr/include/getopt.h cmdline.h
+
+/usr/include/stdio.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/include/stddef.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/libio.h:
+
+/usr/include/_G_config.h:
+
+/usr/include/wchar.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/gconv.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/include/stdarg.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/string.h:
+
+../../../config.h:
+
+/usr/include/getopt.h:
+
+cmdline.h:
diff --git a/src/clients/new/patch_loader/.deps/om_patch_loader-patch_loader.Po b/src/clients/new/patch_loader/.deps/om_patch_loader-patch_loader.Po
new file mode 100644
index 00000000..1388e6d6
--- /dev/null
+++ b/src/clients/new/patch_loader/.deps/om_patch_loader-patch_loader.Po
@@ -0,0 +1,518 @@
+om_patch_loader-patch_loader.o om_patch_loader-patch_loader.o: \
+ patch_loader.cpp \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/iostream \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/c++config.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/os_defines.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/gnu/stubs.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/ostream \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/ios \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/iosfwd \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/c++locale.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cstring \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cstddef \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/include/stddef.h \
+ /usr/include/string.h /usr/include/xlocale.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cstdio \
+ /usr/include/stdio.h /usr/include/bits/types.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h \
+ /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
+ /usr/include/bits/wchar.h /usr/include/gconv.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/include/stdarg.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/clocale \
+ /usr/include/locale.h /usr/include/bits/locale.h \
+ /usr/include/langinfo.h /usr/include/nl_types.h /usr/include/iconv.h \
+ /usr/include/libintl.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/c++io.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/gthr.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/gthr-default.h \
+ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \
+ /usr/include/bits/sched.h /usr/include/bits/time.h \
+ /usr/include/signal.h /usr/include/bits/sigset.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/initspin.h \
+ /usr/include/bits/sigthread.h /usr/include/unistd.h \
+ /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
+ /usr/include/bits/confname.h /usr/include/getopt.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cctype \
+ /usr/include/ctype.h /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stringfwd.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/postypes.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cwchar \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/ctime \
+ /usr/include/stdint.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/functexcept.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/exception_defines.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/exception \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/char_traits.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_algobase.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/climits \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/include/limits.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/include/syslimits.h \
+ /usr/include/limits.h /usr/include/bits/posix1_lim.h \
+ /usr/include/bits/local_lim.h /usr/include/linux/limits.h \
+ /usr/include/bits/posix2_lim.h /usr/include/bits/xopen_lim.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cstdlib \
+ /usr/include/stdlib.h /usr/include/bits/waitflags.h \
+ /usr/include/bits/waitstatus.h /usr/include/sys/types.h \
+ /usr/include/sys/select.h /usr/include/bits/select.h \
+ /usr/include/sys/sysmacros.h /usr/include/alloca.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_pair.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/cpp_type_traits.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_iterator_base_types.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_iterator_base_funcs.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/concept_check.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_iterator.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/debug/debug.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cassert \
+ /usr/include/assert.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/localefwd.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/ios_base.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/atomicity.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/atomic_word.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/locale_classes.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/string \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/memory \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/allocator.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/c++allocator.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/ext/new_allocator.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/new \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_construct.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_uninitialized.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_raw_storage_iter.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/limits \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_function.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/basic_string.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/algorithm \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_algo.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_heap.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_tempbuf.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/basic_string.tcc \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/streambuf \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/streambuf.tcc \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/basic_ios.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/streambuf_iterator.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/locale_facets.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cwctype \
+ /usr/include/wctype.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/ctype_base.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/ctype_inline.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/codecvt.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/time_members.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/messages_members.h \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/basic_ios.tcc \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/ostream.tcc \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/locale \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/locale_facets.tcc \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/typeinfo \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/istream \
+ /usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/istream.tcc \
+ cmdline.h ../../../config.h ../../../src/common/util/Path.h \
+ ../../../src/clients/OSCEngineInterface.h /usr/include/inttypes.h \
+ /usr/local/include/lo/lo.h /usr/local/include/lo/lo_endian.h \
+ /usr/include/netinet/in.h /usr/include/sys/socket.h \
+ /usr/include/sys/uio.h /usr/include/bits/uio.h \
+ /usr/include/bits/socket.h /usr/include/bits/sockaddr.h \
+ /usr/include/asm/socket.h /usr/include/asm-i486/socket.h \
+ /usr/include/asm/sockios.h /usr/include/asm-i486/sockios.h \
+ /usr/include/bits/in.h /usr/include/bits/byteswap.h \
+ /usr/local/include/lo/lo_types.h /usr/include/netdb.h \
+ /usr/include/rpc/netdb.h /usr/include/bits/siginfo.h \
+ /usr/include/bits/netdb.h /usr/local/include/lo/lo_osc_types.h \
+ /usr/local/include/lo/lo_errors.h /usr/local/include/lo/lo_lowlevel.h \
+ /usr/local/include/lo/lo_macros.h \
+ ../../../src/common/interface/EngineInterface.h \
+ ../../../src/clients/PatchLibrarian.h \
+ /usr/include/libxml2/libxml/tree.h \
+ /usr/include/libxml2/libxml/xmlversion.h \
+ /usr/include/libxml2/libxml/xmlexports.h \
+ /usr/include/libxml2/libxml/xmlstring.h \
+ /usr/include/libxml2/libxml/xmlregexp.h \
+ /usr/include/libxml2/libxml/dict.h \
+ /usr/include/libxml2/libxml/xmlmemory.h \
+ /usr/include/libxml2/libxml/threads.h \
+ /usr/include/libxml2/libxml/globals.h \
+ /usr/include/libxml2/libxml/parser.h /usr/include/libxml2/libxml/hash.h \
+ /usr/include/libxml2/libxml/valid.h \
+ /usr/include/libxml2/libxml/xmlerror.h \
+ /usr/include/libxml2/libxml/list.h \
+ /usr/include/libxml2/libxml/xmlautomata.h \
+ /usr/include/libxml2/libxml/entities.h \
+ /usr/include/libxml2/libxml/encoding.h \
+ /usr/include/libxml2/libxml/xmlIO.h /usr/include/libxml2/libxml/SAX.h \
+ /usr/include/libxml2/libxml/xlink.h /usr/include/libxml2/libxml/SAX2.h \
+ ../../../src/common/util/Path.h
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/iostream:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/c++config.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/os_defines.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/ostream:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/ios:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/iosfwd:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/c++locale.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cstring:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cstddef:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/include/stddef.h:
+
+/usr/include/string.h:
+
+/usr/include/xlocale.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cstdio:
+
+/usr/include/stdio.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/libio.h:
+
+/usr/include/_G_config.h:
+
+/usr/include/wchar.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/gconv.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/include/stdarg.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/clocale:
+
+/usr/include/locale.h:
+
+/usr/include/bits/locale.h:
+
+/usr/include/langinfo.h:
+
+/usr/include/nl_types.h:
+
+/usr/include/iconv.h:
+
+/usr/include/libintl.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/c++io.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/gthr.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/gthr-default.h:
+
+/usr/include/pthread.h:
+
+/usr/include/sched.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/signal.h:
+
+/usr/include/bits/sigset.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/initspin.h:
+
+/usr/include/bits/sigthread.h:
+
+/usr/include/unistd.h:
+
+/usr/include/bits/posix_opt.h:
+
+/usr/include/bits/environments.h:
+
+/usr/include/bits/confname.h:
+
+/usr/include/getopt.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cctype:
+
+/usr/include/ctype.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stringfwd.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/postypes.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cwchar:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/ctime:
+
+/usr/include/stdint.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/functexcept.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/exception_defines.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/exception:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/char_traits.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_algobase.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/climits:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/include/limits.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/include/syslimits.h:
+
+/usr/include/limits.h:
+
+/usr/include/bits/posix1_lim.h:
+
+/usr/include/bits/local_lim.h:
+
+/usr/include/linux/limits.h:
+
+/usr/include/bits/posix2_lim.h:
+
+/usr/include/bits/xopen_lim.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cstdlib:
+
+/usr/include/stdlib.h:
+
+/usr/include/bits/waitflags.h:
+
+/usr/include/bits/waitstatus.h:
+
+/usr/include/sys/types.h:
+
+/usr/include/sys/select.h:
+
+/usr/include/bits/select.h:
+
+/usr/include/sys/sysmacros.h:
+
+/usr/include/alloca.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_pair.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/cpp_type_traits.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_iterator_base_types.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_iterator_base_funcs.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/concept_check.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_iterator.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/debug/debug.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cassert:
+
+/usr/include/assert.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/localefwd.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/ios_base.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/atomicity.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/atomic_word.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/locale_classes.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/string:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/memory:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/allocator.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/c++allocator.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/ext/new_allocator.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/new:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_construct.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_uninitialized.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_raw_storage_iter.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/limits:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_function.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/basic_string.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/algorithm:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_algo.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_heap.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/stl_tempbuf.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/basic_string.tcc:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/streambuf:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/streambuf.tcc:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/basic_ios.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/streambuf_iterator.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/locale_facets.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/cwctype:
+
+/usr/include/wctype.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/ctype_base.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/ctype_inline.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/codecvt.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/time_members.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/i486-linux-gnu/bits/messages_members.h:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/basic_ios.tcc:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/ostream.tcc:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/locale:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/locale_facets.tcc:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/typeinfo:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/istream:
+
+/usr/lib/gcc/i486-linux-gnu/4.0.4/../../../../include/c++/4.0.4/bits/istream.tcc:
+
+cmdline.h:
+
+../../../config.h:
+
+../../../src/common/util/Path.h:
+
+../../../src/clients/OSCEngineInterface.h:
+
+/usr/include/inttypes.h:
+
+/usr/local/include/lo/lo.h:
+
+/usr/local/include/lo/lo_endian.h:
+
+/usr/include/netinet/in.h:
+
+/usr/include/sys/socket.h:
+
+/usr/include/sys/uio.h:
+
+/usr/include/bits/uio.h:
+
+/usr/include/bits/socket.h:
+
+/usr/include/bits/sockaddr.h:
+
+/usr/include/asm/socket.h:
+
+/usr/include/asm-i486/socket.h:
+
+/usr/include/asm/sockios.h:
+
+/usr/include/asm-i486/sockios.h:
+
+/usr/include/bits/in.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/local/include/lo/lo_types.h:
+
+/usr/include/netdb.h:
+
+/usr/include/rpc/netdb.h:
+
+/usr/include/bits/siginfo.h:
+
+/usr/include/bits/netdb.h:
+
+/usr/local/include/lo/lo_osc_types.h:
+
+/usr/local/include/lo/lo_errors.h:
+
+/usr/local/include/lo/lo_lowlevel.h:
+
+/usr/local/include/lo/lo_macros.h:
+
+../../../src/common/interface/EngineInterface.h:
+
+../../../src/clients/PatchLibrarian.h:
+
+/usr/include/libxml2/libxml/tree.h:
+
+/usr/include/libxml2/libxml/xmlversion.h:
+
+/usr/include/libxml2/libxml/xmlexports.h:
+
+/usr/include/libxml2/libxml/xmlstring.h:
+
+/usr/include/libxml2/libxml/xmlregexp.h:
+
+/usr/include/libxml2/libxml/dict.h:
+
+/usr/include/libxml2/libxml/xmlmemory.h:
+
+/usr/include/libxml2/libxml/threads.h:
+
+/usr/include/libxml2/libxml/globals.h:
+
+/usr/include/libxml2/libxml/parser.h:
+
+/usr/include/libxml2/libxml/hash.h:
+
+/usr/include/libxml2/libxml/valid.h:
+
+/usr/include/libxml2/libxml/xmlerror.h:
+
+/usr/include/libxml2/libxml/list.h:
+
+/usr/include/libxml2/libxml/xmlautomata.h:
+
+/usr/include/libxml2/libxml/entities.h:
+
+/usr/include/libxml2/libxml/encoding.h:
+
+/usr/include/libxml2/libxml/xmlIO.h:
+
+/usr/include/libxml2/libxml/SAX.h:
+
+/usr/include/libxml2/libxml/xlink.h:
+
+/usr/include/libxml2/libxml/SAX2.h:
+
+../../../src/common/util/Path.h:
diff --git a/src/clients/new/patch_loader/Makefile.am b/src/clients/new/patch_loader/Makefile.am
new file mode 100644
index 00000000..1448ac92
--- /dev/null
+++ b/src/clients/new/patch_loader/Makefile.am
@@ -0,0 +1,13 @@
+EXTRA_DIST = README
+
+om_patch_loader_CXXFLAGS = -I$(top_srcdir)/src/clients -I$(top_srcdir)/src/common/util -I$(top_srcdir)/src/common/interface -DPKGDATADIR=\"$(pkgdatadir)\" $(LXML2_CFLAGS) $(LOSC_CFLAGS)
+om_patch_loader_LDADD = ../libomclient.a $(LOSC_LIBS) $(LXML2_LIBS)
+
+bin_PROGRAMS = om_patch_loader
+
+om_patch_loader_DEPENDENCIES = ../libomclient.a
+
+om_patch_loader_SOURCES = \
+ patch_loader.cpp \
+ cmdline.h \
+ cmdline.c
diff --git a/src/clients/new/patch_loader/README b/src/clients/new/patch_loader/README
new file mode 100644
index 00000000..9f3b6f4b
--- /dev/null
+++ b/src/clients/new/patch_loader/README
@@ -0,0 +1,5 @@
+This is a stand-alone patch loader for Om. It has no user interface, it
+just launches, loads the patch(es) passed as a parameter, and exits.
+
+Useful for loading patches from scripts, other apps, etc. or just using
+Om patches without loading the GUI.
diff --git a/src/clients/new/patch_loader/cmdline.c b/src/clients/new/patch_loader/cmdline.c
new file mode 100644
index 00000000..0606cb7b
--- /dev/null
+++ b/src/clients/new/patch_loader/cmdline.c
@@ -0,0 +1,163 @@
+/*
+ File autogenerated by gengetopt version 2.10
+ generated with the following command:
+ gengetopt -u
+
+ The developers of gengetopt consider the fixed text that goes in all
+ gengetopt output files to be in the public domain:
+ we make no copyright claims on it.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* If we use autoconf. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "getopt.h"
+
+#include "cmdline.h"
+
+void
+cmdline_parser_print_version (void)
+{
+ printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION);
+}
+
+void
+cmdline_parser_print_help (void)
+{
+ cmdline_parser_print_version ();
+ printf("\n"
+ "Usage: %s [OPTIONS]... [FILES]...\n", CMDLINE_PARSER_PACKAGE);
+ printf(" -h --help Print help and exit\n");
+ printf(" -V --version Print version and exit\n");
+ printf(" -uSTRING --engine-url=STRING Om engine URL to connect to\n");
+ printf(" -pINT --client-port=INT Client port to listen on\n");
+}
+
+
+static char *gengetopt_strdup (const char *s);
+
+/* gengetopt_strdup() */
+/* strdup.c replacement of strdup, which is not standard */
+char *
+gengetopt_strdup (const char *s)
+{
+ char *result = (char*)malloc(strlen(s) + 1);
+ if (result == (char*)0)
+ return (char*)0;
+ strcpy(result, s);
+ return result;
+}
+
+int
+cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info)
+{
+ int c; /* Character of the parsed option. */
+ int missing_required_options = 0;
+
+ args_info->help_given = 0 ;
+ args_info->version_given = 0 ;
+ args_info->engine_url_given = 0 ;
+ args_info->client_port_given = 0 ;
+#define clear_args() { \
+ args_info->engine_url_arg = NULL; \
+}
+
+ clear_args();
+
+ args_info->inputs = NULL;
+ args_info->inputs_num = 0;
+
+ optarg = 0;
+ optind = 1;
+ opterr = 1;
+ optopt = '?';
+
+ while (1)
+ {
+ int option_index = 0;
+ char *stop_char;
+
+ static struct option long_options[] = {
+ { "help", 0, NULL, 'h' },
+ { "version", 0, NULL, 'V' },
+ { "engine-url", 1, NULL, 'u' },
+ { "client-port", 1, NULL, 'p' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ stop_char = 0;
+ c = getopt_long (argc, argv, "hVu:p:", long_options, &option_index);
+
+ if (c == -1) break; /* Exit from `while (1)' loop. */
+
+ switch (c)
+ {
+ case 'h': /* Print help and exit. */
+ clear_args ();
+ cmdline_parser_print_help ();
+ exit (EXIT_SUCCESS);
+
+ case 'V': /* Print version and exit. */
+ clear_args ();
+ cmdline_parser_print_version ();
+ exit (EXIT_SUCCESS);
+
+ case 'u': /* Om engine URL to connect to. */
+ if (args_info->engine_url_given)
+ {
+ fprintf (stderr, "%s: `--engine-url' (`-u') option given more than once\n", CMDLINE_PARSER_PACKAGE);
+ clear_args ();
+ exit (EXIT_FAILURE);
+ }
+ args_info->engine_url_given = 1;
+ args_info->engine_url_arg = gengetopt_strdup (optarg);
+ break;
+
+ case 'p': /* Client port to listen on. */
+ if (args_info->client_port_given)
+ {
+ fprintf (stderr, "%s: `--client-port' (`-p') option given more than once\n", CMDLINE_PARSER_PACKAGE);
+ clear_args ();
+ exit (EXIT_FAILURE);
+ }
+ args_info->client_port_given = 1;
+ args_info->client_port_arg = strtol (optarg,&stop_char,0);
+ break;
+
+
+ case 0: /* Long option with no short option */
+
+ case '?': /* Invalid option. */
+ /* `getopt_long' already printed an error message. */
+ exit (EXIT_FAILURE);
+
+ default: /* bug: option not considered. */
+ fprintf (stderr, "%s: option unknown: %c\n", CMDLINE_PARSER_PACKAGE, c);
+ abort ();
+ } /* switch */
+ } /* while */
+
+
+ if ( missing_required_options )
+ exit (EXIT_FAILURE);
+
+ if (optind < argc)
+ {
+ int i = 0 ;
+
+ args_info->inputs_num = argc - optind ;
+ args_info->inputs =
+ (char **)(malloc ((args_info->inputs_num)*sizeof(char *))) ;
+ while (optind < argc)
+ args_info->inputs[ i++ ] = gengetopt_strdup (argv[optind++]) ;
+ }
+
+ return 0;
+}
diff --git a/src/clients/new/patch_loader/cmdline.ggo b/src/clients/new/patch_loader/cmdline.ggo
new file mode 100644
index 00000000..5acd6737
--- /dev/null
+++ b/src/clients/new/patch_loader/cmdline.ggo
@@ -0,0 +1,7 @@
+# Process this file with gengetopt -u to generate the necessary code (in cmdline.h, cmdline.c)
+
+package "om_patch_loader - A command line patch loading client for Om"
+
+option "engine-url" u "Om engine URL to connect to" string no
+option "client-port" p "Client port to listen on" int no
+
diff --git a/src/clients/new/patch_loader/cmdline.h b/src/clients/new/patch_loader/cmdline.h
new file mode 100644
index 00000000..b417c664
--- /dev/null
+++ b/src/clients/new/patch_loader/cmdline.h
@@ -0,0 +1,47 @@
+/* cmdline.h */
+
+/* File autogenerated by gengetopt version 2.10 */
+
+#ifndef CMDLINE_H
+#define CMDLINE_H
+
+/* If we use autoconf. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef CMDLINE_PARSER_PACKAGE
+#define CMDLINE_PARSER_PACKAGE "om_patch_loader - A command line patch loading client for the Om realtime modular synthesizer"
+#endif
+
+#ifndef CMDLINE_PARSER_VERSION
+#define CMDLINE_PARSER_VERSION VERSION
+#endif
+
+struct gengetopt_args_info
+{
+ char * engine_url_arg; /* Om engine URL to connect to. */
+ int client_port_arg; /* Client port to listen on. */
+
+ int help_given ; /* Whether help was given. */
+ int version_given ; /* Whether version was given. */
+ int engine_url_given ; /* Whether engine-url was given. */
+ int client_port_given ; /* Whether client-port was given. */
+
+ char **inputs ; /* unamed options */
+ unsigned inputs_num ; /* unamed options number */
+} ;
+
+int cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info);
+
+void cmdline_parser_print_help(void);
+void cmdline_parser_print_version(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* CMDLINE_H */
diff --git a/src/clients/new/patch_loader/om_patch_loader b/src/clients/new/patch_loader/om_patch_loader
new file mode 100755
index 00000000..8624109f
--- /dev/null
+++ b/src/clients/new/patch_loader/om_patch_loader
Binary files differ
diff --git a/src/clients/new/patch_loader/patch_loader.cpp b/src/clients/new/patch_loader/patch_loader.cpp
new file mode 100644
index 00000000..8884e85b
--- /dev/null
+++ b/src/clients/new/patch_loader/patch_loader.cpp
@@ -0,0 +1,76 @@
+/* This file is part of Om. Copyright (C) 2005 Dave Robillard.
+ *
+ * Om 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.
+ *
+ * Om 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.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <iostream>
+#include <unistd.h>
+#include "cmdline.h" // generated by gengetopt
+#include "util/Path.h"
+#include "OSCEngineInterface.h"
+#include "PatchLibrarian.h"
+
+using std::cout; using std::cerr; using std::endl;
+using Om::Path;
+
+using namespace LibOmClient;
+
+
+int
+main(int argc, char** argv)
+{
+ const char* engine_url = NULL;
+ int client_port = 0;
+
+ /* Parse command line options */
+ gengetopt_args_info args_info;
+ if (cmdline_parser (argc, argv, &args_info) != 0)
+ return 1;
+
+ if (args_info.engine_url_given) {
+ engine_url = args_info.engine_url_arg;
+ } else {
+ cout << "[Main] No engine URL specified. Attempting to use osc.udp://localhost:16180" << endl;
+ engine_url = "osc.udp://localhost:16180";
+ }
+
+ if (args_info.client_port_given)
+ client_port = args_info.client_port_arg;
+ else
+ client_port = 0; // will choose a free port automatically
+
+ OSCEngineInterface engine(engine_url);
+
+ /* Connect to engine */
+ if (!engine.attach()) {
+ cerr << "Unable to connect to engine" << endl;
+ return 1;
+ }
+
+ engine.activate();
+ engine.register_client();
+
+ /*int id = engine.get_next_request_id();
+ engine.set_wait_response_id(id);
+ engine.load_plugins(id);
+ engine.wait_for_response();
+ */
+ engine.load_plugins();
+
+ // Load patches
+ for (uint i=0; i < args_info.inputs_num; ++i)
+ PatchLibrarian::load_patch(&engine, args_info.inputs[i]);
+
+ return 0;
+}