/* This file is part of Machina. * Copyright 2007-2011 David Robillard * * Machina 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 3 of the License, or * (at your option) any later version. * * Machina 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 more details. * * You should have received a copy of the GNU General Public License * along with Machina. If not, see . */ #include #include #include #include #include "machina/Loader.hpp" #include "machina/Machine.hpp" #include "machina-config.h" #include "ActionFactory.hpp" #include "Edge.hpp" #include "Node.hpp" 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(Sord::World& rdf_world) : _rdf_world(rdf_world) { _rdf_world.add_prefix("xsd", "http://www.w3.org/2001/XMLSchema#"); _rdf_world.add_prefix("", "http://drobilla.net/ns/machina#"); } /** Load (create) all objects from RDF into the engine. * * @param uri URI of machine (resolvable URI to an RDF document). * @return Loaded Machine. */ SharedPtr Loader::load(const Glib::ustring& uri) { using Glib::ustring; SharedPtr machine; ustring document_uri = uri; // If "URI" doesn't contain a colon, try to resolve as a filename if (uri.find(":") == ustring::npos) { document_uri = "file://" + document_uri; } const string machine_uri = string("<>"); cout << "[Loader] Loading " << document_uri << endl; machine = SharedPtr(new Machine(TimeUnit::beats(MACHINA_PPQN))); typedef std::map > Created; Created created; Sord::Model model(_rdf_world, document_uri); SerdEnv* env = serd_env_new(NULL); 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 "initialNode"); 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); SharedPtr 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); } machine->add_node(node); created[node_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()) { SharedPtr 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()) { SharedPtr 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((unsigned char)note_num)); node->set_exit_action(ActionFactory::note_off((unsigned char)note_num)); } else { cerr << "WARNING: MIDI note number out of range, ignoring." << endl; } } else { cerr << "WARNING: Found note for unknown states. Ignoring." << endl; } } #endif /* Get edges */ for (Sord::Iter i = model.find(machine_node, 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); Sord::Iter p = model.find(edge, machina_probability, nil); Sord::Node tail = t.get_object(); Sord::Node head = h.get_object(); Sord::Node probability = p.get_object(); float prob = probability.to_float(); Created::iterator tail_i = created.find(tail); Created::iterator head_i = created.find(head); if (tail_i != created.end() && head_i != created.end()) { const SharedPtr tail = tail_i->second; const SharedPtr head = head_i->second; SharedPtr edge(new Edge(tail, head)); edge->set_probability(prob); tail->add_edge(edge); } else { cerr << "[Loader] WARNING: Ignored edge between unknown nodes " << tail << " -> " << head << endl; } } if (machine && machine->nodes().size() > 0) { machine->reset(machine->time()); return machine; } else { return SharedPtr(); } } } // namespace Machina