aboutsummaryrefslogtreecommitdiffstats
path: root/src/engine
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/JackDriver.cpp87
-rw-r--r--src/engine/JackNodeFactory.cpp10
-rw-r--r--src/engine/Machine.cpp114
-rw-r--r--src/engine/MidiAction.cpp27
-rw-r--r--src/engine/Node.cpp19
-rw-r--r--src/engine/machina/Action.hpp5
-rw-r--r--src/engine/machina/JackDriver.hpp8
-rw-r--r--src/engine/machina/Machine.hpp16
-rw-r--r--src/engine/machina/Makefile.am3
-rw-r--r--src/engine/machina/MidiAction.hpp22
-rw-r--r--src/engine/machina/Node.hpp22
11 files changed, 186 insertions, 147 deletions
diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp
index ff78520..fefa4d2 100644
--- a/src/engine/JackDriver.cpp
+++ b/src/engine/JackDriver.cpp
@@ -16,6 +16,7 @@
*/
#include <iostream>
+#include <iomanip>
#include "machina/JackDriver.hpp"
#include "machina/MidiAction.hpp"
@@ -34,18 +35,24 @@ JackDriver::JackDriver()
void
JackDriver::attach(const std::string& client_name)
{
- Raul::JackDriver::attach(client_name, "debug");
+ Raul::JackDriver::attach(client_name);
if (jack_client()) {
_input_port = jack_port_register(jack_client(),
- "out",
+ "in",
JACK_DEFAULT_MIDI_TYPE, JackPortIsInput,
0);
+
+ if (!_input_port)
+ std:: cerr << "WARNING: Failed to create MIDI input port." << std::endl;
_output_port = jack_port_register(jack_client(),
"out",
JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput,
0);
+
+ if (!_output_port)
+ std::cerr << "WARNING: Failed to create MIDI output port." << std::endl;
}
}
@@ -74,17 +81,10 @@ JackDriver::stamp_to_offset(Timestamp stamp)
void
-JackDriver::learn(SharedPtr<Node> node)
-{
- _learn_enter_action = SharedPtr<MidiAction>(new MidiAction(shared_from_this(), 4, NULL));
- _learn_exit_action = SharedPtr<MidiAction>(new MidiAction(shared_from_this(), 4, NULL));
- _learn_node = node;
-}
-
-
-void
JackDriver::process_input(jack_nframes_t nframes)
{
+ using namespace std;
+
//if (_learn_node) {
void* jack_buffer = jack_port_get_buffer(_input_port, nframes);
const jack_nframes_t event_count = jack_midi_get_event_count(jack_buffer, nframes);
@@ -93,7 +93,33 @@ JackDriver::process_input(jack_nframes_t nframes)
jack_midi_event_t ev;
jack_midi_event_get(&ev, jack_buffer, i, nframes);
- std::cerr << "EVENT: " << (char)ev.buffer[0] << "\n";
+ if (ev.buffer[0] == 0x90) {
+ cerr << "NOTE ON\n";
+
+ const SharedPtr<LearnRequest> learn = _machine->pending_learn();
+ if (learn) {
+ learn->enter_action()->set_event(ev.size, ev.buffer);
+ cerr << "LEARN START\n";
+ learn->start(jack_last_frame_time(_client) + ev.time);
+ //LearnRecord learn = _machine->pop_learn();
+ }
+
+ } else if (ev.buffer[0] == 0x80) {
+ cerr << "NOTE OFF\n";
+
+ const SharedPtr<LearnRequest> learn = _machine->pending_learn();
+
+ if (learn) {
+ if (learn->started()) {
+ learn->exit_action()->set_event(ev.size, ev.buffer);
+ learn->finish(jack_last_frame_time(_client) + ev.time);
+ _machine->clear_pending_learn();
+ cerr << "LEARNED!\n";
+ }
+ }
+ }
+
+ //std::cerr << "EVENT: " << std::hex << (int)ev.buffer[0] << "\n";
}
//}
@@ -108,6 +134,7 @@ JackDriver::write_event(Timestamp time,
const FrameCount nframes = _current_cycle_nframes;
const FrameCount offset = stamp_to_offset(time);
+ assert(_output_port);
jack_midi_event_write(
jack_port_get_buffer(_output_port, nframes), offset,
event, size, nframes);
@@ -117,25 +144,35 @@ JackDriver::write_event(Timestamp time,
void
JackDriver::on_process(jack_nframes_t nframes)
{
- //std::cerr << "======================================================\n";
+ using namespace std;
+ //std::cerr << "> ======================================================\n";
_current_cycle_offset = 0;
_current_cycle_nframes = nframes;
+ assert(_output_port);
jack_midi_clear_buffer(jack_port_get_buffer(_output_port, nframes), nframes);
+ process_input(nframes);
+
+ if (_machine->is_empty()) {
+ //cerr << "EMPTY\n";
+ return;
+ }
+
while (true) {
- bool machine_done = ! _machine->run(_current_cycle_nframes);
+ const FrameCount run_duration = _machine->run(_current_cycle_nframes);
- if (machine_done && _machine->is_finished())
+ // Machine didn't run at all (empty, or no initial states)
+ if (run_duration == 0) {
+ _machine->reset(); // Try again next cycle
+ _current_cycle_start = 0;
return;
+ }
- if (!machine_done) {
- _current_cycle_start += _current_cycle_nframes;
- break;
-
- } else {
+ // Machine ran for portion of cycle
+ else if (run_duration < _current_cycle_nframes) {
const Timestamp finish_time = _machine->time();
const FrameCount finish_offset = stamp_to_offset(finish_time);
@@ -146,10 +183,18 @@ JackDriver::on_process(jack_nframes_t nframes)
_current_cycle_nframes -= _current_cycle_offset;
_current_cycle_start = 0;
_machine->reset();
+
+ // Machine ran for entire cycle
+ } else {
+ if (_machine->is_finished())
+ _machine->reset();
+
+ _current_cycle_start += _current_cycle_nframes;
+ break;
}
}
- //std::cerr << "======================================================\n";
+ //std::cerr << "< ======================================================\n";
}
diff --git a/src/engine/JackNodeFactory.cpp b/src/engine/JackNodeFactory.cpp
index ac99422..55c7ff2 100644
--- a/src/engine/JackNodeFactory.cpp
+++ b/src/engine/JackNodeFactory.cpp
@@ -28,19 +28,19 @@ JackNodeFactory::create_node(Node::ID, byte note, FrameCount duration)
{
// FIXME: obviously leaks like a sieve
- size_t event_size = 3;
- static const byte note_on[3] = { 0x80, note, 0x40 };
+ //size_t event_size = 3;
+ //static const byte note_on[3] = { 0x80, note, 0x40 };
Node* n = new Node(duration);
- MidiAction* a_enter = new MidiAction(_driver, event_size, note_on);
+ /*SharedPtr<MidiAction> a_enter = MidiAction::create(event_size, note_on);
static const byte note_off[3] = { 0x90, note, 0x40 };
- MidiAction* a_exit = new MidiAction(_driver, event_size, note_off);
+ SharedPtr<MidiAction> a_exit = MidiAction::create(event_size, note_off);
n->add_enter_action(a_enter);
n->add_exit_action(a_exit);
-
+*/
return SharedPtr<Node>(n);
}
diff --git a/src/engine/Machine.cpp b/src/engine/Machine.cpp
index 3f28414..476e3d1 100644
--- a/src/engine/Machine.cpp
+++ b/src/engine/Machine.cpp
@@ -15,10 +15,11 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
-#include <algorithm>
+#include "raul/SharedPtr.h"
#include "machina/Machine.hpp"
#include "machina/Node.hpp"
#include "machina/Edge.hpp"
+#include "machina/MidiAction.hpp"
namespace Machina {
@@ -103,25 +104,27 @@ Machine::exit_node(const SharedPtr<Node> node)
/** 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
+ * Returns the duration of time the machine actually ran (from 0 to nframes).
+ * Caller can check is_finished() to determine if the machine still has any
+ * active states. If not, time() will return the exact time stamp the
* machine actually finished on (so it can be restarted immediately
* with sample accuracy if necessary).
*/
-bool
+FrameCount
Machine::run(FrameCount nframes)
{
- if (_is_finished)
- return false;
+ using namespace std;
+ if (_is_finished) {
+ cerr << "FINISHED\n";
+ return 0;
+ }
const FrameCount cycle_end = _time + nframes;
+ //std::cerr << "Start: " << _time << std::endl;
+
assert(_is_activated);
- //std::cerr << "--------- " << _time << " - " << _time + nframes << std::endl;
-
// Initial run, enter all initial states
if (_time == 0) {
bool entered = false;
@@ -131,16 +134,19 @@ Machine::run(FrameCount nframes)
(*n)->enter(0);
entered = true;
} else {
- (*n)->exit(0);
+ if ((*n)->is_active())
+ (*n)->exit(0);
}
}
}
if (!entered) {
- _is_finished = false; // run next time
- return false; // but done this cycle
+ _is_finished = true;
+ return 0;
}
}
+ FrameCount this_time = 0;
+
while (true) {
SharedPtr<Node> earliest = earliest_node();
@@ -148,83 +154,45 @@ Machine::run(FrameCount nframes)
// No more active states, machine is finished
if (!earliest) {
_is_finished = true;
- return false;
+ break;
// Earliest active state ends this cycle
} else if (earliest->exit_time() < cycle_end) {
+ this_time += earliest->exit_time() - _time;
_time = earliest->exit_time();
exit_node(earliest);
// Earliest active state ends in the future, done this cycle
} else {
_time = cycle_end;
- return true;
+ this_time = nframes; // ran the entire cycle
+ break;
}
}
-#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;
- }
- }
+ //std::cerr << "Done: " << this_time << std::endl;
- latest_event = end_time;
- }
+ assert(this_time <= nframes);
+ return this_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;
+/** Push a node onto the learn stack.
+ *
+ * NOT realtime (actions are allocated here).
+ */
+void
+Machine::learn(SharedPtr<LearnRequest> learn)
+{
+ std::cerr << "LEARN\n";
+
+ /*LearnRequest request(node,
+ SharedPtr<MidiAction>(new MidiAction(4, NULL)),
+ SharedPtr<MidiAction>(new MidiAction(4, NULL)));*/
- return false;
-#endif
+ //_pending_learns.push_back(learn);
+ _pending_learn = learn;
}
diff --git a/src/engine/MidiAction.cpp b/src/engine/MidiAction.cpp
index 9d30151..aca4b75 100644
--- a/src/engine/MidiAction.cpp
+++ b/src/engine/MidiAction.cpp
@@ -22,6 +22,8 @@
namespace Machina {
+WeakPtr<MidiDriver> MidiAction::_driver;
+
/** Create a MIDI action.
*
@@ -31,11 +33,9 @@ namespace Machina {
* Memory management of @event is the caller's responsibility
* (ownership is not taken).
*/
-MidiAction::MidiAction(WeakPtr<MidiDriver> driver,
- size_t size,
- const byte* event)
- : _driver(driver)
- , _size(0)
+MidiAction::MidiAction(size_t size,
+ const byte* event)
+ : _size(0)
, _max_size(size)
{
_event = new byte[_max_size];
@@ -50,6 +50,18 @@ MidiAction::~MidiAction()
}
+/** Set the MIDI driver to be used for executing MIDI actions.
+ *
+ * MIDI actions will silently do nothing unless this call is passed an
+ * existing MidiDriver.
+ */
+void
+MidiAction::set_driver(SharedPtr<MidiDriver> driver)
+{
+ _driver = driver;
+}
+
+
/** Set the MIDI event to be emitted when the action executes.
*
* Returns pointer to old event (caller's responsibility to free if non-NULL).
@@ -63,7 +75,7 @@ MidiAction::set_event(size_t size, const byte* new_event)
byte* const event = _event.get();
if (size <= _max_size) {
_event = NULL;
- if (size > 0)
+ if (size > 0 && new_event)
memcpy(event, new_event, size);
_size = size;
_event = event;
@@ -86,7 +98,6 @@ MidiAction::execute(Timestamp time)
using namespace std;
if (event) {
- cerr << "MIDI FIRING";
SharedPtr<MidiDriver> driver = _driver.lock();
if (driver)
driver->write_event(time, _size, event);
@@ -98,4 +109,4 @@ MidiAction::execute(Timestamp time)
} // namespace Machina
-
+
diff --git a/src/engine/Node.cpp b/src/engine/Node.cpp
index def7a70..59af04e 100644
--- a/src/engine/Node.cpp
+++ b/src/engine/Node.cpp
@@ -27,46 +27,44 @@ Node::Node(FrameCount duration, bool initial)
, _is_active(false)
, _enter_time(0)
, _duration(duration)
- , _enter_action(NULL)
- , _exit_action(NULL)
{
}
void
-Node::add_enter_action(Action* action)
+Node::add_enter_action(SharedPtr<Action> action)
{
- assert(!_enter_action);
_enter_action = action;
}
void
-Node::remove_enter_action(Action* /*action*/)
+Node::remove_enter_action(SharedPtr<Action> /*action*/)
{
- _enter_action = NULL;
+ _enter_action.reset();
}
void
-Node::add_exit_action(Action* action)
+Node::add_exit_action(SharedPtr<Action> action)
{
- assert(!_exit_action);
_exit_action = action;
}
void
-Node::remove_exit_action(Action* /*action*/)
+Node::remove_exit_action(SharedPtr<Action> /*action*/)
{
- _exit_action = NULL;
+ _exit_action.reset();
}
+//using namespace std;
void
Node::enter(Timestamp time)
{
+ //cerr << "ENTER " << time << endl;
_is_active = true;
_enter_time = time;
if (_enter_action)
@@ -77,6 +75,7 @@ Node::enter(Timestamp time)
void
Node::exit(Timestamp time)
{
+ //cerr << "EXIT " << time << endl;
if (_exit_action)
_exit_action->execute(time);
_is_active = false;
diff --git a/src/engine/machina/Action.hpp b/src/engine/machina/Action.hpp
index feb0e0b..984a1a0 100644
--- a/src/engine/machina/Action.hpp
+++ b/src/engine/machina/Action.hpp
@@ -20,6 +20,7 @@
#include <string>
#include <iostream>
+#include <raul/Deletable.h>
#include "types.hpp"
namespace Machina {
@@ -29,9 +30,7 @@ namespace Machina {
*
* Actions do not have time as a property.
*/
-struct Action {
- virtual ~Action() {}
-
+struct Action : public Raul::Deletable {
virtual void execute(Timestamp /*time*/) {}
};
diff --git a/src/engine/machina/JackDriver.hpp b/src/engine/machina/JackDriver.hpp
index 9a72a62..e1f809f 100644
--- a/src/engine/machina/JackDriver.hpp
+++ b/src/engine/machina/JackDriver.hpp
@@ -50,8 +50,6 @@ public:
Timestamp cycle_start() { return _current_cycle_start; }
FrameCount cycle_length() { return _current_cycle_nframes; }
- void learn(SharedPtr<Node> node);
-
void write_event(Timestamp time,
size_t size,
const unsigned char* event);
@@ -66,13 +64,9 @@ private:
SharedPtr<Machine> _machine;
- SharedPtr<Node> _learn_node;
- SharedPtr<MidiAction> _learn_enter_action;
- SharedPtr<MidiAction> _learn_exit_action;
-
jack_port_t* _input_port;
jack_port_t* _output_port;
- Timestamp _current_cycle_start;
+ Timestamp _current_cycle_start; ///< in machine relative time
Timestamp _current_cycle_offset; ///< for split cycles
FrameCount _current_cycle_nframes;
};
diff --git a/src/engine/machina/Machine.hpp b/src/engine/machina/Machine.hpp
index 4036ef3..b53f55c 100644
--- a/src/engine/machina/Machine.hpp
+++ b/src/engine/machina/Machine.hpp
@@ -18,11 +18,10 @@
#ifndef MACHINA_MACHINE_HPP
#define MACHINA_MACHINE_HPP
-#include <vector>
-#include <map>
#include <raul/SharedPtr.h>
#include <raul/List.h>
#include "types.hpp"
+#include "LearnRequest.hpp"
#include "Node.hpp"
namespace Machina {
@@ -37,16 +36,24 @@ public:
void activate() { _is_activated = true; }
void deactivate() { _is_activated = false; }
+ bool is_empty() { return _nodes.empty(); }
bool is_finished() { return _is_finished; }
void add_node(SharedPtr<Node> node);
+ void learn(SharedPtr<LearnRequest> learn);
// Audio context
void reset();
- bool run(FrameCount nframes);
+ FrameCount run(FrameCount nframes);
// Any context
FrameCount time() { return _time; }
+
+
+ //LearnRequest pop_learn() { return _pending_learns.pop_front(); }
+ //SharedPtr<LearnRequest> first_learn() { return *_pending_learns.begin(); }
+ SharedPtr<LearnRequest> pending_learn() { return _pending_learn; }
+ void clear_pending_learn() { _pending_learn.reset(); }
private:
typedef Raul::List<SharedPtr<Node> > Nodes;
@@ -59,6 +66,9 @@ private:
bool _is_finished;
FrameCount _time;
Nodes _nodes;
+
+ //Raul::List<SharedPtr<LearnRequest> > _pending_learns;
+ SharedPtr<LearnRequest> _pending_learn;
};
diff --git a/src/engine/machina/Makefile.am b/src/engine/machina/Makefile.am
index ffcae1e..7bdd1fd 100644
--- a/src/engine/machina/Makefile.am
+++ b/src/engine/machina/Makefile.am
@@ -10,4 +10,5 @@ libmachinainclude_HEADERS = \
NodeFactory.hpp \
JackNodeFactory.hpp \
MidiAction.hpp \
- MidiDriver.hpp
+ MidiDriver.hpp \
+ LearnRequest.hpp
diff --git a/src/engine/machina/MidiAction.hpp b/src/engine/machina/MidiAction.hpp
index d362a63..7dff692 100644
--- a/src/engine/machina/MidiAction.hpp
+++ b/src/engine/machina/MidiAction.hpp
@@ -18,6 +18,7 @@
#ifndef MACHINA_MIDIACTION_HPP
#define MACHINA_MIDIACTION_HPP
+#include <raul/Maid.h>
#include <raul/WeakPtr.h>
#include <raul/AtomicPtr.h>
#include "types.hpp"
@@ -30,18 +31,29 @@ class MidiDriver;
class MidiAction : public Action {
public:
- MidiAction(WeakPtr<MidiDriver> driver,
- size_t size,
- const unsigned char* event);
-
~MidiAction();
+
+ static SharedPtr<MidiAction>
+ create(SharedPtr<Raul::Maid> maid,
+ size_t size, const unsigned char* event)
+ {
+ SharedPtr<MidiAction> ret(new MidiAction(size, event));
+ maid->manage(ret);
+ return ret;
+ }
+
+ static void set_driver(SharedPtr<MidiDriver> driver);
bool set_event(size_t size, const byte* event);
void execute(Timestamp time);
private:
- WeakPtr<MidiDriver> _driver;
+ MidiAction(size_t size,
+ const unsigned char* event);
+
+ static WeakPtr<MidiDriver> _driver;
+
size_t _size;
const size_t _max_size;
Raul::AtomicPtr<byte> _event;
diff --git a/src/engine/machina/Node.hpp b/src/engine/machina/Node.hpp
index d0e19db..243773f 100644
--- a/src/engine/machina/Node.hpp
+++ b/src/engine/machina/Node.hpp
@@ -43,11 +43,11 @@ public:
Node(FrameCount duration=0, bool initial=false);
- void add_enter_action(Action* action);
- void remove_enter_action(Action* action);
+ void add_enter_action(SharedPtr<Action> action);
+ void remove_enter_action(SharedPtr<Action> action);
- void add_exit_action(Action* action);
- void remove_exit_action(Action* action);
+ void add_exit_action(SharedPtr<Action> action);
+ void remove_exit_action(SharedPtr<Action> action);
void enter(Timestamp time);
void exit(Timestamp time);
@@ -67,13 +67,13 @@ public:
const EdgeList& outgoing_edges() const { return _outgoing_edges; }
private:
- bool _is_initial;
- bool _is_active;
- Timestamp _enter_time; ///< valid iff _is_active
- FrameCount _duration;
- Action* _enter_action;
- Action* _exit_action;
- EdgeList _outgoing_edges;
+ bool _is_initial;
+ bool _is_active;
+ Timestamp _enter_time; ///< valid iff _is_active
+ FrameCount _duration;
+ SharedPtr<Action> _enter_action;
+ SharedPtr<Action> _exit_action;
+ EdgeList _outgoing_edges;
};