diff options
Diffstat (limited to 'src/engine')
-rw-r--r-- | src/engine/JackDriver.cpp | 87 | ||||
-rw-r--r-- | src/engine/JackNodeFactory.cpp | 10 | ||||
-rw-r--r-- | src/engine/Machine.cpp | 114 | ||||
-rw-r--r-- | src/engine/MidiAction.cpp | 27 | ||||
-rw-r--r-- | src/engine/Node.cpp | 19 | ||||
-rw-r--r-- | src/engine/machina/Action.hpp | 5 | ||||
-rw-r--r-- | src/engine/machina/JackDriver.hpp | 8 | ||||
-rw-r--r-- | src/engine/machina/Machine.hpp | 16 | ||||
-rw-r--r-- | src/engine/machina/Makefile.am | 3 | ||||
-rw-r--r-- | src/engine/machina/MidiAction.hpp | 22 | ||||
-rw-r--r-- | src/engine/machina/Node.hpp | 22 |
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; }; |