aboutsummaryrefslogtreecommitdiffstats
path: root/src/engine
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-03-03 04:40:05 +0000
committerDavid Robillard <d@drobilla.net>2007-03-03 04:40:05 +0000
commit43cca924857a2c9b8833d0f3e441a5d277ad42fe (patch)
tree86591a16c7f44674dbb264d245151086474995bd /src/engine
parent085f3de0f526ac2ad7b00bfbc76be18b33a5c3c5 (diff)
downloadmachina-43cca924857a2c9b8833d0f3e441a5d277ad42fe.tar.gz
machina-43cca924857a2c9b8833d0f3e441a5d277ad42fe.tar.bz2
machina-43cca924857a2c9b8833d0f3e441a5d277ad42fe.zip
SMF writing work.
git-svn-id: http://svn.drobilla.net/lad/machina@343 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/Engine.cpp17
-rw-r--r--src/engine/JackDriver.cpp25
-rw-r--r--src/engine/Machine.cpp26
-rw-r--r--src/engine/Makefile.am1
-rw-r--r--src/engine/MidiAction.cpp28
-rw-r--r--src/engine/Node.cpp8
-rw-r--r--src/engine/machina/Action.hpp9
-rw-r--r--src/engine/machina/Engine.hpp1
-rw-r--r--src/engine/machina/JackDriver.hpp8
-rw-r--r--src/engine/machina/Machine.hpp13
-rw-r--r--src/engine/machina/MidiAction.hpp10
-rw-r--r--src/engine/machina/MidiDriver.hpp6
-rw-r--r--src/engine/machina/Node.hpp6
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);