summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2006-09-30 06:47:00 +0000
committerDavid Robillard <d@drobilla.net>2006-09-30 06:47:00 +0000
commit35a5d92cfcf6815553a0939c3e2bf77c1108fd31 (patch)
tree456351b4b18d48aba25a2db7218df9be09d4047e /src
parentd82dcd232f201b531a0be165ee44aede1bc8a1df (diff)
downloadingen-35a5d92cfcf6815553a0939c3e2bf77c1108fd31.tar.gz
ingen-35a5d92cfcf6815553a0939c3e2bf77c1108fd31.tar.bz2
ingen-35a5d92cfcf6815553a0939c3e2bf77c1108fd31.zip
Work on RDF serialization (only (partial) saving so far).
git-svn-id: http://svn.drobilla.net/lad/ingen@146 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r--src/common/util/Atom.h12
-rw-r--r--src/common/util/LibloAtom.h2
-rw-r--r--src/common/util/Makefile.am3
-rw-r--r--src/common/util/Path.h28
-rw-r--r--src/common/util/RedlandAtom.h77
-rw-r--r--src/libs/client/ConnectionModel.cpp2
-rw-r--r--src/libs/client/ConnectionModel.h2
-rw-r--r--src/libs/client/DeprecatedSerializer.cpp (renamed from src/libs/client/PatchLibrarian.cpp)280
-rw-r--r--src/libs/client/DeprecatedSerializer.h (renamed from src/libs/client/PatchLibrarian.h)8
-rw-r--r--src/libs/client/Makefile.am13
-rw-r--r--src/libs/client/ObjectModel.h5
-rw-r--r--src/libs/client/PatchModel.h14
-rw-r--r--src/libs/client/Serializer.cpp525
-rw-r--r--src/libs/client/Serializer.h118
-rw-r--r--src/libs/engine/Makefile.am2
-rw-r--r--src/progs/demolition/Makefile.am4
-rw-r--r--src/progs/demolition/demolition.cpp8
-rw-r--r--src/progs/ingenuity/Loader.cpp42
-rw-r--r--src/progs/ingenuity/Loader.h16
-rw-r--r--src/progs/ingenuity/Makefile.am11
-rw-r--r--src/progs/ingenuity/NodeModule.cpp12
-rw-r--r--src/progs/ingenuity/PatchCanvas.cpp8
-rw-r--r--src/progs/ingenuity/PatchPortModule.cpp16
-rw-r--r--src/progs/patch_loader/Makefile.am10
-rw-r--r--src/progs/patch_loader/patch_loader.cpp6
25 files changed, 865 insertions, 359 deletions
diff --git a/src/common/util/Atom.h b/src/common/util/Atom.h
index f28b9339..2a6ae982 100644
--- a/src/common/util/Atom.h
+++ b/src/common/util/Atom.h
@@ -20,6 +20,9 @@
#include <cstdlib>
#include <cassert>
#include <cstring>
+#include <string>
+
+using std::string;
/** An OSC atom (fundamental data types OSC messages are composed of).
@@ -34,10 +37,11 @@ public:
BLOB
};
- Atom() : _type(NIL), _blob_val(0) {}
- Atom(int32_t val) : _type(INT), _int_val(val) {}
- Atom(float val) : _type(FLOAT), _float_val(val) {}
- Atom(const char* val) : _type(STRING), _string_val(strdup(val)) {}
+ Atom() : _type(NIL), _blob_val(0) {}
+ Atom(int32_t val) : _type(INT), _int_val(val) {}
+ Atom(float val) : _type(FLOAT), _float_val(val) {}
+ Atom(const char* val) : _type(STRING), _string_val(strdup(val)) {}
+ Atom(const string& val) : _type(STRING), _string_val(strdup(val.c_str())) {}
Atom(void* val) : _type(BLOB), _blob_size(sizeof(val)), _blob_val(malloc(_blob_size))
{ memcpy(_blob_val, val, sizeof(_blob_size)); }
diff --git a/src/common/util/LibloAtom.h b/src/common/util/LibloAtom.h
index 02a469fe..db76a807 100644
--- a/src/common/util/LibloAtom.h
+++ b/src/common/util/LibloAtom.h
@@ -23,7 +23,7 @@
/** Support for serializing an Atom to/from liblo messages.
*
- * (Here to prevent a unnecessary liblo dependency on Atom).
+ * (Here to prevent a unnecessary liblo dependency for Atom).
*/
class LibloAtom {
public:
diff --git a/src/common/util/Makefile.am b/src/common/util/Makefile.am
index 845a5d9a..6bddb707 100644
--- a/src/common/util/Makefile.am
+++ b/src/common/util/Makefile.am
@@ -8,4 +8,5 @@ EXTRA_DIST = \
Thread.h \
Slave.h \
Atom.h \
- LibloAtom.h
+ LibloAtom.h \
+ RedlandAtom.h
diff --git a/src/common/util/Path.h b/src/common/util/Path.h
index 2fcf5774..bcb047ad 100644
--- a/src/common/util/Path.h
+++ b/src/common/util/Path.h
@@ -17,6 +17,7 @@
#ifndef PATH_H
#define PATH_H
+#include <cctype>
#include <string>
#include <cassert>
using std::string;
@@ -137,7 +138,7 @@ public:
/** Convert a string to a valid name (or "method" - tokens between slashes)
*
- * This will strip all slashes and always return a valid name/method.
+ * This will strip all slashes, etc, and always return a valid name/method.
*/
static string nameify(const std::basic_string<char>& str)
{
@@ -155,18 +156,22 @@ public:
/** Replace any invalid characters in @a str with a suitable replacement.
+ *
+ * Makes a pretty name - underscores are a valid character, but this chops
+ * both spaces and underscores, uppercasing the next letter, to create
+ * uniform CamelCase names that look nice
*/
static void replace_invalid_chars(string& str, bool replace_slash = false)
{
for (size_t i=0; i < str.length(); ++i) {
- if (str[i] == ' ') {
- str[i] = '_';
+ if (str[i] == ' ' || str[i] == '_') {
+ str[i+1] = std::toupper(str[i+1]); // capitalize next char
+ str = str.substr(0, i) + str.substr(i+1); // chop space/underscore
} else if (str[i] == '[' || str[i] == '{') {
str[i] = '(';
} else if (str[i] == ']' || str[i] == '}') {
str[i] = ')';
} else if (str[i] < 32 || str.at(i) > 126
- || str[i] == ' '
|| str[i] == '#'
|| str[i] == '*'
|| str[i] == ','
@@ -175,6 +180,21 @@ public:
str[i] = '.';
}
}
+
+ // Chop brackets
+ while (true) {
+
+ const string::size_type open = str.find("(");
+ const string::size_type close = str.find(")");
+
+ if (open != string::npos) {
+ if (close != string::npos)
+ str.erase(open, (close - open) + 1);
+ } else {
+ break;
+ }
+
+ }
}
diff --git a/src/common/util/RedlandAtom.h b/src/common/util/RedlandAtom.h
new file mode 100644
index 00000000..6b5658cf
--- /dev/null
+++ b/src/common/util/RedlandAtom.h
@@ -0,0 +1,77 @@
+/* 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 REDLAND_ATOM_H
+#define REDLAND_ATOM_H
+
+#include <redland.h>
+#include "util/Atom.h"
+
+#define U(x) ((const unsigned char*)(x))
+
+/** Support for serializing an Atom to/from RDF (via redland aka librdf).
+ *
+ * (Here to prevent a unnecessary redland dependency for Atom).
+ */
+class RedlandAtom {
+public:
+ static librdf_node* atom_to_node(librdf_world* world, const Atom& atom) {
+ char tmp_buf[32];
+
+ switch (atom.type()) {
+ //case NIL:
+ // (see below)
+ //break;
+ case Atom::INT:
+ snprintf(tmp_buf, 32, "%d", atom.get_int32());
+ return librdf_new_node_from_typed_literal(world, U(tmp_buf), NULL, librdf_new_uri(world, U("http://www.w3.org/2001/XMLSchema#integer")));
+ break;
+ case Atom::FLOAT:
+ snprintf(tmp_buf, 32, "%f", atom.get_float());
+ return librdf_new_node_from_typed_literal(world, U(tmp_buf), NULL, librdf_new_uri(world, U("http://www.w3.org/2001/XMLSchema#float")));
+ break;
+ case Atom::STRING:
+ return librdf_new_node_from_literal(world, U(atom.get_string()), NULL, 0);
+ case Atom::BLOB:
+ cerr << "WARNING: Unserializable atom!" << endl;
+ return NULL;
+ default: // This catches Atom::Type::NIL too
+ return librdf_new_node(world); // blank node
+ }
+ }
+
+ static Atom node_to_atom(librdf_node* node) {
+ /*switch (type) {
+ case 'i':
+ return Atom(arg->i);
+ case 'f':
+ return Atom(arg->f);
+ case 's':
+ return Atom(&arg->s);
+ //case 'b'
+ // FIXME: How to get a blob from a lo_arg?
+ //return Atom(arg->b);
+ default:
+ return Atom();
+ }*/
+ cerr << "FIXME: node_to_atom\n";
+ return Atom();
+ }
+
+};
+
+
+#endif // REDLAND_ATOM_H
diff --git a/src/libs/client/ConnectionModel.cpp b/src/libs/client/ConnectionModel.cpp
index e120207d..e7f66077 100644
--- a/src/libs/client/ConnectionModel.cpp
+++ b/src/libs/client/ConnectionModel.cpp
@@ -101,6 +101,8 @@ ConnectionModel::patch_path() const
return patch_path;
}
+typedef list<CountedPtr<ConnectionModel> > ConnectionList;
+
} // namespace Client
} // namespace Ingen
diff --git a/src/libs/client/ConnectionModel.h b/src/libs/client/ConnectionModel.h
index 4c0d18f8..e1530f88 100644
--- a/src/libs/client/ConnectionModel.h
+++ b/src/libs/client/ConnectionModel.h
@@ -68,6 +68,8 @@ private:
CountedPtr<PortModel> _dst_port;
};
+typedef list<CountedPtr<ConnectionModel> > ConnectionList;
+
} // namespace Client
} // namespace Ingen
diff --git a/src/libs/client/PatchLibrarian.cpp b/src/libs/client/DeprecatedSerializer.cpp
index 00687993..1526c527 100644
--- a/src/libs/client/PatchLibrarian.cpp
+++ b/src/libs/client/DeprecatedSerializer.cpp
@@ -14,7 +14,7 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "PatchLibrarian.h"
+#include "DeprecatedSerializer.h"
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
@@ -56,7 +56,7 @@ namespace Client {
* 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)
+DeprecatedSerializer::find_file(const string& filename, const string& additional_path)
{
string search_path = additional_path + ":" + _patch_search_path;
@@ -86,7 +86,7 @@ PatchLibrarian::find_file(const string& filename, const string& additional_path)
is.close();
return full_patch_path;
} else {
- cerr << "[PatchLibrarian] Could not find patch file " << full_patch_path << endl;
+ cerr << "[DeprecatedSerializer] Could not find patch file " << full_patch_path << endl;
}
}
@@ -95,7 +95,7 @@ PatchLibrarian::find_file(const string& filename, const string& additional_path)
string
-PatchLibrarian::translate_load_path(const string& path)
+DeprecatedSerializer::translate_load_path(const string& path)
{
std::map<string,string>::iterator t = _load_path_translations.find(path);
@@ -108,262 +108,6 @@ PatchLibrarian::translate_load_path(const string& path)
}
-/** 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 (Ingen) path
- */
-#if 0
-void
-PatchLibrarian::save_patch(CountedPtr<PatchModel> patch_model, const string& filename, bool recursive)
-{
- assert(filename != "");
- assert(patch_model->path() != "");
-
- cout << "Saving patch " << patch_model->path() << " to " << filename << endl;
-
- if (patch_model->filename() != filename)
- cerr << "Warning: Saving patch to file other than filename stored in model." << endl;
-
- string dir = filename.substr(0, filename.find_last_of("/"));
-
- NodeModel* nm = NULL;
-
- 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->path().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 (MetadataMap::const_iterator i = patch_model->metadata().begin();
- i != patch_model->metadata().end(); ++i) {
- cerr << "FIXME: metadata save" << endl;
- // 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.get();
-
- if (nm->plugin()->type() == PluginModel::Patch) { // Subpatch
- CountedPtr<PatchModel> spm = PtrCast<PatchModel>(i->second);
- assert(spm);
-
- xml_node = xmlNewChild(xml_root_node, NULL, (xmlChar*)"subpatch", NULL);
-
- xml_child_node = xmlNewChild(xml_node, NULL, (xmlChar*)"name", (xmlChar*)spm->path().name().c_str());
-
- string ref_filename;
- // No path
- if (spm->filename() == "") {
- ref_filename = spm->path().name() + ".om";
- cerr << "FIXME: subpatch filename" << endl;
- //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);
- cerr << "FIXME: subpatch filename (2)" << endl;
- //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 (MetadataMap::const_iterator i = nm->metadata().begin();
- i != nm->metadata().end(); ++i) {
- cerr << "FIXME: save metadata\n";
- // 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->path().name().c_str());
-
- if (!nm->plugin()) 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 (MetadataMap::const_iterator i = nm->metadata().begin(); i != nm->metadata().end(); ++i) {
- cerr << "FIXME: Save metadata\n";
- /*
- // 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());
- }
- */
- }
-
- // Write port metadata, if necessary
- for (PortModelList::const_iterator i = nm->ports().begin(); i != nm->ports().end(); ++i) {
- cerr << "FIXME: save metadata\n";
- /*
- const PortModel* const pm = i->get();
- 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<CountedPtr<ConnectionModel> >& cl = patch_model->connections();
- const ConnectionModel* c = NULL;
-
- for (list<CountedPtr<ConnectionModel> >::const_iterator i = cl.begin(); i != cl.end(); ++i) {
- c = (*i).get();
- 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.get();
- for (PortModelList::const_iterator p = nm->ports().begin(); p != nm->ports().end(); ++p) {
- pm = (*p).get();
- 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->path().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).get();
- 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();
-}
-#endif
-
-
/** 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
@@ -390,14 +134,14 @@ PatchLibrarian::save_patch(CountedPtr<PatchModel> patch_model, const string& fil
* Returns the path of the newly created patch.
*/
string
-PatchLibrarian::load_patch(const string& filename,
+DeprecatedSerializer::load_patch(const string& filename,
const string& parent_path,
const string& name,
size_t poly,
MetadataMap initial_data,
bool existing)
{
- cerr << "[PatchLibrarian] Loading patch " << filename << "" << endl;
+ cerr << "[DeprecatedSerializer] Loading patch " << filename << "" << endl;
Path path = "/"; // path of the new patch
@@ -530,7 +274,7 @@ PatchLibrarian::load_patch(const string& filename,
/** Build a NodeModel given a pointer to a Node in a patch file.
*/
bool
-PatchLibrarian::load_node(const Path& parent, xmlDocPtr doc, const xmlNodePtr node)
+DeprecatedSerializer::load_node(const Path& parent, xmlDocPtr doc, const xmlNodePtr node)
{
xmlChar* key;
xmlNodePtr cur = node->xmlChildrenNode;
@@ -669,8 +413,8 @@ PatchLibrarian::load_node(const Path& parent, xmlDocPtr doc, const xmlNodePtr no
}
if (path == "") {
- cerr << "[PatchLibrarian] Malformed patch file (node tag has empty children)" << endl;
- cerr << "[PatchLibrarian] Node ignored." << endl;
+ cerr << "[DeprecatedSerializer] Malformed patch file (node tag has empty children)" << endl;
+ cerr << "[DeprecatedSerializer] Node ignored." << endl;
return false;
}
@@ -753,7 +497,7 @@ PatchLibrarian::load_node(const Path& parent, xmlDocPtr doc, const xmlNodePtr no
bool
-PatchLibrarian::load_subpatch(const Path& parent, xmlDocPtr doc, const xmlNodePtr subpatch)
+DeprecatedSerializer::load_subpatch(const Path& parent, xmlDocPtr doc, const xmlNodePtr subpatch)
{
xmlChar *key;
xmlNodePtr cur = subpatch->xmlChildrenNode;
@@ -794,7 +538,7 @@ PatchLibrarian::load_subpatch(const Path& parent, xmlDocPtr doc, const xmlNodePt
/** Build a ConnectionModel given a pointer to a connection in a patch file.
*/
bool
-PatchLibrarian::load_connection(const Path& parent, xmlDocPtr doc, const xmlNodePtr node)
+DeprecatedSerializer::load_connection(const Path& parent, xmlDocPtr doc, const xmlNodePtr node)
{
xmlChar *key;
xmlNodePtr cur = node->xmlChildrenNode;
@@ -843,7 +587,7 @@ PatchLibrarian::load_connection(const Path& parent, xmlDocPtr doc, const xmlNode
/** Build a PresetModel given a pointer to a preset in a patch file.
*/
bool
-PatchLibrarian::load_preset(const Path& parent, xmlDocPtr doc, const xmlNodePtr node)
+DeprecatedSerializer::load_preset(const Path& parent, xmlDocPtr doc, const xmlNodePtr node)
{
cerr << "FIXME: load preset\n";
#if 0
diff --git a/src/libs/client/PatchLibrarian.h b/src/libs/client/DeprecatedSerializer.h
index 893d5cdc..645c03f7 100644
--- a/src/libs/client/PatchLibrarian.h
+++ b/src/libs/client/DeprecatedSerializer.h
@@ -38,14 +38,14 @@ class PresetModel;
class ModelEngineInterface;
-/** Handles all patch saving and loading.
+/** Loads deprecated (XML) patch files (from the Om days).
*
* \ingroup IngenClient
*/
-class PatchLibrarian
+class DeprecatedSerializer
{
public:
- PatchLibrarian(CountedPtr<ModelEngineInterface> engine)
+ DeprecatedSerializer(CountedPtr<ModelEngineInterface> engine)
: _patch_search_path("."), _engine(engine)
{
assert(_engine);
@@ -56,8 +56,6 @@ 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(const string& filename,
const string& parent_path,
const string& name,
diff --git a/src/libs/client/Makefile.am b/src/libs/client/Makefile.am
index 42f1fddc..47e675c2 100644
--- a/src/libs/client/Makefile.am
+++ b/src/libs/client/Makefile.am
@@ -1,11 +1,12 @@
AM_CXXFLAGS = -I$(top_srcdir)/src/common
if BUILD_CLIENT_LIB
-noinst_LTLIBRARIES = libomclient.la
+noinst_LTLIBRARIES = libingenclient.la
-libomclient_la_CXXFLAGS = -I$(top_srcdir)/src/common -DPKGDATADIR=\"$(pkgdatadir)\" $(LXML2_CFLAGS) $(LSIGCPP_CFLAGS)
+libingenclient_la_CXXFLAGS = -I$(top_srcdir)/src/common -DPKGDATADIR=\"$(pkgdatadir)\" @LXML2_CFLAGS@ @REDLAND_CFLAGS@ @LSIGCPP_CFLAGS@
+libingenclient_la_LIBADD = @LXML2_LIBS@ @LOSC_LIBS@ @REDLAND_LIBS@ @LSIGCPP_LIBS@
-libomclient_la_SOURCES = \
+libingenclient_la_SOURCES = \
ClientInterface.h \
OSCEngineSender.h \
OSCEngineSender.cpp \
@@ -29,8 +30,10 @@ libomclient_la_SOURCES = \
PatchModel.h \
PatchModel.cpp \
PluginModel.h \
- PatchLibrarian.h \
- PatchLibrarian.cpp \
+ Serializer.h \
+ Serializer.cpp \
+ DeprecatedSerializer.h \
+ DeprecatedSerializer.cpp \
ConnectionModel.h \
ConnectionModel.cpp \
Store.h \
diff --git a/src/libs/client/ObjectModel.h b/src/libs/client/ObjectModel.h
index 5ef03b85..bc780cba 100644
--- a/src/libs/client/ObjectModel.h
+++ b/src/libs/client/ObjectModel.h
@@ -64,7 +64,6 @@ public:
protected:
friend class Store;
- friend class PatchLibrarian; // FIXME: remove
ObjectModel(const Path& path);
@@ -81,8 +80,8 @@ protected:
{ _metadata[key] = value; metadata_update_sig.emit(key, value); }
- Path _path;
- CountedPtr<ObjectModel> _parent;
+ Path _path;
+ CountedPtr<ObjectModel> _parent;
MetadataMap _metadata;
diff --git a/src/libs/client/PatchModel.h b/src/libs/client/PatchModel.h
index b5f9d428..a7679b15 100644
--- a/src/libs/client/PatchModel.h
+++ b/src/libs/client/PatchModel.h
@@ -41,8 +41,8 @@ class Store;
class PatchModel : public NodeModel
{
public:
- const NodeModelMap& nodes() const { return m_nodes; }
- const list<CountedPtr<ConnectionModel> >& connections() const { return m_connections; }
+ const NodeModelMap& nodes() const { return m_nodes; }
+ const ConnectionList& connections() const { return m_connections; }
CountedPtr<ConnectionModel> get_connection(const string& src_port_path, const string& dst_port_path) const;
CountedPtr<NodeModel> get_node(const string& node_name) const;
@@ -91,11 +91,11 @@ private:
PatchModel(const PatchModel& copy);
PatchModel& operator=(const PatchModel& copy);
- NodeModelMap m_nodes;
- list<CountedPtr<ConnectionModel> > m_connections;
- string m_filename;
- bool m_enabled;
- size_t m_poly;
+ NodeModelMap m_nodes;
+ ConnectionList m_connections;
+ string m_filename;
+ bool m_enabled;
+ size_t m_poly;
};
typedef map<string, CountedPtr<PatchModel> > PatchModelMap;
diff --git a/src/libs/client/Serializer.cpp b/src/libs/client/Serializer.cpp
new file mode 100644
index 00000000..e82389d4
--- /dev/null
+++ b/src/libs/client/Serializer.cpp
@@ -0,0 +1,525 @@
+/* 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 <algorithm>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <utility> // pair, make_pair
+#include <cassert>
+#include <cmath>
+#include <cstdlib> // atof
+#include <cstring>
+#include <redland.h>
+#include "Serializer.h"
+#include "PatchModel.h"
+#include "NodeModel.h"
+#include "ConnectionModel.h"
+#include "PortModel.h"
+#include "PresetModel.h"
+#include "ModelEngineInterface.h"
+#include "PluginModel.h"
+#include "util/Path.h"
+#include "util/Atom.h"
+#include "util/RedlandAtom.h"
+
+#define U(x) ((const unsigned char*)(x))
+
+using std::string; using std::vector; using std::pair;
+using std::cerr; using std::cout; using std::endl;
+
+namespace Ingen {
+namespace Client {
+
+
+Serializer::Serializer(CountedPtr<ModelEngineInterface> engine)
+ : _world(librdf_new_world())
+ , _serializer(0)
+ , _patch_search_path(".")
+ , _engine(engine)
+{
+ librdf_world_open(_world);
+
+ //_prefixes["xsd"] = "http://www.w3.org/2001/XMLSchema#";
+ _prefixes["rdf"] = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+ _prefixes["ingen"] = "http://codeson.net/ns/ingen#";
+ _prefixes["ingenuity"] = "http://codeson.net/ns/ingenuity#";
+}
+
+
+Serializer::~Serializer()
+{
+
+ librdf_free_world(_world);
+}
+
+
+void
+Serializer::create()
+{
+ _serializer = librdf_new_serializer(_world, "rdfxml-abbrev", NULL, librdf_new_uri(_world, U(NS_INGEN())));
+
+ setup_prefixes();
+}
+
+void
+Serializer::destroy()
+{
+ librdf_free_serializer(_serializer);
+ _serializer = NULL;
+}
+
+
+void
+Serializer::setup_prefixes()
+{
+ for (map<string,string>::const_iterator i = _prefixes.begin(); i != _prefixes.end(); ++i) {
+ librdf_serializer_set_namespace(_serializer,
+ librdf_new_uri(_world, U(i->second.c_str())), i->first.c_str());
+ }
+}
+
+
+/** Expands the prefix of URI, if the prefix is registered.
+ *
+ * If uri is not a valid URI, the empty string is returned (so invalid URIs won't be serialized).
+ */
+string
+Serializer::expand_uri(const string& uri)
+{
+ // FIXME: slow, stupid
+ for (map<string,string>::const_iterator i = _prefixes.begin(); i != _prefixes.end(); ++i)
+ if (uri.substr(0, i->first.length()+1) == i->first + ":")
+ return i->second + uri.substr(i->first.length()+1);
+
+ /*librdf_uri* redland_uri = librdf_new_uri(_world, U(uri.c_str()));
+ string ret = (redland_uri) ? uri : "";
+ librdf_free_uri(redland_uri);
+ return ret;*/
+
+ // FIXME: find a correct way to validate a URI
+ if (uri.find(":") == string::npos && uri.find("/") == string::npos)
+ return "";
+ else
+ return uri;
+}
+
+
+/** 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
+Serializer::find_file(const string& filename, const string& additional_path)
+{
+ string search_path = additional_path + ":" + _patch_search_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 << "[Serializer] 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.
+ *
+ * FIXME: make this take a URI. network loading for free.
+ *
+ * This will break if:
+ * - The filename does not have an extension (ie contain a ".")
+ * - The patch_model has no (Ingen) path
+ */
+void
+Serializer::save_patch(CountedPtr<PatchModel> patch_model, const string& filename, bool recursive)
+{
+ librdf_storage* storage = librdf_new_storage(_world, "hashes", NULL, "hash-type='memory'");
+
+ librdf_model* model = librdf_new_model(_world, storage, NULL);
+ assert(model);
+
+ const string uri = string("file://") + filename;
+ add_patch_to_rdf(model, patch_model, uri);
+
+ create();
+
+ //librdf_serializer_serialize_model_to_file_handle(serializer, stdout, NULL, model);
+ librdf_serializer_serialize_model_to_file(_serializer,
+ filename.c_str(), NULL, model);
+
+ destroy();
+
+ librdf_storage_close(storage);
+ librdf_free_storage(storage);
+ librdf_free_model(model);
+}
+
+
+void
+Serializer::add_resource_to_rdf(librdf_model* rdf,
+ const string& subject_uri, const string& predicate_uri, const string& object_uri)
+{
+
+ librdf_node* subject = librdf_new_node_from_uri_string(_world, U(subject_uri.c_str()));
+ add_resource_to_rdf(rdf, subject, predicate_uri, object_uri);
+}
+
+void
+Serializer::add_resource_to_rdf(librdf_model* rdf,
+ librdf_node* subject, const string& predicate_uri, const string& object_uri)
+{
+
+ librdf_node* predicate = librdf_new_node_from_uri_string(_world, U(predicate_uri.c_str()));
+ librdf_node* object = librdf_new_node_from_uri_string(_world, U(object_uri.c_str()));
+
+ librdf_model_add(rdf, subject, predicate, object);
+}
+
+
+void
+Serializer::add_atom_to_rdf(librdf_model* rdf,
+ const string& subject_uri, const string& predicate_uri, const Atom& atom)
+{
+ librdf_node* subject = librdf_new_node_from_uri_string(_world, U(subject_uri.c_str()));
+ librdf_node* predicate = librdf_new_node_from_uri_string(_world, U(predicate_uri.c_str()));
+ librdf_node* object = RedlandAtom::atom_to_node(_world, atom);
+
+ librdf_model_add(rdf, subject, predicate, object);
+}
+
+
+void
+Serializer::add_patch_to_rdf(librdf_model* rdf,
+ CountedPtr<PatchModel> patch, const string& uri_unused)
+{
+ const string uri = "#";
+
+ add_resource_to_rdf(rdf,
+ uri.c_str(),
+ NS_RDF("type"),
+ NS_INGEN("Patch"));
+
+ if (patch->path().name().length() > 0) {
+ add_atom_to_rdf(rdf,
+ uri.c_str(),
+ NS_INGEN("name"),
+ Atom(patch->path().name().c_str()));
+ }
+
+ add_atom_to_rdf(rdf,
+ uri.c_str(),
+ NS_INGEN("polyphony"),
+ Atom((int)patch->poly()));
+
+ for (NodeModelMap::const_iterator n = patch->nodes().begin(); n != patch->nodes().end(); ++n) {
+ add_node_to_rdf(rdf, n->second, "#");
+ add_resource_to_rdf(rdf, "#", NS_INGEN("node"), uri + n->second->path().name());
+ }
+
+ for (PortModelList::const_iterator p = patch->ports().begin(); p != patch->ports().end(); ++p) {
+ add_port_to_rdf(rdf, *p, uri);
+ add_resource_to_rdf(rdf, "#", NS_INGEN("port"), uri + (*p)->path().name());
+ }
+
+ for (ConnectionList::const_iterator c = patch->connections().begin(); c != patch->connections().end(); ++c) {
+ add_connection_to_rdf(rdf, *c, uri);
+ }
+
+ //_engine->set_metadata(patch->path(), "uri", uri);
+}
+
+
+void
+Serializer::add_node_to_rdf(librdf_model* rdf,
+ CountedPtr<NodeModel> node, const string ns_prefix)
+{
+ const string node_uri = ns_prefix + node->path().name();
+
+ add_resource_to_rdf(rdf,
+ node_uri.c_str(),
+ NS_RDF("type"),
+ NS_INGEN("Node"));
+
+ /*add_atom_to_rdf(rdf,
+ node_uri_ref.c_str(),
+ NS_INGEN("name"),
+ Atom(node->path().name()));*/
+
+ for (PortModelList::const_iterator p = node->ports().begin(); p != node->ports().end(); ++p) {
+ add_port_to_rdf(rdf, *p, node_uri + "/");
+ add_resource_to_rdf(rdf, node_uri, NS_INGEN("port"), node_uri + "/" + (*p)->path().name());
+ }
+
+ for (MetadataMap::const_iterator m = node->metadata().begin(); m != node->metadata().end(); ++m) {
+ if (expand_uri(m->first) != "") {
+ add_atom_to_rdf(rdf,
+ node_uri.c_str(),
+ expand_uri(m->first.c_str()).c_str(),
+ m->second);
+ }
+ }
+}
+
+
+void
+Serializer::add_port_to_rdf(librdf_model* rdf,
+ CountedPtr<PortModel> port, const string ns_prefix)
+{
+ const string port_uri_ref = ns_prefix + port->path().name();
+
+ add_resource_to_rdf(rdf,
+ port_uri_ref.c_str(),
+ NS_RDF("type"),
+ NS_INGEN("Port"));
+
+ for (MetadataMap::const_iterator m = port->metadata().begin(); m != port->metadata().end(); ++m) {
+ if (expand_uri(m->first) != "") {
+ add_atom_to_rdf(rdf,
+ port_uri_ref.c_str(),
+ expand_uri(m->first).c_str(),
+ m->second);
+ }
+ }
+}
+
+
+void
+Serializer::add_connection_to_rdf(librdf_model* rdf,
+ CountedPtr<ConnectionModel> connection, const string ns_prefix)
+{
+ librdf_node* c = librdf_new_node(_world);
+
+ const string src_port_rel_path = connection->src_port_path().substr(connection->patch_path().length());
+ const string dst_port_rel_path = connection->dst_port_path().substr(connection->patch_path().length());
+
+ librdf_statement* s = librdf_new_statement_from_nodes(_world, c,
+ librdf_new_node_from_uri_string(_world, U(NS_INGEN("source"))),
+ librdf_new_node_from_uri_string(_world, U((ns_prefix + src_port_rel_path).c_str())));
+ librdf_model_add_statement(rdf, s);
+
+ librdf_statement* d = librdf_new_statement_from_nodes(_world, c,
+ librdf_new_node_from_uri_string(_world, U(NS_INGEN("destination"))),
+ librdf_new_node_from_uri_string(_world, U((ns_prefix + dst_port_rel_path).c_str())));
+ librdf_model_add_statement(rdf, d);
+
+ add_resource_to_rdf(rdf, c, NS_RDF("type"), NS_INGEN("Connection"));
+}
+
+
+/** 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 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).
+ *
+ * @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
+Serializer::load_patch(const string& filename,
+ const string& parent_path,
+ const string& name,
+ size_t poly,
+ MetadataMap initial_data,
+ bool existing)
+{
+#if 0
+ cerr << "[Serializer] Loading patch " << filename << "" << endl;
+
+ Path path = "/"; // path of the new patch
+
+ 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) {
+ cerr << "Unable to parse patch file." << endl;
+ return "";
+ }
+
+ xmlNodePtr cur = xmlDocGetRootElement(doc);
+
+ if (!cur) {
+ cerr << "Empty document." << endl;
+ xmlFreeDoc(doc);
+ return "";
+ }
+
+ if (xmlStrcmp(cur->name, (const xmlChar*) "patch")) {
+ cerr << "File is not an Ingen patch file (root node != <patch>)" << endl;
+ xmlFreeDoc(doc);
+ return "";
+ }
+
+ xmlChar* key = NULL;
+ cur = cur->xmlChildrenNode;
+
+ // Load Patch attributes
+ while (cur != NULL) {
+ key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+
+ if ((!xmlStrcmp(cur->name, (const xmlChar*)"name"))) {
+ if (load_name) {
+ assert(key != NULL);
+ 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);
+ }
+ } else if (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")) {
+ // 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)
+ if (initial_data.find((const char*)cur->name) == initial_data.end())
+ initial_data[(const char*)cur->name] = (const char*)key;
+ }
+
+ xmlFree(key);
+ key = NULL; // Avoid a (possible?) double free
+
+ cur = cur->next;
+ }
+
+ if (poly == 0)
+ poly = 1;
+
+ // 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")))
+ load_node(path, doc, cur);
+
+ cur = cur->next;
+ }
+
+ // Load subpatches
+ cur = xmlDocGetRootElement(doc)->xmlChildrenNode;
+ while (cur != NULL) {
+ if ((!xmlStrcmp(cur->name, (const xmlChar*)"subpatch"))) {
+ load_subpatch(path, doc, cur);
+ }
+ cur = cur->next;
+ }
+
+ // Load connections
+ cur = xmlDocGetRootElement(doc)->xmlChildrenNode;
+ while (cur != NULL) {
+ if ((!xmlStrcmp(cur->name, (const xmlChar*)"connection"))) {
+ load_connection(path, doc, cur);
+ }
+ cur = cur->next;
+ }
+
+
+ // Load presets (control values)
+ cerr << "FIXME: load preset\n";
+ /*cur = xmlDocGetRootElement(doc)->xmlChildrenNode;
+ while (cur != NULL) {
+ if ((!xmlStrcmp(cur->name, (const xmlChar*)"preset"))) {
+ 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();
+
+ // Done above.. late enough?
+ //_engine->set_metadata_map(path, initial_data);
+
+ if (!existing)
+ _engine->enable_patch(path);
+
+ _load_path_translations.clear();
+
+ return path;
+#endif
+ return "/FIXME";
+}
+
+} // namespace Client
+} // namespace Ingen
diff --git a/src/libs/client/Serializer.h b/src/libs/client/Serializer.h
new file mode 100644
index 00000000..b2dbf000
--- /dev/null
+++ b/src/libs/client/Serializer.h
@@ -0,0 +1,118 @@
+/* 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 PATCHLIBRARIAN_H
+#define PATCHLIBRARIAN_H
+
+#include <map>
+#include <utility>
+#include <string>
+#include <redland.h>
+#include <cassert>
+#include "util/CountedPtr.h"
+#include "util/Path.h"
+#include "util/Atom.h"
+#include "ObjectModel.h"
+
+using std::string;
+
+namespace Ingen {
+namespace Client {
+
+class PatchModel;
+class NodeModel;
+class PortModel;
+class ConnectionModel;
+class PresetModel;
+class ModelEngineInterface;
+
+
+/** Namespace prefix macros. */
+#define NS_RDF(x) "http://www.w3.org/1999/02/22-rdf-syntax-ns#" x
+#define NS_INGEN(x) "http://codeson.net/ns/ingen#" x
+
+
+/** Handles all patch saving and loading.
+ *
+ * \ingroup IngenClient
+ */
+class Serializer
+{
+public:
+ Serializer(CountedPtr<ModelEngineInterface> engine);
+ ~Serializer();
+
+ void path(const string& path) { _patch_search_path = path; }
+ const string& path() { return _patch_search_path; }
+
+ 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(const string& filename,
+ const string& parent_path,
+ const string& name,
+ size_t poly,
+ MetadataMap initial_data,
+ bool existing = false);
+
+private:
+
+ // Model -> RDF
+
+ void add_patch_to_rdf(librdf_model* rdf,
+ CountedPtr<PatchModel> patch, const string& uri);
+
+ void add_node_to_rdf(librdf_model* rdf,
+ CountedPtr<NodeModel> node, const string ns_prefix="");
+
+ void add_port_to_rdf(librdf_model* rdf,
+ CountedPtr<PortModel> port, const string ns_prefix="");
+
+ void add_connection_to_rdf(librdf_model* rdf,
+ CountedPtr<ConnectionModel> connection, const string port_ns_prefix="");
+
+
+ // Triple -> RDF
+
+ void add_resource_to_rdf(librdf_model* model,
+ const string& subject_uri, const string& predicate_uri, const string& object_uri);
+
+ void add_resource_to_rdf(librdf_model* model,
+ librdf_node* subject, const string& predicate_uri, const string& object_uri);
+
+ void add_atom_to_rdf(librdf_model* model,
+ const string& subject_uri, const string& predicate_uri, const Atom& atom);
+
+
+ void create();
+ void destroy();
+ void setup_prefixes();
+ string expand_uri(const string& uri);
+
+
+ librdf_world* _world;
+ librdf_serializer* _serializer;
+ string _patch_search_path;
+ map<string, string> _prefixes;
+ CountedPtr<ModelEngineInterface> _engine;
+};
+
+
+} // namespace Client
+} // namespace Ingen
+
+#endif // PATCHLIBRARIAN_H
diff --git a/src/libs/engine/Makefile.am b/src/libs/engine/Makefile.am
index 3747515b..95b684d5 100644
--- a/src/libs/engine/Makefile.am
+++ b/src/libs/engine/Makefile.am
@@ -3,6 +3,8 @@ DIST_SUBDIRS = events
AM_CXXFLAGS = @JACK_CFLAGS@ @LOSC_CFLAGS@ @ALSA_CFLAGS@ @LASH_CFLAGS@ @SLV2_CFLAGS@ -I$(top_srcdir)/src/common -I$(top_srcdir)/src/libs/engine/events
+libingen_la_LIBADD = @JACK_LIBS@ @LOSC_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@
+
MAINTAINERCLEANFILES = Makefile.in
noinst_LTLIBRARIES = libingen.la
diff --git a/src/progs/demolition/Makefile.am b/src/progs/demolition/Makefile.am
index b01b062b..fe2b20b6 100644
--- a/src/progs/demolition/Makefile.am
+++ b/src/progs/demolition/Makefile.am
@@ -1,11 +1,11 @@
EXTRA_DIST = README
om_demolition_CXXFLAGS = -I$(top_srcdir)/src/libs/client -I$(top_srcdir)/src/common -DPKGDATADIR=\"$(pkgdatadir)\" $(LXML2_CFLAGS) $(LOSC_CFLAGS) $(LSIGCPP_CFLAGS)
-om_demolition_LDADD = ../../libs/client/libomclient.la $(LOSC_LIBS) $(LXML2_LIBS) $(LSIGCPP_LIBS)
+om_demolition_LDADD = ../../libs/client/libingenclient.la $(LOSC_LIBS) $(LXML2_LIBS) $(LSIGCPP_LIBS)
bin_PROGRAMS = om_demolition
-om_demolition_DEPENDENCIES = ../../libs/client/libomclient.la
+om_demolition_DEPENDENCIES = ../../libs/client/libingenclient.la
om_demolition_SOURCES = \
demolition.cpp \
diff --git a/src/progs/demolition/demolition.cpp b/src/progs/demolition/demolition.cpp
index 3015200e..3693b5f3 100644
--- a/src/progs/demolition/demolition.cpp
+++ b/src/progs/demolition/demolition.cpp
@@ -229,8 +229,8 @@ create_patch()
engine->create_patch(path, (rand()%8)+1);
// Spread them out a bit for easier monitoring with ingenuity
- engine->set_metadata(path, "module-x", 1600 + rand()%800 - 400);
- engine->set_metadata(path, "module-y", 1200 + rand()%700 - 350);
+ engine->set_metadata(path, "ingenuity:module-x", 1600 + rand()%800 - 400);
+ engine->set_metadata(path, "ingenuity:module-y", 1200 + rand()%700 - 350);
}
@@ -255,8 +255,8 @@ add_node()
engine->create_node(path, random_plugin(), rand()%2);
// Spread them out a bit for easier monitoring with ingenuity
- engine->set_metadata(path, "module-x", 1600 + rand()%800 - 400);
- engine->set_metadata(path, "module-y", 1200 + rand()%700 - 350);
+ engine->set_metadata(path, "ingenuity:module-x", 1600 + rand()%800 - 400);
+ engine->set_metadata(path, "ingenuity:module-y", 1200 + rand()%700 - 350);
}
diff --git a/src/progs/ingenuity/Loader.cpp b/src/progs/ingenuity/Loader.cpp
index 59d718c7..485e450d 100644
--- a/src/progs/ingenuity/Loader.cpp
+++ b/src/progs/ingenuity/Loader.cpp
@@ -18,7 +18,7 @@
#include <fstream>
#include <cassert>
#include <string>
-#include "PatchLibrarian.h"
+#include "Serializer.h"
#include "PatchModel.h"
using std::cout; using std::endl;
@@ -26,9 +26,9 @@ namespace Ingenuity {
Loader::Loader(CountedPtr<ModelEngineInterface> engine)
-: _patch_librarian(new PatchLibrarian(engine))
+: _serializer(new Serializer(engine))
{
- assert(_patch_librarian != NULL);
+ assert(_serializer != NULL);
// FIXME: rework this so the thread is only present when it's doing something (save mem)
start();
@@ -37,7 +37,7 @@ Loader::Loader(CountedPtr<ModelEngineInterface> engine)
Loader::~Loader()
{
- delete _patch_librarian;
+ delete _serializer;
}
@@ -45,12 +45,12 @@ void
Loader::_whipped()
{
_mutex.lock();
+
+ while ( ! _events.empty() ) {
+ _events.front()();
+ _events.pop_front();
+ }
- Closure& ev = _event;
- ev();
- ev.disconnect();
-
- _cond.signal();
_mutex.unlock();
}
@@ -65,23 +65,29 @@ Loader::load_patch(const string& filename,
{
_mutex.lock();
- _event = sigc::hide_return(sigc::bind(
- sigc::mem_fun(_patch_librarian, &PatchLibrarian::load_patch),
- filename, parent_path, name, poly, initial_data, existing));
+ _events.push_back(sigc::hide_return(sigc::bind(
+ sigc::mem_fun(_serializer, &Serializer::load_patch),
+ filename, parent_path, name, poly, initial_data, existing)));
- whip();
-
- _cond.wait(_mutex);
_mutex.unlock();
+
+ whip();
}
void
Loader::save_patch(CountedPtr<PatchModel> model, const string& filename, bool recursive)
{
- cerr << "FIXME: (loader) save patch\n";
- //cout << "[Loader] Saving patch " << filename << endl;
- //set_event(new SavePatchEvent(m_patch_librarian, model, filename, recursive));
+ _mutex.lock();
+
+ _events.push_back(sigc::hide_return(sigc::bind(
+ sigc::mem_fun(_serializer, &Serializer::save_patch),
+ model, filename, recursive)));
+
+ _mutex.unlock();
+
+ whip();
}
+
} // namespace Ingenuity
diff --git a/src/progs/ingenuity/Loader.h b/src/progs/ingenuity/Loader.h
index a33945a1..7459378e 100644
--- a/src/progs/ingenuity/Loader.h
+++ b/src/progs/ingenuity/Loader.h
@@ -18,6 +18,7 @@
#define LOADERTHREAD_H
#include <string>
+#include <list>
#include <cassert>
#include "util/Thread.h"
#include "util/Slave.h"
@@ -26,9 +27,10 @@
#include "ModelEngineInterface.h"
#include "ObjectModel.h"
using std::string;
+using std::list;
namespace Ingen { namespace Client {
- class PatchLibrarian;
+ class Serializer;
class PatchModel;
} }
using namespace Ingen::Client;
@@ -42,6 +44,9 @@ namespace Ingenuity {
* blocking everything else, so the app can respond to the incoming events
* caused as a result of the patch loading, while the patch loads.
*
+ * Implemented as a slave with a list of closures (events) which processes
+ * all events in the (mutex protected) list each time it's whipped.
+ *
* \ingroup Ingenuity
*/
class Loader : public Slave
@@ -50,7 +55,7 @@ public:
Loader(CountedPtr<ModelEngineInterface> engine);
~Loader();
- PatchLibrarian& librarian() { return *_patch_librarian; }
+ Serializer& serializer() const { return *_serializer; }
void load_patch(const string& filename,
const string& parent_path,
@@ -69,10 +74,9 @@ private:
void _whipped();
- PatchLibrarian* const _patch_librarian;
- Mutex _mutex;
- Condition _cond;
- Closure _event;
+ Serializer* const _serializer;
+ Mutex _mutex;
+ list<Closure> _events;
};
diff --git a/src/progs/ingenuity/Makefile.am b/src/progs/ingenuity/Makefile.am
index 48b53f33..3044a2fc 100644
--- a/src/progs/ingenuity/Makefile.am
+++ b/src/progs/ingenuity/Makefile.am
@@ -6,14 +6,15 @@ MAINTAINERCLEANFILES = Makefile.in
sharefilesdir = $(pkgdatadir)
dist_sharefiles_DATA = ingenuity.glade om-icon.png
-AM_CXXFLAGS = -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -I$(top_srcdir)/src/common -I$(top_srcdir)/src/libs/client -DPKGDATADIR=\"$(pkgdatadir)\" @GTKMM_CFLAGS@ @LIBGLADEMM_CFLAGS@ @GNOMECANVASMM_CFLAGS@ @LOSC_CFLAGS@ @LASH_CFLAGS@ @FLOWCANVAS_CFLAGS@
-ingenuity_LDADD = @GTKMM_LIBS@ @LIBGLADEMM_LIBS@ @GNOMECANVASMM_LIBS@ @LOSC_LIBS@ @LASH_LIBS@ @FLOWCANVAS_LIBS@ ../../libs/client/libomclient.la
-ingenuity_DEPENDENCIES = ../../libs/client/libomclient.la
+ingenuity_CXXFLAGS = -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -I$(top_srcdir)/src/common -I$(top_srcdir)/src/libs/client -DPKGDATADIR=\"$(pkgdatadir)\" @GTKMM_CFLAGS@ @LIBGLADEMM_CFLAGS@ @GNOMECANVASMM_CFLAGS@ @LOSC_CFLAGS@ @LASH_CFLAGS@ @FLOWCANVAS_CFLAGS@
+ingenuity_LDADD = @GTKMM_LIBS@ @LIBGLADEMM_LIBS@ @GNOMECANVASMM_LIBS@ @LOSC_LIBS@ @LASH_LIBS@ @FLOWCANVAS_LIBS@ ../../libs/client/libingenclient.la
+ingenuity_DEPENDENCIES = ../../libs/client/libingenclient.la
# FIXME: make engine have a separate include dir
if MONOLITHIC_INGENUITY
-AM_CXXFLAGS += -I$(top_srcdir)/src/libs
-ingenuity_LDADD += @JACK_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@ -lrt ../../libs/engine/libingen.la
+ingenuity_CXXFLAGS += -I$(top_srcdir)/src/libs
+#ingenuity_LDADD += @JACK_LIBS@ @ALSA_LIBS@ @LASH_LIBS@ @SLV2_LIBS@ -lrt ../../libs/engine/libingen.la
+ingenuity_LDADD += ../../libs/engine/libingen.la
ingenuity_DEPENDENCIES += ../../libs/engine/libingen.la
endif
diff --git a/src/progs/ingenuity/NodeModule.cpp b/src/progs/ingenuity/NodeModule.cpp
index 8545e493..29af857e 100644
--- a/src/progs/ingenuity/NodeModule.cpp
+++ b/src/progs/ingenuity/NodeModule.cpp
@@ -104,13 +104,13 @@ NodeModule::store_location()
const float x = static_cast<float>(property_x());
const float y = static_cast<float>(property_y());
- const Atom& existing_x = m_node->get_metadata("module-x");
- const Atom& existing_y = m_node->get_metadata("module-y");
+ const Atom& existing_x = m_node->get_metadata("ingenuity:canvas-x");
+ const Atom& existing_y = m_node->get_metadata("ingenuity:canvas-y");
if (existing_x.type() != Atom::FLOAT || existing_y.type() != Atom::FLOAT
|| existing_x.get_float() != x || existing_y.get_float() != y) {
- App::instance().engine()->set_metadata(m_node->path(), "module-x", Atom(x));
- App::instance().engine()->set_metadata(m_node->path(), "module-y", Atom(y));
+ App::instance().engine()->set_metadata(m_node->path(), "ingenuity:canvas-x", Atom(x));
+ App::instance().engine()->set_metadata(m_node->path(), "ingenuity:canvas-y", Atom(y));
}
}
@@ -126,9 +126,9 @@ NodeModule::on_right_click(GdkEventButton* event)
void
NodeModule::metadata_update(const string& key, const Atom& value)
{
- if (key == "module-x" && value.type() == Atom::FLOAT)
+ if (key == "ingenuity:canvas-x" && value.type() == Atom::FLOAT)
move_to(value.get_float(), property_y());
- else if (key == "module-y" && value.type() == Atom::FLOAT)
+ else if (key == "ingenuity:canvas-y" && value.type() == Atom::FLOAT)
move_to(property_x(), value.get_float());
}
diff --git a/src/progs/ingenuity/PatchCanvas.cpp b/src/progs/ingenuity/PatchCanvas.cpp
index 9419b252..707b8856 100644
--- a/src/progs/ingenuity/PatchCanvas.cpp
+++ b/src/progs/ingenuity/PatchCanvas.cpp
@@ -217,9 +217,9 @@ PatchCanvas::connect(const LibFlowCanvas::Port* src_port, const LibFlowCanvas::P
CountedPtr<PluginModel> pm(new PluginModel(PluginModel::Internal, "", "midi_control_in", ""));
CountedPtr<NodeModel> nm(new NodeModel(pm, m_patch->path().base()
+ src->name() + "-" + dst->name(), false));
- nm->set_metadata("module-x", Atom((float)
+ nm->set_metadata("canvas-x", Atom((float)
(dst->module()->property_x() - dst->module()->width() - 20)));
- nm->set_metadata("module-y", Atom((float)
+ nm->set_metadata("canvas-y", Atom((float)
(dst->module()->property_y())));
App::instance().engine()->create_node_from_model(nm.get());
App::instance().engine()->connect(src->model()->path(), nm->path() + "/MIDI_In");
@@ -332,8 +332,8 @@ PatchCanvas::get_initial_data()
{
MetadataMap result;
- result["module-x"] = Atom((float)m_last_click_x);
- result["module-y"] = Atom((float)m_last_click_y);
+ result["ingenuity:canvas-x"] = Atom((float)m_last_click_x);
+ result["ingenuity:canvas-y"] = Atom((float)m_last_click_y);
return result;
}
diff --git a/src/progs/ingenuity/PatchPortModule.cpp b/src/progs/ingenuity/PatchPortModule.cpp
index 369a04b1..8843882b 100644
--- a/src/progs/ingenuity/PatchPortModule.cpp
+++ b/src/progs/ingenuity/PatchPortModule.cpp
@@ -51,8 +51,8 @@ PatchPortModule::PatchPortModule(PatchCanvas* canvas, CountedPtr<PortModel> port
resize();
- const Atom& x_atom = port->get_metadata("module-x");
- const Atom& y_atom = port->get_metadata("module-y");
+ const Atom& x_atom = port->get_metadata("ingenuity:canvas-x");
+ const Atom& y_atom = port->get_metadata("ingenuity:canvas-y");
if (x_atom && y_atom && x_atom.type() == Atom::FLOAT && y_atom.type() == Atom::FLOAT) {
move_to(x_atom.get_float(), y_atom.get_float());
@@ -73,13 +73,13 @@ PatchPortModule::store_location()
const float x = static_cast<float>(property_x());
const float y = static_cast<float>(property_y());
- const Atom& existing_x = m_port->get_metadata("module-x");
- const Atom& existing_y = m_port->get_metadata("module-y");
+ const Atom& existing_x = m_port->get_metadata("ingenuity:canvas-x");
+ const Atom& existing_y = m_port->get_metadata("ingenuity:canvas-y");
if (existing_x.type() != Atom::FLOAT || existing_y.type() != Atom::FLOAT
|| existing_x.get_float() != x || existing_y.get_float() != y) {
- App::instance().engine()->set_metadata(m_port->path(), "module-x", Atom(x));
- App::instance().engine()->set_metadata(m_port->path(), "module-y", Atom(y));
+ App::instance().engine()->set_metadata(m_port->path(), "ingenuity:canvas-x", Atom(x));
+ App::instance().engine()->set_metadata(m_port->path(), "ingenuity:canvas-y", Atom(y));
}
}
@@ -87,9 +87,9 @@ PatchPortModule::store_location()
void
PatchPortModule::metadata_update(const string& key, const Atom& value)
{
- if (key == "module-x" && value.type() == Atom::FLOAT)
+ if (key == "ingenuity:canvas-x" && value.type() == Atom::FLOAT)
move_to(value.get_float(), property_y());
- else if (key == "module-y" && value.type() == Atom::FLOAT)
+ else if (key == "ingenuity:canvas-y" && value.type() == Atom::FLOAT)
move_to(property_x(), value.get_float());
}
diff --git a/src/progs/patch_loader/Makefile.am b/src/progs/patch_loader/Makefile.am
index c14814ff..33947a36 100644
--- a/src/progs/patch_loader/Makefile.am
+++ b/src/progs/patch_loader/Makefile.am
@@ -1,13 +1,13 @@
EXTRA_DIST = README
-om_patch_loader_CXXFLAGS = -I$(top_srcdir)/src/libs/client -I$(top_srcdir)/src/common -DPKGDATADIR=\"$(pkgdatadir)\" $(LXML2_CFLAGS) $(LOSC_CFLAGS) $(LSIGCPP_CFLAGS)
-om_patch_loader_LDADD = ../../libs/client/libomclient.la $(LOSC_LIBS) $(LXML2_LIBS) $(LSIGCPP_LIBS)
+ingen_load_CXXFLAGS = -I$(top_srcdir)/src/libs/client -I$(top_srcdir)/src/common @LSIGCPP_CFLAGS@
+ingen_load_LDADD = ../../libs/client/libingenclient.la
-bin_PROGRAMS = om_patch_loader
+bin_PROGRAMS = ingen_load
-om_patch_loader_DEPENDENCIES = ../../libs/client/libomclient.la
+ingen_load_DEPENDENCIES = ../../libs/client/libingenclient.la
-om_patch_loader_SOURCES = \
+ingen_load_SOURCES = \
patch_loader.cpp \
cmdline.h \
cmdline.c
diff --git a/src/progs/patch_loader/patch_loader.cpp b/src/progs/patch_loader/patch_loader.cpp
index 69a06407..b0d8bc94 100644
--- a/src/progs/patch_loader/patch_loader.cpp
+++ b/src/progs/patch_loader/patch_loader.cpp
@@ -16,7 +16,7 @@
#include "OSCModelEngineInterface.h"
-#include "PatchLibrarian.h"
+#include "Serializer.h"
#include "PatchModel.h"
#include "util/Path.h"
#include <iostream>
@@ -53,7 +53,7 @@ int main(int argc, char** argv)
CountedPtr<OSCModelEngineInterface> engine(new OSCModelEngineInterface(engine_url));
- PatchLibrarian librarian(engine);
+ Serializer serializer(engine);
/* Connect to engine */
engine->attach(-1, client_port);
@@ -74,7 +74,7 @@ int main(int argc, char** argv)
cerr << "FIXME: load patch" << endl;
//CountedPtr<PatchModel> pm(new PatchModel("", 0));
//pm->filename(args_info.inputs[i]);
- //librarian.load_patch(pm, true);
+ //serializer.load_patch(pm, true);
}
return 0;