aboutsummaryrefslogtreecommitdiffstats
path: root/src/engine
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/Machine.cpp42
-rw-r--r--src/engine/MachineBuilder.cpp14
-rw-r--r--src/engine/MachineMutation.cpp55
-rw-r--r--src/engine/Makefile.am1
-rw-r--r--src/engine/Node.cpp36
-rw-r--r--src/engine/machina/Machine.hpp5
-rw-r--r--src/engine/machina/MachineMutation.hpp37
-rw-r--r--src/engine/machina/Makefile.am1
-rw-r--r--src/engine/machina/Node.hpp24
-rw-r--r--src/engine/machina/Schrodinbit.hpp45
10 files changed, 223 insertions, 37 deletions
diff --git a/src/engine/Machine.cpp b/src/engine/Machine.cpp
index 2033b5e..7a99b58 100644
--- a/src/engine/Machine.cpp
+++ b/src/engine/Machine.cpp
@@ -53,6 +53,34 @@ Machine::set_sink(SharedPtr<Raul::MIDISink> sink)
{
_sink = sink;
}
+
+
+/** Always returns a node, unless there are none */
+SharedPtr<Node>
+Machine::random_node()
+{
+ size_t i = rand() % _nodes.size();
+
+ // FIXME: O(n) worst case :(
+ for (Nodes::const_iterator n = _nodes.begin(); n != _nodes.end(); ++n, --i)
+ if (i == 0)
+ return *n;
+
+ return SharedPtr<Node>();
+}
+
+
+/** May return NULL even if edges exist (with low probability) */
+SharedPtr<Edge>
+Machine::random_edge()
+{
+ SharedPtr<Node> tail = random_node();
+
+ for (size_t i = 0; i < _nodes.size() && tail->edges().empty(); ++i)
+ tail = random_node();
+
+ return tail->random_edge();
+}
void
@@ -69,7 +97,7 @@ Machine::remove_node(SharedPtr<Node> node)
_nodes.erase(_nodes.find(node));
for (Nodes::const_iterator n = _nodes.begin(); n != _nodes.end(); ++n)
- (*n)->remove_outgoing_edges_to(node);
+ (*n)->remove_edges_to(node);
}
@@ -170,8 +198,8 @@ Machine::exit_node(SharedPtr<Raul::MIDISink> sink, const SharedPtr<Node> node)
const double rand_normal = rand() / (double)RAND_MAX; // [0, 1]
double range_min = 0;
- for (Node::Edges::const_iterator s = node->outgoing_edges().begin();
- s != node->outgoing_edges().end(); ++s) {
+ for (Node::Edges::const_iterator s = node->edges().begin();
+ s != node->edges().end(); ++s) {
if (!(*s)->head()->is_active()
&& rand_normal > range_min
@@ -187,8 +215,8 @@ Machine::exit_node(SharedPtr<Raul::MIDISink> sink, const SharedPtr<Node> node)
} else {
- for (Node::Edges::const_iterator s = node->outgoing_edges().begin();
- s != node->outgoing_edges().end(); ++s) {
+ for (Node::Edges::const_iterator s = node->edges().begin();
+ s != node->edges().end(); ++s) {
const double rand_normal = rand() / (double)RAND_MAX; // [0, 1]
@@ -328,8 +356,8 @@ Machine::write_state(Redland::Model& model)
for (Nodes::const_iterator n = _nodes.begin(); n != _nodes.end(); ++n) {
- for (Node::Edges::const_iterator e = (*n)->outgoing_edges().begin();
- e != (*n)->outgoing_edges().end(); ++e) {
+ for (Node::Edges::const_iterator e = (*n)->edges().begin();
+ e != (*n)->edges().end(); ++e) {
(*e)->write_state(model);
diff --git a/src/engine/MachineBuilder.cpp b/src/engine/MachineBuilder.cpp
index 1830ee6..fd53487 100644
--- a/src/engine/MachineBuilder.cpp
+++ b/src/engine/MachineBuilder.cpp
@@ -91,7 +91,7 @@ MachineBuilder::connect_nodes(SharedPtr<Machine> m,
SharedPtr<Node> delay_node;
- if (is_delay_node(tail) && tail->outgoing_edges().size() == 0) {
+ if (is_delay_node(tail) && tail->edges().size() == 0) {
// Tail is a delay node, just accumulate the time difference into it
set_node_duration(tail, tail->duration() + head_start_time - tail_end_time);
tail->add_outgoing_edge(SharedPtr<Edge>(new Edge(tail, head)));
@@ -133,7 +133,7 @@ MachineBuilder::event(Raul::BeatTime time_offset,
// Results in patterns closes to what a human would choose
if ( ! _poly_nodes.empty()) {
for (PolyList::iterator j = _poly_nodes.begin(); j != _poly_nodes.end(); ++j) {
- if (j->second->outgoing_edges().empty()) {
+ if (j->second->edges().empty()) {
this_connect_node = j->second;
this_connect_node_end_time = j->first + j->second->duration();
break;
@@ -194,7 +194,7 @@ MachineBuilder::event(Raul::BeatTime time_offset,
for (PolyList::iterator j = _poly_nodes.begin(); j != _poly_nodes.end(); ++j) {
_machine->add_node(j->second);
- if (j->second->outgoing_edges().size() == 0)
+ if (j->second->edges().size() == 0)
connect_nodes(_machine, j->second, j->first + j->second->duration(),
_connect_node, t);
}
@@ -207,11 +207,11 @@ MachineBuilder::event(Raul::BeatTime time_offset,
// Trim useless delay node if possible (these appear after poly sections)
if (is_delay_node(_connect_node) && _connect_node->duration() == 0
- && _connect_node->outgoing_edges().size() == 1
- && (*_connect_node->outgoing_edges().begin())->head() == resolved) {
+ && _connect_node->edges().size() == 1
+ && (*_connect_node->edges().begin())->head() == resolved) {
- _connect_node->outgoing_edges().clear();
- assert(_connect_node->outgoing_edges().empty());
+ _connect_node->edges().clear();
+ assert(_connect_node->edges().empty());
_connect_node->set_enter_action(resolved->enter_action());
_connect_node->set_exit_action(resolved->exit_action());
resolved->set_enter_action(SharedPtr<Action>());
diff --git a/src/engine/MachineMutation.cpp b/src/engine/MachineMutation.cpp
new file mode 100644
index 0000000..6e98ee0
--- /dev/null
+++ b/src/engine/MachineMutation.cpp
@@ -0,0 +1,55 @@
+/* This file is part of Machina.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * 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 2 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 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 <iostream>
+#include <cstdlib>
+#include "machina/Edge.hpp"
+#include "machina/Machine.hpp"
+#include "machina/MachineMutation.hpp"
+
+using namespace std;
+
+namespace Machina {
+namespace Mutation {
+
+
+void
+AddEdge::mutate(Machine& machine)
+{
+ cout << "ADD" << endl;
+}
+
+
+void
+RemoveEdge::mutate(Machine& machine)
+{
+ cout << "REMOVE" << endl;
+}
+
+
+void
+AdjustEdge::mutate(Machine& machine)
+{
+ SharedPtr<Edge> edge = machine.random_edge();
+ if (edge)
+ edge->set_probability(rand() / (float)RAND_MAX);
+}
+
+
+} // namespace Mutation
+} // namespace Machina
+
diff --git a/src/engine/Makefile.am b/src/engine/Makefile.am
index 5e291c7..010affa 100644
--- a/src/engine/Makefile.am
+++ b/src/engine/Makefile.am
@@ -10,6 +10,7 @@ libmachina_la_SOURCES = \
Edge.cpp \
Action.cpp \
Machine.cpp \
+ MachineMutation.cpp \
Loader.cpp \
MidiAction.cpp \
ActionFactory.cpp \
diff --git a/src/engine/Node.cpp b/src/engine/Node.cpp
index 5a1ca85..fd784e5 100644
--- a/src/engine/Node.cpp
+++ b/src/engine/Node.cpp
@@ -35,6 +35,28 @@ Node::Node(BeatCount duration, bool initial)
}
+/** Always returns an edge, unless there are none */
+SharedPtr<Edge>
+Node::random_edge()
+{
+ SharedPtr<Edge> ret;
+ if (_edges.empty())
+ return ret;
+
+ size_t i = rand() % _edges.size();
+
+ // FIXME: O(n) worst case :(
+ for (Edges::const_iterator e = _edges.begin(); e != _edges.end(); ++e, --i) {
+ if (i == 0) {
+ ret = *e;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+
void
Node::set_selector(bool yn)
{
@@ -42,10 +64,10 @@ Node::set_selector(bool yn)
if (yn) {
double prob_sum = 0;
- for (Edges::iterator i = _outgoing_edges.begin(); i != _outgoing_edges.end(); ++i)
+ for (Edges::iterator i = _edges.begin(); i != _edges.end(); ++i)
prob_sum += (*i)->probability();
- for (Edges::iterator i = _outgoing_edges.begin(); i != _outgoing_edges.end(); ++i)
+ for (Edges::iterator i = _edges.begin(); i != _edges.end(); ++i)
(*i)->set_probability((*i)->probability() / prob_sum);
}
_changed = true;
@@ -101,26 +123,26 @@ Node::add_outgoing_edge(SharedPtr<Edge> edge)
{
assert(edge->tail().lock().get() == this);
- _outgoing_edges.push_back(edge);
+ _edges.push_back(edge);
}
void
Node::remove_outgoing_edge(SharedPtr<Edge> edge)
{
- _outgoing_edges.erase(_outgoing_edges.find(edge));
+ _edges.erase(_edges.find(edge));
}
void
-Node::remove_outgoing_edges_to(SharedPtr<Node> node)
+Node::remove_edges_to(SharedPtr<Node> node)
{
- for (Edges::iterator i = _outgoing_edges.begin(); i != _outgoing_edges.end() ; ) {
+ for (Edges::iterator i = _edges.begin(); i != _edges.end() ; ) {
Edges::iterator next = i;
++next;
if ((*i)->head() == node)
- _outgoing_edges.erase(i);
+ _edges.erase(i);
i = next;
}
diff --git a/src/engine/machina/Machine.hpp b/src/engine/machina/Machine.hpp
index 626ef10..889dc1a 100644
--- a/src/engine/machina/Machine.hpp
+++ b/src/engine/machina/Machine.hpp
@@ -61,9 +61,12 @@ public:
SharedPtr<LearnRequest> pending_learn() { return _pending_learn; }
void clear_pending_learn() { _pending_learn.reset(); }
- typedef Raul::List<SharedPtr<Node> > Nodes;
+ typedef Raul::List< SharedPtr<Node> > Nodes;
Nodes& nodes() { return _nodes; }
+ SharedPtr<Node> random_node();
+ SharedPtr<Edge> random_edge();
+
void set_sink(SharedPtr<Raul::MIDISink> sink);
private:
diff --git a/src/engine/machina/MachineMutation.hpp b/src/engine/machina/MachineMutation.hpp
new file mode 100644
index 0000000..34eda30
--- /dev/null
+++ b/src/engine/machina/MachineMutation.hpp
@@ -0,0 +1,37 @@
+/* This file is part of Machina.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * 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 2 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 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 MACHINA_MACHINE_MUTATION_HPP
+#define MACHINA_MACHINE_MUTATION_HPP
+
+namespace Machina {
+
+class Machine;
+
+namespace Mutation {
+
+struct Mutation { virtual void mutate(Machine& machine) = 0; };
+
+struct AddEdge { static void mutate(Machine& machine); };
+struct RemoveEdge { static void mutate(Machine& machine); };
+struct AdjustEdge { static void mutate(Machine& machine); };
+
+} // namespace Mutation
+
+} // namespace Machina
+
+#endif // MACHINA_MACHINE_MUTATION_HPP
diff --git a/src/engine/machina/Makefile.am b/src/engine/machina/Makefile.am
index 65ea295..de99845 100644
--- a/src/engine/machina/Makefile.am
+++ b/src/engine/machina/Makefile.am
@@ -11,6 +11,7 @@ libmachinainclude_HEADERS = \
Loader.hpp \
Machine.hpp \
MachineBuilder.hpp \
+ MachineMutation.hpp \
MidiAction.hpp \
Node.hpp \
Recorder.hpp \
diff --git a/src/engine/machina/Node.hpp b/src/engine/machina/Node.hpp
index 041f443..a916eb6 100644
--- a/src/engine/machina/Node.hpp
+++ b/src/engine/machina/Node.hpp
@@ -24,6 +24,7 @@
#include <raul/Stateful.hpp>
#include <raul/MIDISink.hpp>
#include "Action.hpp"
+#include "Schrodinbit.hpp"
namespace Machina {
@@ -57,7 +58,7 @@ public:
void add_outgoing_edge(SharedPtr<Edge> edge);
void remove_outgoing_edge(SharedPtr<Edge> edge);
- void remove_outgoing_edges_to(SharedPtr<Node> node);
+ void remove_edges_to(SharedPtr<Node> node);
void write_state(Redland::Model& model);
@@ -71,23 +72,16 @@ public:
bool is_selector() const { return _is_selector; }
void set_selector(bool i);
- /// Schroedinger's flag
- inline bool changed() {
- if (_changed) {
- _changed = false;
- return true;
- } else {
- return false;
- }
- }
-
- void set_changed() { _changed = true; }
+ inline bool changed() { return _changed; }
+ inline void set_changed() { _changed = true; }
typedef Raul::List<SharedPtr<Edge> > Edges;
- Edges& outgoing_edges() { return _outgoing_edges; }
+ Edges& edges() { return _edges; }
+
+ SharedPtr<Edge> random_edge();
private:
- bool _changed;
+ Schrodinbit _changed;
bool _is_initial;
bool _is_selector;
bool _is_active;
@@ -95,7 +89,7 @@ private:
BeatCount _duration;
SharedPtr<Action> _enter_action;
SharedPtr<Action> _exit_action;
- Edges _outgoing_edges;
+ Edges _edges;
};
diff --git a/src/engine/machina/Schrodinbit.hpp b/src/engine/machina/Schrodinbit.hpp
new file mode 100644
index 0000000..6065cfc
--- /dev/null
+++ b/src/engine/machina/Schrodinbit.hpp
@@ -0,0 +1,45 @@
+/* This file is part of Machina.
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * 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 2 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 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 SCHRODINBIT_HPP
+#define SCHRODINBIT_HPP
+
+
+/** A flag which becomes false when it's value is observed
+ */
+class Schrodinbit {
+public:
+ Schrodinbit() : _flag(false) {}
+
+ inline operator bool() {
+ const bool ret = _flag;
+ _flag = false;
+ return ret;
+ }
+
+ inline bool operator=(bool flag) {
+ _flag = flag;
+ return flag;
+ }
+
+private:
+ bool _flag;
+};
+
+
+#endif // SCHRODINBIT_HPP
+