diff options
Diffstat (limited to 'src/engine')
-rw-r--r-- | src/engine/Machine.cpp | 42 | ||||
-rw-r--r-- | src/engine/MachineBuilder.cpp | 14 | ||||
-rw-r--r-- | src/engine/MachineMutation.cpp | 55 | ||||
-rw-r--r-- | src/engine/Makefile.am | 1 | ||||
-rw-r--r-- | src/engine/Node.cpp | 36 | ||||
-rw-r--r-- | src/engine/machina/Machine.hpp | 5 | ||||
-rw-r--r-- | src/engine/machina/MachineMutation.hpp | 37 | ||||
-rw-r--r-- | src/engine/machina/Makefile.am | 1 | ||||
-rw-r--r-- | src/engine/machina/Node.hpp | 24 | ||||
-rw-r--r-- | src/engine/machina/Schrodinbit.hpp | 45 |
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 + |