From 0a02e807beea6104248cb6cf00ef6689c9231912 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 14 Jan 2013 07:39:55 +0000 Subject: Fix saving and loading machines. git-svn-id: http://svn.drobilla.net/lad/trunk/machina@4984 a436a847-0d15-0410-975c-d299462d15a1 --- src/engine/Loader.cpp | 189 ++++++++++++++++++++++++-------------------------- 1 file changed, 92 insertions(+), 97 deletions(-) (limited to 'src/engine/Loader.cpp') diff --git a/src/engine/Loader.cpp b/src/engine/Loader.cpp index 64927e8..0497268 100644 --- a/src/engine/Loader.cpp +++ b/src/engine/Loader.cpp @@ -20,28 +20,59 @@ #include +#include "lv2/lv2plug.in/ns/ext/midi/midi.h" + #include "machina/Loader.hpp" +#include "machina/URIs.hpp" #include "machina/Machine.hpp" -#include "machina_config.h" -#include "ActionFactory.hpp" #include "Edge.hpp" +#include "MidiAction.hpp" #include "Node.hpp" +#include "SMFDriver.hpp" +#include "machina_config.h" using namespace Raul; using namespace std; -#define NS_MACHINA "http://drobilla.net/ns/machina#" -#define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#" - namespace machina { Loader::Loader(Raul::Forge& forge, Sord::World& rdf_world) : _forge(forge) , _rdf_world(rdf_world) +{} + +static SPtr +load_action(Sord::Model& model, Sord::Node node) { - _rdf_world.add_prefix("xsd", "http://www.w3.org/2001/XMLSchema#"); - _rdf_world.add_prefix("", "http://drobilla.net/ns/machina#"); + if (!node.is_valid()) { + return SPtr(); + } + + Sord::URI rdf_type(model.world(), MACHINA_URI_RDF "type"); + Sord::URI midi_NoteOn(model.world(), LV2_MIDI__NoteOn); + Sord::URI midi_NoteOff(model.world(), LV2_MIDI__NoteOff); + Sord::URI midi_noteNumber(model.world(), LV2_MIDI__noteNumber); + Sord::URI midi_velocity(model.world(), LV2_MIDI__velocity); + + Sord::Node type = model.get(node, rdf_type, Sord::Node()); + uint8_t status = 0; + if (type == midi_NoteOn) { + status = LV2_MIDI_MSG_NOTE_ON; + } else if (type == midi_NoteOff) { + status = LV2_MIDI_MSG_NOTE_OFF; + } else { + return SPtr(); + } + + Sord::Node num_node = model.get(node, midi_noteNumber, Sord::Node()); + Sord::Node vel_node = model.get(node, midi_velocity, Sord::Node()); + + const uint8_t num = num_node.is_int() ? num_node.to_int() : 64; + const uint8_t vel = vel_node.is_int() ? vel_node.to_int() : 64; + const uint8_t event[3] = { status, num, vel }; + + return SPtr(new MidiAction(sizeof(event), event)); } /** Load (create) all objects from RDF into the engine. @@ -54,8 +85,6 @@ Loader::load(const Glib::ustring& uri) { using Glib::ustring; - SPtr machine; - ustring document_uri = uri; // If "URI" doesn't contain a colon, try to resolve as a filename @@ -63,105 +92,67 @@ Loader::load(const Glib::ustring& uri) document_uri = "file://" + document_uri; } - const string machine_uri = string("<>"); + cout << "Loading " << document_uri << endl; - cout << "[Loader] Loading " << document_uri << endl; + TimeUnit beats(TimeUnit::BEATS, MACHINA_PPQN); - machine = SPtr( - new Machine(TimeUnit::beats(MACHINA_PPQN))); + SPtr machine(new Machine(beats)); typedef std::map > Created; Created created; + Sord::URI base_uri(_rdf_world, document_uri); Sord::Model model(_rdf_world, document_uri); - SerdEnv* env = serd_env_new(NULL); + + SerdEnv* env = serd_env_new(base_uri.to_serd_node()); model.load_file(env, SERD_TURTLE, document_uri); serd_env_free(env); Sord::Node nil; - Sord::URI rdf_type(_rdf_world, NS_RDF "type"); - Sord::URI machina_SelectorNode(_rdf_world, NS_MACHINA "SelectorNode"); - Sord::URI machina_node(_rdf_world, NS_MACHINA "node"); - Sord::URI machina_initialNode(_rdf_world, NS_MACHINA "initialNode"); - Sord::URI machina_duration(_rdf_world, NS_MACHINA "duration"); - Sord::URI machina_edge(_rdf_world, NS_MACHINA "edge"); - Sord::URI machina_tail(_rdf_world, NS_MACHINA "tail"); - Sord::URI machina_head(_rdf_world, NS_MACHINA "head"); - Sord::URI machina_probability(_rdf_world, NS_MACHINA "probability"); - - Sord::Node machine_node = Sord::URI(_rdf_world, "."); - - /* Get initial nodes */ - for (Sord::Iter i = model.find(machine_node, machina_initialNode, nil); - !i.end(); ++i) { - const Sord::Node& node_id = i.get_object(); - Sord::Iter d = model.find(node_id, machina_duration, nil); - SPtr node( - new Node(TimeStamp(TimeUnit(TimeUnit::BEATS, MACHINA_PPQN), - d.get_object().to_float()), - true)); - - Sord::Iter s = model.find(node_id, rdf_type, machina_SelectorNode); - if (!s.end()) { - node->set_selector(true); + Sord::URI machina_SelectorNode(_rdf_world, MACHINA_NS_SelectorNode); + Sord::URI machina_duration(_rdf_world, MACHINA_NS_duration); + Sord::URI machina_edge(_rdf_world, MACHINA_NS_arc); + Sord::URI machina_head(_rdf_world, MACHINA_NS_head); + Sord::URI machina_node(_rdf_world, MACHINA_NS_node); + Sord::URI machina_onEnter(_rdf_world, MACHINA_NS_onEnter); + Sord::URI machina_onExit(_rdf_world, MACHINA_NS_onExit); + Sord::URI machina_probability(_rdf_world, MACHINA_NS_probability); + Sord::URI machina_start(_rdf_world, MACHINA_NS_start); + Sord::URI machina_tail(_rdf_world, MACHINA_NS_tail); + Sord::URI rdf_type(_rdf_world, MACHINA_URI_RDF "type"); + + Sord::Node subject = base_uri; + + // Get start node ID (but re-use existing start node) + Sord::Iter i = model.find(subject, machina_start, nil); + if (i.end()) { + cerr << "error: Machine has no start node" << std::endl; + } + created[i.get_object()] = machine->initial_node(); + + // Get remaining nodes + for (Sord::Iter i = model.find(subject, machina_node, nil); !i.end(); ++i) { + const Sord::Node& id = i.get_object(); + if (created.find(id) != created.end()) { + cerr << "warning: Machine lists the same node twice" << std::endl; + continue; } + // Create node + Sord::Iter d = model.find(id, machina_duration, nil); + SPtr node(new Node(TimeStamp(beats, d.get_object().to_float()))); machine->add_node(node); - created[node_id] = node; - } + created[id] = node; - /* Get remaining (non-initial) nodes */ - for (Sord::Iter i = model.find(machine_node, machina_node, nil); - !i.end(); ++i) { - const Sord::Node& node_id = i.get_object(); - Sord::Iter d = model.find(node_id, machina_duration, nil); - if (created.find(node_id) == created.end()) { - SPtr node( - new Node(TimeStamp(TimeUnit(TimeUnit::BEATS, MACHINA_PPQN), - d.get_object().to_float()), - false)); - machine->add_node(node); - created[node_id] = node; - } - } - -#if 0 - cerr << "FIXME: Load actions" << endl; - /* Get note actions */ - - query = Query(_rdf_world, ustring( - "SELECT DISTINCT ?node ?note WHERE {\n" - " ?node :enterAction [ a :MidiAction; :midiNote ?note ] ;\n" - " :exitAction [ a :MidiAction; :midiNote ?note ] .\n" - "}\n")); - - results = query.run(_rdf_world, model); - for (; !results->finished(); results->next()) { - Created::iterator node_i - = created.find((const char*)results->get("node")); - if (node_i != created.end()) { - SPtr node = node_i->second; - const int note_num = results->get("note").to_int(); - if (note_num >= 0 && note_num <= 127) { - node->set_enter_action( - ActionFactory::note_on((uint8_t)note_num)); - node->set_exit_action( - ActionFactory::note_off((uint8_t)note_num)); - } else { - cerr << "WARNING: MIDI note number out of range, ignoring." - << endl; - } - } else { - cerr << "WARNING: Found note for unknown states. Ignoring." - << endl; - } + node->set_enter_action( + load_action(model, model.get(id, machina_onEnter, nil))); + node->set_exit_action( + load_action(model, model.get(id, machina_onExit, nil))); } -#endif - /* Get edges */ - for (Sord::Iter i = model.find(machine_node, machina_edge, nil); - !i.end(); ++i) { + // Get arcs + for (Sord::Iter i = model.find(subject, machina_edge, nil); !i.end(); ++i) { Sord::Node edge = i.get_object(); Sord::Iter t = model.find(edge, machina_tail, nil); Sord::Iter h = model.find(edge, machina_head, nil); @@ -179,16 +170,11 @@ Loader::load(const Glib::ustring& uri) if (tail_i != created.end() && head_i != created.end()) { const SPtr tail = tail_i->second; const SPtr head = head_i->second; - - SPtr edge(new Edge(tail, head)); - edge->set_probability(prob); - tail->add_edge(edge); - + tail->add_edge(SPtr(new Edge(tail, head, prob))); } else { - cerr << "[Loader] WARNING: Ignored edge between unknown nodes " + cerr << "warning: Ignored edge between unknown nodes " << tail << " -> " << head << endl; } - } if (machine && !machine->nodes().empty()) { @@ -199,4 +185,13 @@ Loader::load(const Glib::ustring& uri) } } +SPtr +Loader::load_midi(const Glib::ustring& uri, + double q, + Raul::TimeDuration dur) +{ + SPtr file_driver(new SMFDriver(_forge, dur.unit())); + return file_driver->learn(uri, q, dur); +} + } // namespace machina -- cgit v1.2.1