aboutsummaryrefslogtreecommitdiffstats
path: root/src/engine/Machine.cpp
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-02-10 01:44:16 +0000
committerDavid Robillard <d@drobilla.net>2007-02-10 01:44:16 +0000
commit9f2a520a8f20661385bf6c9f7447aef1227d8696 (patch)
tree1390784d2025a183715319c5ef78b4e2f729547d /src/engine/Machine.cpp
parent374f7e8f35e0205b056184c889b2caf5cdac08ec (diff)
downloadmachina-9f2a520a8f20661385bf6c9f7447aef1227d8696.tar.gz
machina-9f2a520a8f20661385bf6c9f7447aef1227d8696.tar.bz2
machina-9f2a520a8f20661385bf6c9f7447aef1227d8696.zip
Fix previous (broken) commit.
git-svn-id: http://svn.drobilla.net/lad/machina@296 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/engine/Machine.cpp')
-rw-r--r--src/engine/Machine.cpp224
1 files changed, 224 insertions, 0 deletions
diff --git a/src/engine/Machine.cpp b/src/engine/Machine.cpp
new file mode 100644
index 0000000..426ffd3
--- /dev/null
+++ b/src/engine/Machine.cpp
@@ -0,0 +1,224 @@
+/* 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 Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <algorithm>
+#include "machina/Machine.hpp"
+#include "machina/Node.hpp"
+#include "machina/Edge.hpp"
+
+namespace Machina {
+
+
+Machine::Machine()
+ : _is_activated(false)
+ , _is_finished(false)
+ , _time(0)
+{
+}
+
+
+Machine::~Machine()
+{
+}
+
+
+void
+Machine::add_node(SharedPtr<Node> node)
+{
+ assert(!_is_activated);
+
+ _nodes.push_back(node);
+}
+
+
+/** Exit all active states and reset time to 0.
+ */
+void
+Machine::reset()
+{
+ if (!_is_finished) {
+ for (Nodes::const_iterator n = _nodes.begin(); n != _nodes.end(); ++n) {
+ const SharedPtr<Node> node = (*n);
+
+ if (node->is_active())
+ node->exit(_time);
+ }
+ }
+
+ _time = 0;
+ _is_finished = false;
+}
+
+
+/** Return the active Node with the earliest exit time.
+ */
+SharedPtr<Node>
+Machine::earliest_node() const
+{
+ SharedPtr<Node> earliest;
+
+ for (Nodes::const_iterator n = _nodes.begin(); n != _nodes.end(); ++n) {
+ const SharedPtr<Node> node = (*n);
+
+ if (node->is_active())
+ if (!earliest || node->exit_time() < earliest->exit_time())
+ earliest = node;
+ }
+
+ return earliest;
+}
+
+
+/** Exit an active node at the current _time.
+ */
+void
+Machine::exit_node(const SharedPtr<Node> node)
+{
+ node->exit(_time);
+
+ // Activate all successors to this node
+ // (that aren't aready active right now)
+ for (Node::EdgeList::const_iterator s = node->outgoing_edges().begin();
+ s != node->outgoing_edges().end(); ++s) {
+ SharedPtr<Node> dst = (*s)->dst();
+
+ if (!dst->is_active())
+ dst->enter(_time);
+
+ }
+}
+
+
+/** Run the machine for @a nframes frames.
+ *
+ * Returns false when the machine has finished running (i.e. there are
+ * no currently active states).
+ *
+ * If this returns false, time() will return the exact time stamp the
+ * machine actually finished on (so it can be restarted immediately
+ * with sample accuracy if necessary).
+ */
+bool
+Machine::run(FrameCount nframes)
+{
+ if (_is_finished)
+ return false;
+
+ if (_nodes.size() == 0)
+ return true;
+
+ const FrameCount cycle_end = _time + nframes;
+
+ assert(_is_activated);
+
+ //std::cerr << "--------- " << _time << " - " << _time + nframes << std::endl;
+
+ // Initial run, enter all initial states
+ if (_time == 0)
+ for (Nodes::const_iterator n = _nodes.begin(); n != _nodes.end(); ++n)
+ if ((*n)->is_initial())
+ (*n)->enter(0);
+
+ while (true) {
+
+ SharedPtr<Node> earliest = earliest_node();
+
+ // No more active states, machine is finished
+ if (!earliest) {
+ _is_finished = true;
+ return false;
+
+ // Earliest active state ends this cycle
+ } else if (earliest->exit_time() < cycle_end) {
+ _time = earliest->exit_time();
+ exit_node(earliest);
+
+ // Earliest active state ends in the future, done this cycle
+ } else {
+ _time = cycle_end;
+ return true;
+ }
+
+ }
+
+#if 0
+ while (!done) {
+
+ done = true;
+
+ for (std::vector<Node*>::iterator i = _voices.begin();
+ i != _voices.end(); ++i) {
+
+ Node* const n = *i;
+
+ // Active voice which ends within this cycle, transition
+ if (n && n->is_active() && n->end_time() < cycle_end) {
+ // Guaranteed to be within this cycle
+ const FrameCount end_time = std::max(_time, n->end_time());
+ n->exit(std::max(_time, n->end_time()));
+ done = false;
+
+ // Greedily grab one of the successors with the voice already
+ // on this node so voices follow paths nicely
+ for (Node::EdgeList::const_iterator s = n->outgoing_edges().begin();
+ s != n->outgoing_edges().end(); ++s) {
+ Node* dst = (*s)->dst();
+ if (!dst->is_active()) {
+ dst->enter(end_time);
+ *i = dst;
+ break;
+ }
+ }
+
+ latest_event = end_time;
+ }
+
+ }
+
+ // FIXME: use free voices to claim any 'free successors'
+ // (when nodes have multiple successors and one gets chosen in the
+ // greedy bit above)
+
+ // If every voice is on the initial node...
+ bool is_reset = true;
+ for (std::vector<Node*>::iterator i = _voices.begin();
+ i != _voices.end(); ++i)
+ if ((*i) != NULL && (*i)->is_active())
+ is_reset = false;
+
+ // ... then start
+ if (is_reset) {
+
+ std::vector<Node*>::iterator n = _voices.begin();
+ for (Node::EdgeList::const_iterator s = _initial_node->outgoing_edges().begin();
+ s != _initial_node->outgoing_edges().end() && n != _voices.end();
+ ++s, ++n) {
+ (*s)->dst()->enter(latest_event);
+ done = false;
+ *n = (*s)->dst();
+ }
+ }
+ }
+ _time += nframes;
+
+ return false;
+#endif
+}
+
+
+} // namespace Machina
+