diff options
Diffstat (limited to 'src/engine')
-rw-r--r-- | src/engine/Engine.cpp | 17 | ||||
-rw-r--r-- | src/engine/JackDriver.cpp | 25 | ||||
-rw-r--r-- | src/engine/Machine.cpp | 26 | ||||
-rw-r--r-- | src/engine/Makefile.am | 1 | ||||
-rw-r--r-- | src/engine/MidiAction.cpp | 28 | ||||
-rw-r--r-- | src/engine/Node.cpp | 8 | ||||
-rw-r--r-- | src/engine/machina/Action.hpp | 9 | ||||
-rw-r--r-- | src/engine/machina/Engine.hpp | 1 | ||||
-rw-r--r-- | src/engine/machina/JackDriver.hpp | 8 | ||||
-rw-r--r-- | src/engine/machina/Machine.hpp | 13 | ||||
-rw-r--r-- | src/engine/machina/MidiAction.hpp | 10 | ||||
-rw-r--r-- | src/engine/machina/MidiDriver.hpp | 6 | ||||
-rw-r--r-- | src/engine/machina/Node.hpp | 6 |
13 files changed, 100 insertions, 58 deletions
diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 2054b56..289abd3 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -15,9 +15,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include <glibmm/ustring.h> #include "machina/Loader.hpp" #include "machina/Engine.hpp" #include "machina/JackDriver.hpp" +#include "machina/SMFDriver.hpp" namespace Machina { @@ -36,6 +38,21 @@ Engine::load_machine(const Glib::ustring& uri) } +/** Learn the SMF (MIDI) file at @a uri, and run the resulting machine + * (replacing current machine). + * Safe to call while engine is processing. + */ +SharedPtr<Machine> +Engine::learn_midi(const Glib::ustring& uri) +{ + SharedPtr<SMFDriver> file_driver(new SMFDriver()); + SharedPtr<Machine> m = file_driver->learn(uri); + m->activate(); + _driver->set_machine(m); + return m; +} + + void Engine::set_bpm(double bpm) { diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp index a52cd91..b22ad85 100644 --- a/src/engine/JackDriver.cpp +++ b/src/engine/JackDriver.cpp @@ -26,7 +26,8 @@ namespace Machina { JackDriver::JackDriver(SharedPtr<Machine> machine) - : _machine(machine) + : _machine_changed(0) + , _machine(machine) , _input_port(NULL) , _output_port(NULL) , _cycle_time(1/48000.0, 120.0) @@ -87,6 +88,15 @@ JackDriver::detach() void +JackDriver::set_machine(SharedPtr<Machine> machine) +{ + _machine = machine; + if (is_activated()) + _machine_changed.wait(); +} + + +void JackDriver::process_input(SharedPtr<Machine> machine, const TimeSlice& time) { // We only actually read Jack input at the beginning of a cycle @@ -139,7 +149,7 @@ JackDriver::process_input(SharedPtr<Machine> machine, const TimeSlice& time) void JackDriver::write_event(Raul::BeatTime time, size_t size, - const byte* event) + const byte* event) throw (std::logic_error) { const TickCount nframes = _cycle_time.length_ticks(); const TickCount offset = _cycle_time.beats_to_ticks(time) @@ -180,20 +190,23 @@ JackDriver::on_process(jack_nframes_t nframes) /* Take a reference to machine here and use only it during the process * cycle so _machine can be switched with set_machine during a cycle. */ SharedPtr<Machine> machine = _machine; - + machine->set_sink(shared_from_this()); + // Machine was switched since last cycle, finalize old machine. if (_last_machine && machine != _last_machine) { _last_machine->reset(); // Exit all active states assert(_last_machine.use_count() > 1); // Realtime, can't delete _last_machine.reset(); // Cut our reference + _machine_changed.post(); // Signal we're done with it } + if (!machine) + return; + process_input(machine, _cycle_time); - if (machine->is_empty()) { - //cerr << "EMPTY\n"; + if (machine->is_empty()) return; - } while (true) { diff --git a/src/engine/Machine.cpp b/src/engine/Machine.cpp index 6cade39..e88a78e 100644 --- a/src/engine/Machine.cpp +++ b/src/engine/Machine.cpp @@ -38,6 +38,18 @@ Machine::~Machine() } +/** Set the MIDI sink to be used for executing MIDI actions. + * + * MIDI actions will silently do nothing unless this call is passed an + * existing Raul::MIDISink before running. + */ +void +Machine::set_sink(SharedPtr<Raul::MIDISink> sink) +{ + _sink = sink; +} + + void Machine::add_node(SharedPtr<Node> node) { @@ -55,7 +67,7 @@ Machine::reset() const SharedPtr<Node> node = (*n); if (node->is_active()) - node->exit(_time); + node->exit(_sink.lock(), _time); } } @@ -86,9 +98,9 @@ Machine::earliest_node() const /** Exit an active node at the current _time. */ void -Machine::exit_node(const SharedPtr<Node> node) +Machine::exit_node(SharedPtr<Raul::MIDISink> sink, const SharedPtr<Node> node) { - node->exit(_time); + node->exit(sink, _time); // Activate all successors to this node // (that aren't aready active right now) @@ -101,7 +113,7 @@ Machine::exit_node(const SharedPtr<Node> node) SharedPtr<Node> dst = (*s)->dst(); if (!dst->is_active()) - dst->enter(_time); + dst->enter(sink, _time); } } @@ -125,6 +137,8 @@ Machine::run(const Raul::TimeSlice& time) return 0; } + const SharedPtr<Raul::MIDISink> sink = _sink.lock(); + const BeatCount cycle_end = _time + time.length_beats(); //std::cerr << "Start: " << _time << std::endl; @@ -140,7 +154,7 @@ Machine::run(const Raul::TimeSlice& time) assert( ! (*n)->is_active()); if ((*n)->is_initial()) { - (*n)->enter(0); + (*n)->enter(sink, 0); entered = true; } @@ -170,7 +184,7 @@ Machine::run(const Raul::TimeSlice& time) < time.beats_to_ticks(cycle_end)) { this_time += earliest->exit_time() - _time; _time = earliest->exit_time(); - exit_node(earliest); + exit_node(sink, earliest); // Earliest active state ends in the future, done this cycle } else { diff --git a/src/engine/Makefile.am b/src/engine/Makefile.am index d500302..74308fd 100644 --- a/src/engine/Makefile.am +++ b/src/engine/Makefile.am @@ -14,5 +14,6 @@ libmachina_la_SOURCES = \ Loader.cpp \ MidiAction.cpp \ JackDriver.cpp \ + SMFDriver.cpp \ Engine.cpp \ LearnRequest.cpp diff --git a/src/engine/MidiAction.cpp b/src/engine/MidiAction.cpp index ab73fd3..969e53a 100644 --- a/src/engine/MidiAction.cpp +++ b/src/engine/MidiAction.cpp @@ -17,13 +17,11 @@ #include <iostream> #include <raul/SharedPtr.h> +#include <raul/MIDISink.h> #include "machina/MidiAction.hpp" -#include "machina/MidiDriver.hpp" namespace Machina { -WeakPtr<MidiDriver> MidiAction::_driver; - /** Create a MIDI action. * @@ -50,18 +48,6 @@ 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). @@ -91,14 +77,13 @@ MidiAction::set_event(size_t size, const byte* new_event) * Safe to call concurrently with set_event. */ void -MidiAction::execute(Raul::BeatTime time) +MidiAction::execute(SharedPtr<Raul::MIDISink> sink, Raul::BeatTime time) { const byte* const event = _event.get(); if (event) { - SharedPtr<MidiDriver> driver = _driver.lock(); - if (driver) - driver->write_event(time, _size, event); + if (sink) + sink->write_event(time, _size, event); } else { std::cerr << "NULL MIDI ACTION"; } @@ -115,6 +100,11 @@ MidiAction::write_state(Raul::RDFWriter& writer) writer.write(_id, RdfId(RdfId::RESOURCE, "rdf:type"), RdfId(RdfId::RESOURCE, "machina:MidiAction")); + + // FIXME: Assumes note on/note off + writer.write(_id, + RdfId(RdfId::RESOURCE, "machina:midiNote"), + (int)(_event.get()[1])); } diff --git a/src/engine/Node.cpp b/src/engine/Node.cpp index 7af2997..fbf02fe 100644 --- a/src/engine/Node.cpp +++ b/src/engine/Node.cpp @@ -63,22 +63,22 @@ Node::remove_exit_action(SharedPtr<Action> /*action*/) //using namespace std; void -Node::enter(BeatTime time) +Node::enter(SharedPtr<Raul::MIDISink> sink, BeatTime time) { //cerr << "ENTER " << time << endl; _is_active = true; _enter_time = time; if (_enter_action) - _enter_action->execute(time); + _enter_action->execute(sink, time); } void -Node::exit(BeatTime time) +Node::exit(SharedPtr<Raul::MIDISink> sink, BeatTime time) { //cerr << "EXIT " << time << endl; if (_exit_action) - _exit_action->execute(time); + _exit_action->execute(sink, time); _is_active = false; _enter_time = 0; } diff --git a/src/engine/machina/Action.hpp b/src/engine/machina/Action.hpp index 16c9b58..9ea106a 100644 --- a/src/engine/machina/Action.hpp +++ b/src/engine/machina/Action.hpp @@ -20,18 +20,21 @@ #include <string> #include <iostream> -#include <raul/Deletable.h> +#include <raul/MIDISink.h> #include <raul/TimeSlice.h> #include <raul/Stateful.h> +#include <raul/SharedPtr.h> #include "types.hpp" namespace Machina { +class MidiDriver; + /** An Action, executed on entering or exiting of a state. */ struct Action : public Raul::Deletable, public Raul::Stateful { - virtual void execute(Raul::BeatTime /*time*/) {} + virtual void execute(SharedPtr<Raul::MIDISink> sink, Raul::BeatTime time) = 0; virtual void write_state(Raul::RDFWriter& writer); }; @@ -41,7 +44,7 @@ class PrintAction : public Action { public: PrintAction(const std::string& msg) : _msg(msg) {} - void execute(Raul::BeatTime time) + void execute(SharedPtr<Raul::MIDISink>, Raul::BeatTime time) { std::cout << "t=" << time << ": " << _msg << std::endl; } private: diff --git a/src/engine/machina/Engine.hpp b/src/engine/machina/Engine.hpp index 37aa2db..32fab23 100644 --- a/src/engine/machina/Engine.hpp +++ b/src/engine/machina/Engine.hpp @@ -38,6 +38,7 @@ public: SharedPtr<Machine> machine() { return _driver->machine(); } SharedPtr<Machine> load_machine(const Glib::ustring& uri); + SharedPtr<Machine> learn_midi(const Glib::ustring& uri); void set_bpm(double bpm); void set_quantization(double beat_fraction); diff --git a/src/engine/machina/JackDriver.hpp b/src/engine/machina/JackDriver.hpp index 91f4106..0754741 100644 --- a/src/engine/machina/JackDriver.hpp +++ b/src/engine/machina/JackDriver.hpp @@ -21,6 +21,7 @@ #include <raul/JackDriver.h> #include <raul/SharedPtr.h> #include <raul/DoubleBuffer.h> +#include <raul/Semaphore.h> #include <jack/midiport.h> #include "Machine.hpp" #include "MidiDriver.hpp" @@ -45,12 +46,12 @@ public: void attach(const std::string& client_name); void detach(); - SharedPtr<Machine> machine() { return _machine; } - void set_machine(SharedPtr<Machine> machine) { _machine = machine; } + SharedPtr<Machine> machine() { return _machine; } + void set_machine(SharedPtr<Machine> machine); void write_event(Raul::BeatTime time, size_t size, - const unsigned char* event); + const unsigned char* event) throw (std::logic_error); void set_bpm(double bpm) { _bpm.set(bpm); } void set_quantization(double quantization) { _quantization.set(quantization); } @@ -60,6 +61,7 @@ private: const Raul::TimeSlice& time); virtual void on_process(jack_nframes_t nframes); + Raul::Semaphore _machine_changed; SharedPtr<Machine> _machine; SharedPtr<Machine> _last_machine; diff --git a/src/engine/machina/Machine.hpp b/src/engine/machina/Machine.hpp index 7b71d01..12b601d 100644 --- a/src/engine/machina/Machine.hpp +++ b/src/engine/machina/Machine.hpp @@ -61,16 +61,19 @@ public: typedef Raul::List<SharedPtr<Node> > Nodes; const Nodes& nodes() { return _nodes; } + void set_sink(SharedPtr<Raul::MIDISink> sink); + private: // Audio context SharedPtr<Node> earliest_node() const; - void exit_node(const SharedPtr<Node>); + void exit_node(const SharedPtr<Raul::MIDISink> sink, const SharedPtr<Node>); - bool _is_activated; - bool _is_finished; - Raul::BeatTime _time; - Nodes _nodes; + WeakPtr<Raul::MIDISink> _sink; + bool _is_activated; + bool _is_finished; + Raul::BeatTime _time; + Nodes _nodes; //Raul::List<SharedPtr<LearnRequest> > _pending_learns; SharedPtr<LearnRequest> _pending_learn; diff --git a/src/engine/machina/MidiAction.hpp b/src/engine/machina/MidiAction.hpp index b62d841..2a9f91d 100644 --- a/src/engine/machina/MidiAction.hpp +++ b/src/engine/machina/MidiAction.hpp @@ -25,9 +25,9 @@ #include "types.hpp" #include "Action.hpp" -namespace Machina { +namespace Raul { class MIDISink; } -class MidiDriver; +namespace Machina { class MidiAction : public Action { @@ -43,11 +43,9 @@ public: return ret; } - static void set_driver(SharedPtr<MidiDriver> driver); - bool set_event(size_t size, const byte* event); - void execute(Raul::BeatTime time); + void execute(SharedPtr<Raul::MIDISink> driver, Raul::BeatTime time); virtual void write_state(Raul::RDFWriter& writer); @@ -55,8 +53,6 @@ private: 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/MidiDriver.hpp b/src/engine/machina/MidiDriver.hpp index a4d9f51..a4d712c 100644 --- a/src/engine/machina/MidiDriver.hpp +++ b/src/engine/machina/MidiDriver.hpp @@ -18,6 +18,7 @@ #ifndef MACHINA_MIDIDRIVER_HPP #define MACHINA_MIDIDRIVER_HPP +#include <raul/TimeSlice.h> #include "machina/types.hpp" namespace Machina { @@ -25,14 +26,15 @@ namespace Machina { class Node; -class MidiDriver { +class MidiDriver : public Raul::MIDISink { public: virtual ~MidiDriver() {} /** Emit a MIDI event at the given time */ - virtual void write_event(Raul::BeatTime time, + /*virtual void write_event(Raul::BeatTime time, size_t size, const unsigned char* event) = 0; + */ /** Beginning of current cycle in absolute time. */ diff --git a/src/engine/machina/Node.hpp b/src/engine/machina/Node.hpp index 569a54e..bd1a66e 100644 --- a/src/engine/machina/Node.hpp +++ b/src/engine/machina/Node.hpp @@ -22,7 +22,7 @@ #include <raul/SharedPtr.h> #include <raul/List.h> #include <raul/Stateful.h> -#include <raul/TimeSlice.h> +#include <raul/MIDISink.h> #include "Action.hpp" namespace Machina { @@ -52,8 +52,8 @@ public: void add_exit_action(SharedPtr<Action> action); void remove_exit_action(SharedPtr<Action> action); - void enter(BeatTime time); - void exit(BeatTime time); + void enter(SharedPtr<Raul::MIDISink> driver, BeatTime time); + void exit(SharedPtr<Raul::MIDISink> driver, BeatTime time); void add_outgoing_edge(SharedPtr<Edge> edge); void remove_outgoing_edge(SharedPtr<Edge> edge); |