aboutsummaryrefslogtreecommitdiffstats
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
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
-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
-rw-r--r--src/gui/MachinaGUI.cpp52
-rw-r--r--src/gui/MachinaGUI.hpp4
-rw-r--r--src/gui/machina.glade63
-rw-r--r--src/gui/main.cpp2
-rw-r--r--src/main.cpp1
-rwxr-xr-xutil/machina2dot.py3
19 files changed, 217 insertions, 66 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);
diff --git a/src/gui/MachinaGUI.cpp b/src/gui/MachinaGUI.cpp
index 3dd0c96..65ecb13 100644
--- a/src/gui/MachinaGUI.cpp
+++ b/src/gui/MachinaGUI.cpp
@@ -17,12 +17,13 @@
#include <cmath>
#include <sstream>
-#include <libgnomecanvasmm.h>
-#include <libglademm/xml.h>
#include <fstream>
#include <pthread.h>
+#include <libgnomecanvasmm.h>
+#include <libglademm/xml.h>
#include <raul/RDFWriter.h>
#include <machina/Machine.hpp>
+#include <machina/SMFDriver.hpp>
#include "MachinaGUI.hpp"
#include "MachinaCanvas.hpp"
#include "NodeView.hpp"
@@ -114,6 +115,8 @@ MachinaGUI::MachinaGUI(SharedPtr<Machina::Engine> engine)
xml->get_widget("save_menuitem", _menu_file_save);
xml->get_widget("save_as_menuitem", _menu_file_save_as);
xml->get_widget("quit_menuitem", _menu_file_quit);
+ xml->get_widget("learn_midi_menuitem", _menu_learn_midi);
+ xml->get_widget("export_midi_menuitem", _menu_export_midi);
xml->get_widget("view_toolbar_menuitem", _menu_view_toolbar);
//xml->get_widget("view_refresh_menuitem", _menu_view_refresh);
//xml->get_widget("view_messages_menuitem", _menu_view_messages);
@@ -151,6 +154,10 @@ MachinaGUI::MachinaGUI(SharedPtr<Machina::Engine> engine)
sigc::mem_fun(this, &MachinaGUI::menu_file_save_as));
_menu_file_quit->signal_activate().connect(
sigc::mem_fun(this, &MachinaGUI::menu_file_quit));
+ _menu_learn_midi->signal_activate().connect(
+ sigc::mem_fun(this, &MachinaGUI::menu_learn_midi));
+ _menu_export_midi->signal_activate().connect(
+ sigc::mem_fun(this, &MachinaGUI::menu_export_midi));
//_menu_view_refresh->signal_activate().connect(
// sigc::mem_fun(this, &MachinaGUI::menu_view_refresh));
_menu_view_toolbar->signal_toggled().connect(
@@ -352,9 +359,7 @@ void
MachinaGUI::menu_file_open()
{
Gtk::FileChooserDialog dialog(*_main_window, "Open Machine", Gtk::FILE_CHOOSER_ACTION_OPEN);
-
dialog.set_local_only(false);
-
dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
@@ -432,6 +437,45 @@ MachinaGUI::menu_file_save_as()
void
+MachinaGUI::menu_learn_midi()
+{
+ Gtk::FileChooserDialog dialog(*_main_window, "Learn from MIDI file", Gtk::FILE_CHOOSER_ACTION_OPEN);
+ dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+ dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
+
+ const int result = dialog.run();
+
+ if (result == Gtk::RESPONSE_OK) {
+ SharedPtr<Machina::SMFDriver> file_driver(new Machina::SMFDriver());
+ SharedPtr<Machina::Machine> machine = file_driver->learn(dialog.get_uri());
+ }
+}
+
+
+void
+MachinaGUI::menu_export_midi()
+{
+ Gtk::FileChooserDialog dialog(*_main_window, "Export to a MIDI file", Gtk::FILE_CHOOSER_ACTION_SAVE);
+ dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+ dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
+
+ const int result = dialog.run();
+
+ if (result == Gtk::RESPONSE_OK) {
+ SharedPtr<Machina::SMFDriver> file_driver(new Machina::SMFDriver());
+ _engine->driver()->deactivate();
+ const SharedPtr<Machina::Machine> m = _engine->machine();
+ m->set_sink(file_driver);
+ file_driver->start(dialog.get_filename());
+ file_driver->run(m, 32); // FIXME: hardcoded max length. TODO: solve halting problem
+ m->set_sink(_engine->driver());
+ m->reset();
+ _engine->driver()->activate();
+ }
+}
+
+
+void
MachinaGUI::on_pane_position_changed()
{
// avoid infinite recursion...
diff --git a/src/gui/MachinaGUI.hpp b/src/gui/MachinaGUI.hpp
index 47142b0..962a6f9 100644
--- a/src/gui/MachinaGUI.hpp
+++ b/src/gui/MachinaGUI.hpp
@@ -59,6 +59,8 @@ protected:
void menu_file_open();
void menu_file_save();
void menu_file_save_as();
+ void menu_learn_midi();
+ void menu_export_midi();
//void show_messages_toggled();
void show_toolbar_toggled();
//void menu_view_refresh();
@@ -98,6 +100,8 @@ protected:
Gtk::MenuItem* _menu_file_save;
Gtk::MenuItem* _menu_file_save_as;
Gtk::MenuItem* _menu_file_quit;
+ Gtk::MenuItem* _menu_learn_midi;
+ Gtk::MenuItem* _menu_export_midi;
Gtk::MenuItem* _menu_help_about;
Gtk::CheckMenuItem* _menu_view_toolbar;
//Gtk::CheckMenuItem* _menu_view_messages;
diff --git a/src/gui/machina.glade b/src/gui/machina.glade
index 6e5d7e9..d82f528 100644
--- a/src/gui/machina.glade
+++ b/src/gui/machina.glade
@@ -77,6 +77,34 @@
</child>
<child>
+ <widget class="GtkImageMenuItem" id="export_midi_menuitem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Export MIDI...</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_export_midi_menuitem_activate" last_modification_time="Fri, 02 Mar 2007 20:59:46 GMT"/>
+ <accelerator key="E" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image6">
+ <property name="visible">True</property>
+ <property name="stock">gtk-convert</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator6">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
<widget class="GtkImageMenuItem" id="quit_menuitem">
<property name="visible">True</property>
<property name="label">gtk-quit</property>
@@ -90,6 +118,41 @@
</child>
<child>
+ <widget class="GtkMenuItem" id="machine_menu">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Machine</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="machine_menu_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="learn_midi_menuitem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Learn MIDI...</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_learn_midi_menuitem_activate" last_modification_time="Fri, 02 Mar 2007 21:00:16 GMT"/>
+ <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image7">
+ <property name="visible">True</property>
+ <property name="stock">gtk-media-record</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
<widget class="GtkMenuItem" id="view_menu">
<property name="visible">True</property>
<property name="label" translatable="yes">_View</property>
diff --git a/src/gui/main.cpp b/src/gui/main.cpp
index 4e4bc07..3e7f737 100644
--- a/src/gui/main.cpp
+++ b/src/gui/main.cpp
@@ -34,8 +34,6 @@ main(int argc, char** argv)
SharedPtr<JackDriver> driver(new JackDriver());
- MidiAction::set_driver(driver);
-
driver->attach("machina");
SharedPtr<Engine> engine(new Engine(driver));
diff --git a/src/main.cpp b/src/main.cpp
index 9250738..f04a646 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -53,7 +53,6 @@ main(int argc, char** argv)
}
SharedPtr<JackDriver> driver(new JackDriver());
- MidiAction::set_driver(driver);
Engine engine(driver);
diff --git a/util/machina2dot.py b/util/machina2dot.py
index f4e67ec..fc3c6b5 100755
--- a/util/machina2dot.py
+++ b/util/machina2dot.py
@@ -15,7 +15,8 @@ parser.parse_into_model(model, "file:" + sys.argv[1])
print """
digraph finite_state_machine {
- rankdir=LR;
+ rankdir=TD;
+ size="20,20"
node [shape = doublecircle, width = 1.25 ];
""",