aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-03-11 17:33:20 +0000
committerDavid Robillard <d@drobilla.net>2007-03-11 17:33:20 +0000
commitf3ba4fc81cecf8ba61c2508ed9a624c794ab88b5 (patch)
tree192e269d2ee275331327466e69b69a752834ee27 /src
parentf93b6bd24dc98e071e5881595829f2c9a6311139 (diff)
downloadmachina-f3ba4fc81cecf8ba61c2508ed9a624c794ab88b5.tar.gz
machina-f3ba4fc81cecf8ba61c2508ed9a624c794ab88b5.tar.bz2
machina-f3ba4fc81cecf8ba61c2508ed9a624c794ab88b5.zip
MIDI file reading.
git-svn-id: http://svn.drobilla.net/lad/machina@352 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r--src/engine/Action.cpp3
-rw-r--r--src/engine/JackDriver.cpp10
-rw-r--r--src/engine/Node.cpp25
-rw-r--r--src/engine/SMFDriver.cpp60
-rw-r--r--src/engine/machina/MidiAction.hpp9
-rw-r--r--src/engine/machina/Node.hpp5
-rw-r--r--src/gui/MachinaGUI.cpp12
-rw-r--r--src/gui/MachinaGUI.hpp4
-rw-r--r--src/gui/NodeView.cpp4
-rw-r--r--src/gui/machina.glade59
10 files changed, 133 insertions, 58 deletions
diff --git a/src/engine/Action.cpp b/src/engine/Action.cpp
index a893d74..471dfa8 100644
--- a/src/engine/Action.cpp
+++ b/src/engine/Action.cpp
@@ -24,6 +24,9 @@ void
Action::write_state(Raul::RDFWriter& writer)
{
using Raul::RdfId;
+
+ if (!_id)
+ set_id(writer.blank_id());
writer.write(_id,
RdfId(RdfId::RESOURCE, "rdf:type"),
diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp
index b22ad85..0261dd5 100644
--- a/src/engine/JackDriver.cpp
+++ b/src/engine/JackDriver.cpp
@@ -193,10 +193,12 @@ JackDriver::on_process(jack_nframes_t nframes)
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
+ if (machine != _last_machine) {
+ if (_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
}
diff --git a/src/engine/Node.cpp b/src/engine/Node.cpp
index fbf02fe..4a1ded0 100644
--- a/src/engine/Node.cpp
+++ b/src/engine/Node.cpp
@@ -68,7 +68,7 @@ Node::enter(SharedPtr<Raul::MIDISink> sink, BeatTime time)
//cerr << "ENTER " << time << endl;
_is_active = true;
_enter_time = time;
- if (_enter_action)
+ if (sink && _enter_action)
_enter_action->execute(sink, time);
}
@@ -77,7 +77,7 @@ void
Node::exit(SharedPtr<Raul::MIDISink> sink, BeatTime time)
{
//cerr << "EXIT " << time << endl;
- if (_exit_action)
+ if (sink && _exit_action)
_exit_action->execute(sink, time);
_is_active = false;
_enter_time = 0;
@@ -131,13 +131,22 @@ Node::write_state(Raul::RDFWriter& writer)
RdfId(RdfId::RESOURCE, "machina:duration"),
Raul::Atom((float)_duration));
- writer.write(_id,
- RdfId(RdfId::RESOURCE, "machina:enterAction"),
- _enter_action->id());
- _enter_action->write_state(writer);
+ if (_enter_action) {
+ _enter_action->write_state(writer);
+
+ writer.write(_id,
+ RdfId(RdfId::RESOURCE, "machina:enterAction"),
+ _enter_action->id());
+ }
+
+ if (_exit_action) {
+ _exit_action->write_state(writer);
+
+ writer.write(_id,
+ RdfId(RdfId::RESOURCE, "machina:exitAction"),
+ _exit_action->id());
+ }
- _exit_action->write_state(writer);
-
/*for (Node::Edges::const_iterator e = _outgoing_edges.begin();
e != _outgoing_edges.end(); ++e)
(*e)->write_state(writer);*/
diff --git a/src/engine/SMFDriver.cpp b/src/engine/SMFDriver.cpp
index dd60903..181da52 100644
--- a/src/engine/SMFDriver.cpp
+++ b/src/engine/SMFDriver.cpp
@@ -15,10 +15,14 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <list>
#include <iostream>
#include <glibmm/convert.h>
+#include <raul/midi_events.h>
#include <raul/SMFWriter.h>
+#include <raul/SMFReader.h>
#include "machina/Machine.hpp"
+#include "machina/Edge.hpp"
#include "machina/SMFDriver.hpp"
using namespace std;
@@ -37,8 +41,64 @@ SMFDriver::learn(const Glib::ustring& uri)
const string filename = Glib::filename_from_uri(uri);
std::cerr << "Learn MIDI: " << filename << std::endl;
+
SharedPtr<Machine> m(new Machine());
+ list<SharedPtr<Node> > active_nodes;
+ SharedPtr<Node> connect_node(new Node());
+ connect_node->set_initial(true);
+ m->add_node(connect_node);
+
+ Raul::SMFReader reader;
+ reader.open(filename);
+ Raul::BeatTime t = 0;
+ unsigned char buf[4];
+ uint32_t ev_size;
+ uint32_t ev_time;
+ while (reader.read_event(4, buf, &ev_size, &ev_time) >= 0) {
+ t += ev_time / (double)reader.ppqn();
+ cerr << "t = " << t << endl;
+ if (ev_size > 0) {
+ if ((buf[0] & 0xF0) == MIDI_CMD_NOTE_ON) {
+ cerr << "NOTE ON: " << (int)buf[1] << endl;
+ SharedPtr<Node> node(new Node());
+ node->add_enter_action(SharedPtr<Action>(new MidiAction(ev_size, buf)));
+ connect_node->add_outgoing_edge(SharedPtr<Edge>(new Edge(connect_node, node)));
+ node->enter(SharedPtr<Raul::MIDISink>(), t);
+ active_nodes.push_back(node);
+ } else if ((buf[0] & 0xF0) == MIDI_CMD_NOTE_OFF) {
+ cerr << "NOTE OFF: " << (int)buf[1] << endl;
+ for (list<SharedPtr<Node> >::iterator i = active_nodes.begin();
+ i != active_nodes.end(); ++i) {
+ SharedPtr<MidiAction> action = PtrCast<MidiAction>((*i)->enter_action());
+ if (!action)
+ continue;
+
+ const size_t ev_size = action->event_size();
+ const unsigned char* ev = action->event();
+ if (ev_size == 3 && (ev[0] & 0xF0) == MIDI_CMD_NOTE_ON
+ && ev[1] == buf[1]) {
+ cerr << "FOUND MATCHING NOTE ON!\n";
+ (*i)->add_exit_action(SharedPtr<Action>(new MidiAction(ev_size, buf)));
+ (*i)->set_duration(t - (*i)->enter_time());
+ (*i)->exit(SharedPtr<Raul::MIDISink>(), t);
+ m->add_node((*i));
+ if (active_nodes.size() == 1)
+ connect_node = (*i);
+ active_nodes.erase(i);
+ break;
+ }
+ }
+ }
+ }
+ /*std::cerr << "Event, size = " << ev_size << ", time = " << ev_time << std::endl;
+ cerr.flags(ios::hex);
+ for (uint32_t i=0; i < ev_size; ++i) {
+ cerr << "0x" << (int)buf[i] << " ";
+ }
+ cerr.flags(ios::dec);
+ cerr << endl;*/
+ }
return m;
}
diff --git a/src/engine/machina/MidiAction.hpp b/src/engine/machina/MidiAction.hpp
index 2a9f91d..60d9189 100644
--- a/src/engine/machina/MidiAction.hpp
+++ b/src/engine/machina/MidiAction.hpp
@@ -34,6 +34,9 @@ class MidiAction : public Action {
public:
~MidiAction();
+ MidiAction(size_t size,
+ const unsigned char* event);
+
static SharedPtr<MidiAction>
create(SharedPtr<Raul::Maid> maid,
size_t size, const unsigned char* event)
@@ -43,6 +46,9 @@ public:
return ret;
}
+ size_t event_size() { return _size; }
+ byte* event() { return _event.get(); }
+
bool set_event(size_t size, const byte* event);
void execute(SharedPtr<Raul::MIDISink> driver, Raul::BeatTime time);
@@ -50,8 +56,7 @@ public:
virtual void write_state(Raul::RDFWriter& writer);
private:
- MidiAction(size_t size,
- const unsigned char* event);
+
size_t _size;
const size_t _max_size;
diff --git a/src/engine/machina/Node.hpp b/src/engine/machina/Node.hpp
index bd1a66e..2f9c2e4 100644
--- a/src/engine/machina/Node.hpp
+++ b/src/engine/machina/Node.hpp
@@ -48,10 +48,13 @@ public:
void add_enter_action(SharedPtr<Action> action);
void remove_enter_action(SharedPtr<Action> action);
-
+
void add_exit_action(SharedPtr<Action> action);
void remove_exit_action(SharedPtr<Action> action);
+ SharedPtr<Action> enter_action() { return _enter_action; }
+ SharedPtr<Action> exit_action() { return _exit_action; }
+
void enter(SharedPtr<Raul::MIDISink> driver, BeatTime time);
void exit(SharedPtr<Raul::MIDISink> driver, BeatTime time);
diff --git a/src/gui/MachinaGUI.cpp b/src/gui/MachinaGUI.cpp
index 65ecb13..121e25a 100644
--- a/src/gui/MachinaGUI.cpp
+++ b/src/gui/MachinaGUI.cpp
@@ -115,7 +115,7 @@ 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("import_midi_menuitem", _menu_import_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);
@@ -154,8 +154,8 @@ 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_import_midi->signal_activate().connect(
+ sigc::mem_fun(this, &MachinaGUI::menu_import_midi));
_menu_export_midi->signal_activate().connect(
sigc::mem_fun(this, &MachinaGUI::menu_export_midi));
//_menu_view_refresh->signal_activate().connect(
@@ -437,7 +437,7 @@ MachinaGUI::menu_file_save_as()
void
-MachinaGUI::menu_learn_midi()
+MachinaGUI::menu_import_midi()
{
Gtk::FileChooserDialog dialog(*_main_window, "Learn from MIDI file", Gtk::FILE_CHOOSER_ACTION_OPEN);
dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
@@ -448,6 +448,10 @@ MachinaGUI::menu_learn_midi()
if (result == Gtk::RESPONSE_OK) {
SharedPtr<Machina::SMFDriver> file_driver(new Machina::SMFDriver());
SharedPtr<Machina::Machine> machine = file_driver->learn(dialog.get_uri());
+ machine->activate();
+ machine->reset();
+ _engine->driver()->set_machine(machine);
+ _canvas->build(machine);
}
}
diff --git a/src/gui/MachinaGUI.hpp b/src/gui/MachinaGUI.hpp
index 962a6f9..0e507fc 100644
--- a/src/gui/MachinaGUI.hpp
+++ b/src/gui/MachinaGUI.hpp
@@ -59,7 +59,7 @@ protected:
void menu_file_open();
void menu_file_save();
void menu_file_save_as();
- void menu_learn_midi();
+ void menu_import_midi();
void menu_export_midi();
//void show_messages_toggled();
void show_toolbar_toggled();
@@ -100,7 +100,7 @@ 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_import_midi;
Gtk::MenuItem* _menu_export_midi;
Gtk::MenuItem* _menu_help_about;
Gtk::CheckMenuItem* _menu_view_toolbar;
diff --git a/src/gui/NodeView.cpp b/src/gui/NodeView.cpp
index 62be95b..f34c658 100644
--- a/src/gui/NodeView.cpp
+++ b/src/gui/NodeView.cpp
@@ -34,10 +34,11 @@ void
NodeView::on_double_click(GdkEventButton*)
{
bool is_initial = _node->is_initial();
- std::cerr << "INITIAL " << is_initial;
+ std::cerr << "Initial: " << is_initial << std::endl;
_node->set_initial( ! is_initial );
}
+
void
NodeView::update_state()
{
@@ -52,3 +53,4 @@ NodeView::update_state()
set_base_color(_old_color);
}
}
+
diff --git a/src/gui/machina.glade b/src/gui/machina.glade
index d82f528..c0d1b87 100644
--- a/src/gui/machina.glade
+++ b/src/gui/machina.glade
@@ -77,6 +77,28 @@
</child>
<child>
+ <widget class="GtkImageMenuItem" id="import_midi_menuitem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Import 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="I" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image8">
+ <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>
+
+ <child>
<widget class="GtkImageMenuItem" id="export_midi_menuitem">
<property name="visible">True</property>
<property name="label" translatable="yes">_Export MIDI...</property>
@@ -85,7 +107,7 @@
<accelerator key="E" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image">
- <widget class="GtkImage" id="image6">
+ <widget class="GtkImage" id="image9">
<property name="visible">True</property>
<property name="stock">gtk-convert</property>
<property name="icon_size">1</property>
@@ -118,41 +140,6 @@
</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>