From 43cca924857a2c9b8833d0f3e441a5d277ad42fe Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 3 Mar 2007 04:40:05 +0000 Subject: SMF writing work. git-svn-id: http://svn.drobilla.net/lad/machina@343 a436a847-0d15-0410-975c-d299462d15a1 --- src/engine/Engine.cpp | 17 +++++++++++++++++ src/engine/JackDriver.cpp | 25 +++++++++++++++++++------ src/engine/Machine.cpp | 26 ++++++++++++++++++++------ src/engine/Makefile.am | 1 + src/engine/MidiAction.cpp | 28 +++++++++------------------- src/engine/Node.cpp | 8 ++++---- src/engine/machina/Action.hpp | 9 ++++++--- src/engine/machina/Engine.hpp | 1 + src/engine/machina/JackDriver.hpp | 8 +++++--- src/engine/machina/Machine.hpp | 13 ++++++++----- src/engine/machina/MidiAction.hpp | 10 +++------- src/engine/machina/MidiDriver.hpp | 6 ++++-- src/engine/machina/Node.hpp | 6 +++--- 13 files changed, 100 insertions(+), 58 deletions(-) (limited to 'src/engine') 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 #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 +Engine::learn_midi(const Glib::ustring& uri) +{ + SharedPtr file_driver(new SMFDriver()); + SharedPtr 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_changed(0) + , _machine(machine) , _input_port(NULL) , _output_port(NULL) , _cycle_time(1/48000.0, 120.0) @@ -86,6 +87,15 @@ JackDriver::detach() } +void +JackDriver::set_machine(SharedPtr machine) +{ + _machine = machine; + if (is_activated()) + _machine_changed.wait(); +} + + void JackDriver::process_input(SharedPtr machine, const TimeSlice& time) { @@ -139,7 +149,7 @@ JackDriver::process_input(SharedPtr 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->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 sink) +{ + _sink = sink; +} + + void Machine::add_node(SharedPtr node) { @@ -55,7 +67,7 @@ Machine::reset() const SharedPtr 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) +Machine::exit_node(SharedPtr sink, const SharedPtr 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) SharedPtr 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 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 #include +#include #include "machina/MidiAction.hpp" -#include "machina/MidiDriver.hpp" namespace Machina { -WeakPtr 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 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 sink, Raul::BeatTime time) { const byte* const event = _event.get(); if (event) { - SharedPtr 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*/) //using namespace std; void -Node::enter(BeatTime time) +Node::enter(SharedPtr 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 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 #include -#include +#include #include #include +#include #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 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::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() { return _driver->machine(); } SharedPtr load_machine(const Glib::ustring& uri); + SharedPtr 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 #include #include +#include #include #include "Machine.hpp" #include "MidiDriver.hpp" @@ -45,12 +46,12 @@ public: void attach(const std::string& client_name); void detach(); - SharedPtr machine() { return _machine; } - void set_machine(SharedPtr machine) { _machine = machine; } + SharedPtr machine() { return _machine; } + void set_machine(SharedPtr 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; SharedPtr _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 > Nodes; const Nodes& nodes() { return _nodes; } + void set_sink(SharedPtr sink); + private: // Audio context SharedPtr earliest_node() const; - void exit_node(const SharedPtr); + void exit_node(const SharedPtr sink, const SharedPtr); - bool _is_activated; - bool _is_finished; - Raul::BeatTime _time; - Nodes _nodes; + WeakPtr _sink; + bool _is_activated; + bool _is_finished; + Raul::BeatTime _time; + Nodes _nodes; //Raul::List > _pending_learns; SharedPtr _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 driver); - bool set_event(size_t size, const byte* event); - void execute(Raul::BeatTime time); + void execute(SharedPtr 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 _driver; - size_t _size; const size_t _max_size; Raul::AtomicPtr _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 #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 #include #include -#include +#include #include "Action.hpp" namespace Machina { @@ -52,8 +52,8 @@ public: void add_exit_action(SharedPtr action); void remove_exit_action(SharedPtr action); - void enter(BeatTime time); - void exit(BeatTime time); + void enter(SharedPtr driver, BeatTime time); + void exit(SharedPtr driver, BeatTime time); void add_outgoing_edge(SharedPtr edge); void remove_outgoing_edge(SharedPtr edge); -- cgit v1.2.1