aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/engine/Engine.cpp14
-rw-r--r--src/engine/JackDriver.cpp45
-rw-r--r--src/engine/Loader.cpp66
-rw-r--r--src/engine/Machine.cpp6
-rw-r--r--src/engine/Node.cpp6
-rw-r--r--src/engine/machina/Engine.hpp4
-rw-r--r--src/engine/machina/JackDriver.hpp4
-rw-r--r--src/engine/machina/Machine.hpp4
-rw-r--r--src/engine/machina/Node.hpp6
-rw-r--r--src/gui/MachinaCanvas.cpp63
-rw-r--r--src/gui/MachinaCanvas.hpp4
-rw-r--r--src/gui/MachinaGUI.cpp19
12 files changed, 177 insertions, 64 deletions
diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp
index d659626..31c98f2 100644
--- a/src/engine/Engine.cpp
+++ b/src/engine/Engine.cpp
@@ -15,12 +15,26 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "machina/Loader.hpp"
#include "machina/Engine.hpp"
#include "machina/JackDriver.hpp"
namespace Machina {
+/** Load the machine at @a uri, and run it (replacing current machine).
+ * Safe to call while engine is processing.
+ */
+SharedPtr<Machine>
+Engine::load_machine(const Glib::ustring& uri)
+{
+ Loader l; // FIXME: namespaces?
+ SharedPtr<Machine> m = l.load(uri);
+ _machine = m;
+ return m;
+}
+
+
void
Engine::set_bpm(double bpm)
{
diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp
index 404d972..1056820 100644
--- a/src/engine/JackDriver.cpp
+++ b/src/engine/JackDriver.cpp
@@ -80,7 +80,7 @@ JackDriver::detach()
void
-JackDriver::process_input(const TimeSlice& time)
+JackDriver::process_input(SharedPtr<Machine> machine, const TimeSlice& time)
{
// We only actually read Jack input at the beginning of a cycle
assert(time.offset_ticks() == 0);
@@ -98,25 +98,25 @@ JackDriver::process_input(const TimeSlice& time)
if (ev.buffer[0] == 0x90) {
- const SharedPtr<LearnRequest> learn = _machine->pending_learn();
+ const SharedPtr<LearnRequest> learn = machine->pending_learn();
if (learn) {
learn->enter_action()->set_event(ev.size, ev.buffer);
cerr << "LEARN START\n";
learn->start(_quantization.get(),
time.ticks_to_beats(jack_last_frame_time(_client) + ev.time));
- //LearnRecord learn = _machine->pop_learn();
+ //LearnRecord learn = machine->pop_learn();
}
} else if (ev.buffer[0] == 0x80) {
- const SharedPtr<LearnRequest> learn = _machine->pending_learn();
+ const SharedPtr<LearnRequest> learn = machine->pending_learn();
if (learn) {
if (learn->started()) {
learn->exit_action()->set_event(ev.size, ev.buffer);
learn->finish(
time.ticks_to_beats(jack_last_frame_time(_client) + ev.time));
- _machine->clear_pending_learn();
+ machine->clear_pending_learn();
cerr << "LEARNED!\n";
}
}
@@ -158,33 +158,44 @@ JackDriver::write_event(Raul::BeatTime time,
void
JackDriver::on_process(jack_nframes_t nframes)
{
- using namespace std;
+ //using namespace std;
//std::cerr << "> ======================================================\n";
-
+
_cycle_time.set_bpm(_bpm.get());
- // Start time set at end of previous cycle
+ // (start time set at end of previous cycle)
_cycle_time.set_offset(0);
_cycle_time.set_length(nframes);
assert(_output_port);
jack_midi_clear_buffer(jack_port_get_buffer(_output_port, nframes), nframes);
+
+ /* Take a reference to machine here and use only it during the process
+ * cycle so _machine can be switched with set_machine during a cycle. */
+ SharedPtr<Machine> machine = _machine;
+
+ // Machine was switched since last cycle, finalize old machine.
+ if (_last_machine && machine != _last_machine) {
+ _last_machine->reset(); // Exit all active states
+ assert(_last_machine.use_count() > 1); // Realtime, can't delete
+ _last_machine.reset(); // Cut our reference
+ }
- process_input(_cycle_time);
+ process_input(machine, _cycle_time);
- if (_machine->is_empty()) {
+ if (machine->is_empty()) {
//cerr << "EMPTY\n";
return;
}
while (true) {
- const BeatCount run_dur_beats = _machine->run(_cycle_time);
+ const BeatCount run_dur_beats = machine->run(_cycle_time);
const TickCount run_dur_ticks = _cycle_time.beats_to_ticks(run_dur_beats);
// Machine didn't run at all (empty, or no initial states)
if (run_dur_ticks == 0) {
- _machine->reset(); // Try again next cycle
+ machine->reset(); // Try again next cycle
_cycle_time.set_start(0);
return;
@@ -193,7 +204,7 @@ JackDriver::on_process(jack_nframes_t nframes)
const TickCount finish_offset = _cycle_time.offset_ticks() + run_dur_ticks;
assert(finish_offset < nframes);
- _machine->reset();
+ machine->reset();
_cycle_time.set_start(0);
_cycle_time.set_length(nframes - finish_offset);
@@ -201,8 +212,8 @@ JackDriver::on_process(jack_nframes_t nframes)
// Machine ran for entire cycle
} else {
- if (_machine->is_finished()) {
- _machine->reset();
+ if (machine->is_finished()) {
+ machine->reset();
_cycle_time.set_start(0);
} else {
_cycle_time.set_start(
@@ -212,6 +223,10 @@ JackDriver::on_process(jack_nframes_t nframes)
break;
}
}
+
+ /* Remember the last machine run, in case a switch happens and
+ * we need to finalize it next cycle. */
+ _last_machine = machine;
//std::cerr << "< ======================================================\n";
}
diff --git a/src/engine/Loader.cpp b/src/engine/Loader.cpp
index ec884eb..078d783 100644
--- a/src/engine/Loader.cpp
+++ b/src/engine/Loader.cpp
@@ -17,6 +17,7 @@
#include <iostream>
#include <map>
+#include <cmath>
#include <raptor.h>
#include <rasqal.h>
#include <glibmm/ustring.h>
@@ -45,30 +46,33 @@ Loader::Loader(SharedPtr<Namespaces> namespaces)
/** Load (create) all objects from an RDF into the engine.
*
- * @param filename Filename to load objects from.
- * @param parent Path of parent under which to load objects.
- * @return whether or not load was successful.
+ * @param uri URI of machine (e.g. resolvable URI to an RDF document).
+ * @return Loaded Machine.
*/
SharedPtr<Machine>
-Loader::load(const Glib::ustring& filename)
+Loader::load(const Glib::ustring& uri)
{
using Raul::RDFQuery;
SharedPtr<Machine> machine;
rasqal_init();
- unsigned char* document_uri_str = raptor_uri_filename_to_uri_string(filename.c_str());
- assert(document_uri_str);
- raptor_uri* document_raptor_uri = raptor_new_uri(document_uri_str);
+ //unsigned char* document_uri_str = raptor_uri_filename_to_uri_string(filename.c_str());
+ //assert(document_uri_str);
+ //raptor_uri* document_raptor_uri = raptor_new_uri(document_uri_str);
+ raptor_uri* document_raptor_uri = raptor_new_uri((const unsigned char*)uri.c_str());
- if (!document_uri_str)
- return machine;
+ if (!document_raptor_uri)
+ return machine; // NULL
machine = SharedPtr<Machine>(new Machine());
- Glib::ustring document_uri = (const char*)document_uri_str;
+ //Glib::ustring document_uri = (const char*)document_uri_str;
+ const Glib::ustring& document_uri = uri;
- string machine_uri = "<> ";
+ //string machine_uri = "<> ";
+ //string machine_uri = string("<") + document_uri + "> ";
+ string machine_uri = "?foo ";
cout << "[Loader] Loading " << machine_uri << " from " << document_uri << endl;
@@ -79,18 +83,16 @@ Loader::load(const Glib::ustring& filename)
/* Get initial nodes */
Raul::RDFQuery query = Raul::RDFQuery(*_namespaces, Glib::ustring(
- "SELECT DISTINCT ?initialNode ?midiNote ?duration FROM <")
+ "SELECT DISTINCT ?initialNode ?duration FROM <")
+ document_uri + "> WHERE {\n" +
machine_uri + " :initialNode ?initialNode .\n"
- "?initialNode :midiNote ?midiNote ;\n"
- " :duration ?duration .\n"
+ "?initialNode :duration ?duration .\n"
"}\n");
RDFQuery::Results results = query.run(document_uri);
for (RDFQuery::Results::iterator i = results.begin(); i != results.end(); ++i) {
const Glib::ustring& node_uri = (*i)["initialNode"];
- const Glib::ustring& midi_note = (*i)["midiNote"];
const Glib::ustring& duration = (*i)["duration"];
raptor_uri* node_raptor_uri
@@ -99,7 +101,7 @@ Loader::load(const Glib::ustring& filename)
char* node_name = (char*)
raptor_uri_to_relative_uri_string(document_raptor_uri, node_raptor_uri);
- //cout << "Initial: " << node_name << ": " << midi_note << " - " << duration << endl;
+ cout << "Initial: " << node_name << " - " << duration << endl;
cerr << "FIXME: load\n";
/*
@@ -114,6 +116,10 @@ Loader::load(const Glib::ustring& filename)
created.insert(std::make_pair(node_uri.collate_key(), node));
*/
+
+ SharedPtr<Node> node(new Node(strtod(duration.c_str(), NULL), true));
+ machine->add_node(node);
+ created.insert(std::make_pair(node_uri.collate_key(), node));
raptor_free_uri(node_raptor_uri);
free(node_name);
@@ -123,18 +129,16 @@ Loader::load(const Glib::ustring& filename)
/* Get remaining nodes */
query = Raul::RDFQuery(*_namespaces, Glib::ustring(
- "SELECT DISTINCT ?node ?midiNote ?duration FROM <")
+ "SELECT DISTINCT ?node ?duration FROM <")
+ document_uri + "> WHERE {\n" +
machine_uri + " :node ?node .\n"
- "?node :midiNote ?midiNote ;\n"
- " :duration ?duration .\n"
+ "?node :duration ?duration .\n"
"}\n");
results = query.run(document_uri);
for (RDFQuery::Results::iterator i = results.begin(); i != results.end(); ++i) {
const Glib::ustring& node_uri = (*i)["node"];
- const Glib::ustring& midi_note = (*i)["midiNote"];
const Glib::ustring& duration = (*i)["duration"];
raptor_uri* node_raptor_uri
@@ -143,6 +147,7 @@ Loader::load(const Glib::ustring& filename)
char* node_name = (char*)
raptor_uri_to_relative_uri_string(document_raptor_uri, node_raptor_uri);
+ cout << "Node: " << node_name << " - " << duration << endl;
cerr << "FIXME: load (2)\n";
/*
@@ -159,6 +164,10 @@ Loader::load(const Glib::ustring& filename)
created.insert(std::make_pair(node_uri.collate_key(), node));
}
*/
+ SharedPtr<Node> node(new Node(strtod(duration.c_str(), NULL), true));
+ machine->add_node(node);
+ created.insert(std::make_pair(node_uri.collate_key(), node));
+
raptor_free_uri(node_raptor_uri);
free(node_name);
}
@@ -167,16 +176,19 @@ Loader::load(const Glib::ustring& filename)
/* Get edges */
query = Raul::RDFQuery(*_namespaces, Glib::ustring(
- "SELECT DISTINCT ?src ?edge ?dst FROM <")
+ "SELECT DISTINCT ?edge ?src ?dst ?prob FROM <")
+ document_uri + "> WHERE {\n" +
machine_uri + " :edge ?edge .\n"
- "?edge :tail ?src ;\n"
- " :head ?dst .\n }");
+ "?edge :tail ?src ;\n"
+ " :head ?dst ;\n"
+ " :probability ?prob .\n }");
+
results = query.run(document_uri);
for (RDFQuery::Results::iterator i = results.begin(); i != results.end(); ++i) {
const Glib::ustring& src_uri = (*i)["src"];
- const Glib::ustring& dst_uri = (*i)["dst"];
+ const Glib::ustring& dst_uri = (*i)["dst"];
+ double prob = strtod((*i)["prob"].c_str(), NULL);
Created::iterator src_i = created.find(src_uri.collate_key());
Created::iterator dst_i = created.find(dst_uri.collate_key());
@@ -185,7 +197,9 @@ Loader::load(const Glib::ustring& filename)
const SharedPtr<Node> src = src_i->second;
const SharedPtr<Node> dst = dst_i->second;
- src->add_outgoing_edge(SharedPtr<Edge>(new Edge(src, dst)));
+ SharedPtr<Edge> edge(new Edge(src, dst));
+ edge->set_probability(prob);
+ src->add_outgoing_edge(edge);
} else {
cerr << "[Loader] WARNING: Ignored edge between unknown nodes "
@@ -194,7 +208,7 @@ Loader::load(const Glib::ustring& filename)
}
- free(document_uri_str);
+ //free(document_uri_str);
raptor_free_uri(document_raptor_uri);
return machine;
diff --git a/src/engine/Machine.cpp b/src/engine/Machine.cpp
index 2d3358b..41335bc 100644
--- a/src/engine/Machine.cpp
+++ b/src/engine/Machine.cpp
@@ -92,7 +92,7 @@ Machine::exit_node(const SharedPtr<Node> node)
// Activate all successors to this node
// (that aren't aready active right now)
- for (Node::EdgeList::const_iterator s = node->outgoing_edges().begin();
+ for (Node::Edges::const_iterator s = node->outgoing_edges().begin();
s != node->outgoing_edges().end(); ++s) {
const double rand_normal = rand() / (double)RAND_MAX; // [0, 1]
@@ -211,7 +211,7 @@ Machine::write_state(Raul::RDFWriter& writer)
{
using Raul::RdfId;
- writer.add_prefix("machina", "http://drobilla.net/ns/machina");
+ writer.add_prefix("machina", "http://drobilla.net/ns/machina#");
writer.write(RdfId(RdfId::RESOURCE, ""),
RdfId(RdfId::RESOURCE, "rdf:type"),
@@ -225,7 +225,7 @@ Machine::write_state(Raul::RDFWriter& writer)
RdfId(RdfId::RESOURCE, "machina:node"),
(*n)->id());
- for (Node::EdgeList::const_iterator e = (*n)->outgoing_edges().begin();
+ for (Node::Edges::const_iterator e = (*n)->outgoing_edges().begin();
e != (*n)->outgoing_edges().end(); ++e) {
(*e)->write_state(writer);
diff --git a/src/engine/Node.cpp b/src/engine/Node.cpp
index 1b4fdee..ecb7a22 100644
--- a/src/engine/Node.cpp
+++ b/src/engine/Node.cpp
@@ -103,8 +103,8 @@ Node::remove_outgoing_edge(SharedPtr<Edge> edge)
void
Node::remove_outgoing_edges_to(SharedPtr<Node> node)
{
- for (EdgeList::iterator i = _outgoing_edges.begin(); i != _outgoing_edges.end() ; ) {
- EdgeList::iterator next = i;
+ for (Edges::iterator i = _outgoing_edges.begin(); i != _outgoing_edges.end() ; ) {
+ Edges::iterator next = i;
++next;
if ((*i)->dst() == node)
@@ -131,7 +131,7 @@ Node::write_state(Raul::RDFWriter& writer)
RdfId(RdfId::RESOURCE, "machina:duration"),
Raul::Atom((float)_duration));
- for (Node::EdgeList::const_iterator e = _outgoing_edges.begin();
+ for (Node::Edges::const_iterator e = _outgoing_edges.begin();
e != _outgoing_edges.end(); ++e)
(*e)->write_state(writer);
}
diff --git a/src/engine/machina/Engine.hpp b/src/engine/machina/Engine.hpp
index fcb75d3..cd4cf27 100644
--- a/src/engine/machina/Engine.hpp
+++ b/src/engine/machina/Engine.hpp
@@ -18,6 +18,7 @@
#ifndef MACHINA_ENGINE_HPP
#define MACHINA_ENGINE_HPP
+#include <glibmm/ustring.h>
#include <raul/SharedPtr.h>
namespace Machina {
@@ -36,8 +37,9 @@ public:
SharedPtr<JackDriver> driver() { return _driver; }
SharedPtr<Machine> machine() { return _machine; }
+ SharedPtr<Machine> load_machine(const Glib::ustring& uri);
+
void set_bpm(double bpm);
-
void set_quantization(double beat_fraction);
private:
diff --git a/src/engine/machina/JackDriver.hpp b/src/engine/machina/JackDriver.hpp
index 1f9b197..f78c1f1 100644
--- a/src/engine/machina/JackDriver.hpp
+++ b/src/engine/machina/JackDriver.hpp
@@ -55,10 +55,12 @@ public:
void set_quantization(double quantization) { _quantization.set(quantization); }
private:
- void process_input(const Raul::TimeSlice& time);
+ void process_input(SharedPtr<Machine> machine,
+ const Raul::TimeSlice& time);
virtual void on_process(jack_nframes_t nframes);
SharedPtr<Machine> _machine;
+ SharedPtr<Machine> _last_machine;
jack_port_t* _input_port;
jack_port_t* _output_port;
diff --git a/src/engine/machina/Machine.hpp b/src/engine/machina/Machine.hpp
index a7b92c8..7b71d01 100644
--- a/src/engine/machina/Machine.hpp
+++ b/src/engine/machina/Machine.hpp
@@ -58,8 +58,10 @@ public:
SharedPtr<LearnRequest> pending_learn() { return _pending_learn; }
void clear_pending_learn() { _pending_learn.reset(); }
-private:
typedef Raul::List<SharedPtr<Node> > Nodes;
+ const Nodes& nodes() { return _nodes; }
+
+private:
// Audio context
SharedPtr<Node> earliest_node() const;
diff --git a/src/engine/machina/Node.hpp b/src/engine/machina/Node.hpp
index 7573e39..569a54e 100644
--- a/src/engine/machina/Node.hpp
+++ b/src/engine/machina/Node.hpp
@@ -69,8 +69,8 @@ public:
BeatCount duration() { return _duration; }
void set_duration(BeatCount d) { _duration = d; }
- typedef Raul::List<SharedPtr<Edge> > EdgeList;
- const EdgeList& outgoing_edges() const { return _outgoing_edges; }
+ typedef Raul::List<SharedPtr<Edge> > Edges;
+ const Edges& outgoing_edges() const { return _outgoing_edges; }
private:
bool _is_initial;
@@ -79,7 +79,7 @@ private:
BeatCount _duration;
SharedPtr<Action> _enter_action;
SharedPtr<Action> _exit_action;
- EdgeList _outgoing_edges;
+ Edges _outgoing_edges;
};
diff --git a/src/gui/MachinaCanvas.cpp b/src/gui/MachinaCanvas.cpp
index 03a05bc..878e790 100644
--- a/src/gui/MachinaCanvas.cpp
+++ b/src/gui/MachinaCanvas.cpp
@@ -46,11 +46,9 @@ MachinaCanvas::status_message(const string& msg)
void
-MachinaCanvas::node_clicked(SharedPtr<NodeView> item, GdkEventButton* event)
+MachinaCanvas::node_clicked(WeakPtr<NodeView> item, GdkEventButton* event)
{
- cerr << "CLICKED: " << item->name() << endl;
-
- SharedPtr<NodeView> node = PtrCast<NodeView>(item);
+ SharedPtr<NodeView> node = PtrCast<NodeView>(item.lock());
if (!node)
return;
@@ -101,10 +99,8 @@ MachinaCanvas::canvas_event(GdkEvent* event)
SharedPtr<NodeView> view(new NodeView(node, shared_from_this(),
name, x, y));
- //view->signal_clicked.connect(sigc::bind(sigc::mem_fun(this,
- // &MachinaCanvas::node_clicked), view));
view->signal_clicked.connect(sigc::bind<0>(sigc::mem_fun(this,
- &MachinaCanvas::node_clicked), view));
+ &MachinaCanvas::node_clicked), WeakPtr<NodeView>(view)));
add_item(view);
view->resize();
view->raise_to_top();
@@ -173,3 +169,56 @@ MachinaCanvas::disconnect_node(boost::shared_ptr<NodeView> src,
}
+void
+MachinaCanvas::build(SharedPtr<Machina::Machine> machine)
+{
+ destroy();
+
+ for (Machina::Machine::Nodes::const_iterator i = machine->nodes().begin();
+ i != machine->nodes().end(); ++i) {
+
+ const double x = 1600 + rand() % 300;
+ const double y = 1200 + rand() % 300;
+
+ SharedPtr<NodeView> view(new NodeView((*i), shared_from_this(),
+ "", x, y));
+
+ view->signal_clicked.connect(sigc::bind<0>(sigc::mem_fun(this,
+ &MachinaCanvas::node_clicked), WeakPtr<NodeView>(view)));
+
+ add_item(view);
+ view->resize();
+ }
+
+ for (ItemMap::iterator n = _items.begin(); n != _items.end(); ++n) {
+
+ SharedPtr<NodeView> src = PtrCast<NodeView>(n->second);
+ if (!src)
+ continue;
+
+ for (Machina::Node::Edges::const_iterator e = src->node()->outgoing_edges().begin();
+ e != src->node()->outgoing_edges().end(); ++e) {
+
+ SharedPtr<NodeView> dst;
+ for (ItemMap::iterator m = _items.begin(); m != _items.end(); ++m) {
+ SharedPtr<NodeView> nv = PtrCast<NodeView>((*m).second);
+ if (nv && nv->node() == (*e)->dst()) {
+ dst = nv;
+ break;
+ }
+ }
+
+ if (dst) {
+ boost::shared_ptr<Connection> c(new EdgeView(shared_from_this(),
+ src, dst, (*e)));
+ src->add_connection(c);
+ dst->add_connection(c);
+ add_connection(c);
+ }
+
+ }
+ }
+
+}
+
+
diff --git a/src/gui/MachinaCanvas.hpp b/src/gui/MachinaCanvas.hpp
index 361e154..feead3e 100644
--- a/src/gui/MachinaCanvas.hpp
+++ b/src/gui/MachinaCanvas.hpp
@@ -42,10 +42,12 @@ public:
void status_message(const string& msg);
+ void build(SharedPtr<Machina::Machine> machine);
+
protected:
bool canvas_event(GdkEvent* event);
- void node_clicked(SharedPtr<NodeView> item, GdkEventButton* ev);
+ void node_clicked(WeakPtr<NodeView> item, GdkEventButton* ev);
private:
MachinaGUI* _app;
diff --git a/src/gui/MachinaGUI.cpp b/src/gui/MachinaGUI.cpp
index 77dcbc5..3dd0c96 100644
--- a/src/gui/MachinaGUI.cpp
+++ b/src/gui/MachinaGUI.cpp
@@ -351,8 +351,21 @@ MachinaGUI::menu_file_quit()
void
MachinaGUI::menu_file_open()
{
- cerr << "open\n";
+ Gtk::FileChooserDialog dialog(*_main_window, "Open Machine", Gtk::FILE_CHOOSER_ACTION_OPEN);
+
+ dialog.set_local_only(false);
+
+ dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+ dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
+ const int result = dialog.run();
+
+ if (result == Gtk::RESPONSE_OK) {
+ SharedPtr<Machina::Machine> new_machine = _engine->load_machine(dialog.get_uri());
+ _canvas->destroy();
+ _canvas->build(new_machine);
+ _save_filename = dialog.get_filename();
+ }
}
@@ -387,8 +400,8 @@ MachinaGUI::menu_file_save_as()
if (result == Gtk::RESPONSE_OK) {
string filename = dialog.get_filename();
- if (filename.length() < 12 || filename.substr(filename.length()-12) != ".machina.ttl")
- filename += ".machina.ttl";
+ if (filename.length() < 8 || filename.substr(filename.length()-8) != ".machina")
+ filename += ".machina";
bool confirm = false;
std::fstream fin;