aboutsummaryrefslogtreecommitdiffstats
path: root/src/engine/SMFDriver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/SMFDriver.cpp')
-rw-r--r--src/engine/SMFDriver.cpp73
1 files changed, 62 insertions, 11 deletions
diff --git a/src/engine/SMFDriver.cpp b/src/engine/SMFDriver.cpp
index abd0fb2..d2fcabb 100644
--- a/src/engine/SMFDriver.cpp
+++ b/src/engine/SMFDriver.cpp
@@ -38,7 +38,7 @@ namespace Machina {
* @return the resulting machine.
*/
SharedPtr<Machine>
-SMFDriver::learn(const Glib::ustring& uri, unsigned track)
+SMFDriver::learn(const Glib::ustring& uri, unsigned track, Raul::BeatTime max_duration)
{
const string filename = Glib::filename_from_uri(uri);
@@ -50,7 +50,7 @@ SMFDriver::learn(const Glib::ustring& uri, unsigned track)
if (track > reader.num_tracks())
return SharedPtr<Machine>();
else
- learn_track(m, reader, track);
+ learn_track(m, reader, track, max_duration);
if (m->nodes().size() > 1)
return m;
@@ -64,7 +64,7 @@ SMFDriver::learn(const Glib::ustring& uri, unsigned track)
* This will result in a disjoint subgraph in the machine, one for each track.
*/
SharedPtr<Machine>
-SMFDriver::learn(const Glib::ustring& uri)
+SMFDriver::learn(const Glib::ustring& uri, Raul::BeatTime max_duration)
{
const string filename = Glib::filename_from_uri(uri);
@@ -74,7 +74,7 @@ SMFDriver::learn(const Glib::ustring& uri)
reader.open(filename);
for (unsigned t=1; t <= reader.num_tracks(); ++t) {
- learn_track(m, reader, t);
+ learn_track(m, reader, t, max_duration);
}
if (m->nodes().size() > 1)
@@ -87,7 +87,8 @@ SMFDriver::learn(const Glib::ustring& uri)
void
SMFDriver::learn_track(SharedPtr<Machine> m,
Raul::SMFReader& reader,
- unsigned track)
+ unsigned track,
+ Raul::BeatTime max_duration)
{
const bool found_track = reader.seek_to_track(track);
assert(found_track);
@@ -95,9 +96,13 @@ SMFDriver::learn_track(SharedPtr<Machine> m,
list<SharedPtr<Node> > active_nodes;
SharedPtr<Node> initial_node(new Node());
- m->add_node(initial_node);
+ initial_node->set_initial(true);
+ //m->add_node(initial_node);
SharedPtr<Node> connect_node = initial_node;
+ Raul::BeatTime connect_node_end_time = 0;
+
+ unsigned added_nodes = 0;
Raul::BeatTime t = 0;
unsigned char buf[4];
@@ -105,13 +110,31 @@ SMFDriver::learn_track(SharedPtr<Machine> m,
uint32_t ev_time;
while (reader.read_event(4, buf, &ev_size, &ev_time) >= 0) {
t += ev_time / (double)reader.ppqn();
+
+ if (t > max_duration)
+ break;
+
//cerr << "t = " << t << endl;
if (ev_size > 0) {
if ((buf[0] & 0xF0) == MIDI_CMD_NOTE_ON) {
- //cerr << "NOTE ON: " << (int)buf[1] << endl;
+ cerr << "NOTE ON: " << (int)buf[1] << ", channel = " << (int)(buf[0] & 0x0F) << 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)));
+ assert(connect_node_end_time <= t);
+
+ if (t == connect_node_end_time) {
+ connect_node->add_outgoing_edge(SharedPtr<Edge>(new Edge(connect_node, node)));
+ } else {
+ SharedPtr<Node> delay_node(new Node());
+ delay_node->set_duration(t - connect_node_end_time);
+ connect_node->add_outgoing_edge(SharedPtr<Edge>(new Edge(connect_node, delay_node)));
+ delay_node->add_outgoing_edge(SharedPtr<Edge>(new Edge(delay_node, node)));
+ m->add_node(delay_node);
+ ++added_nodes;
+ connect_node = delay_node;
+ connect_node_end_time = t;
+ }
+
node->enter(SharedPtr<Raul::MIDISink>(), t);
active_nodes.push_back(node);
} else if ((buf[0] & 0xF0) == MIDI_CMD_NOTE_OFF) {
@@ -125,14 +148,19 @@ SMFDriver::learn_track(SharedPtr<Machine> m,
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]) {
+ && (ev[0] & 0x0F) == (buf[0] & 0x0F) // same channel
+ && ev[1] == buf[1]) // same note
+ {
//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)
+ ++added_nodes;
+ if (active_nodes.size() == 1) {
connect_node = (*i);
+ connect_node_end_time = t;
+ }
active_nodes.erase(i);
break;
}
@@ -141,7 +169,30 @@ SMFDriver::learn_track(SharedPtr<Machine> m,
}
}
- initial_node->set_initial(true);
+ // Resolve any stuck notes when the rest of the machine is finished
+ if ( ! active_nodes.empty()) {
+ for (list<SharedPtr<Node> >::iterator i = active_nodes.begin(); i != active_nodes.end(); ++i) {
+ cerr << "WARNING: Resolving stuck note from MIDI file." << endl;
+ 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) {
+ unsigned char note_off[3] = { ((MIDI_CMD_NOTE_OFF & 0xF0) | (ev[0] & 0x0F)), ev[1], 0x40 };
+ (*i)->add_exit_action(SharedPtr<Action>(new MidiAction(3, note_off)));
+ (*i)->set_duration(t - (*i)->enter_time());
+ (*i)->exit(SharedPtr<Raul::MIDISink>(), t);
+ m->add_node((*i));
+ ++added_nodes;
+ }
+ }
+ active_nodes.clear();
+ }
+
+ if (added_nodes > 0)
+ m->add_node(initial_node);
}