/* This file is part of Machina. * Copyright (C) 2007-2009 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(Redland::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) { raptor_uri* base_uri = raptor_new_uri((const unsigned char*)"file:."); raptor_uri* document_raptor_uri = raptor_new_uri_relative_to_base( base_uri, (const unsigned char*)uri.c_str()); if (document_raptor_uri) { document_uri = (char*)raptor_uri_as_string(document_raptor_uri); raptor_free_uri(document_raptor_uri); raptor_free_uri(base_uri); } else { raptor_free_uri(base_uri); return machine; // NULL } } 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; Redland::Model model(_rdf_world, document_uri); model.load_file(document_uri); Redland::Node nil; Redland::Resource rdf_type(_rdf_world, NS_RDF "type"); Redland::Resource machina_SelectorNode(_rdf_world, NS_MACHINA "initialNode"); Redland::Resource machina_node(_rdf_world, NS_MACHINA "node"); Redland::Resource machina_initialNode(_rdf_world, NS_MACHINA "initialNode"); Redland::Resource machina_duration(_rdf_world, NS_MACHINA "duration"); Redland::Resource machina_edge(_rdf_world, NS_MACHINA "edge"); Redland::Resource machina_tail(_rdf_world, NS_MACHINA "tail"); Redland::Resource machina_head(_rdf_world, NS_MACHINA "head"); Redland::Resource machina_probability(_rdf_world, NS_MACHINA "probability"); Redland::Node machine_node = Redland::Resource(_rdf_world, "."); /* Get initial nodes */ for (Redland::Iter i = model.find(machine_node, machina_initialNode, nil); !i.end(); ++i) { const Redland::Node& node_id = i.get_object(); Redland::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)); Redland::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 (Redland::Iter i = model.find(machine_node, machina_node, nil); !i.end(); ++i) { const Redland::Node& node_id = i.get_object(); Redland::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 (Redland::Iter i = model.find(machine_node, machina_edge, nil); !i.end(); ++i) { Redland::Node edge = i.get_object(); Redland::Iter t = model.find(edge, machina_tail, nil); Redland::Iter h = model.find(edge, machina_head, nil); Redland::Iter p = model.find(edge, machina_probability, nil); Redland::Node tail = t.get_object(); Redland::Node head = h.get_object(); Redland::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