diff options
Diffstat (limited to 'src/engine/SMFDriver.cpp')
-rw-r--r-- | src/engine/SMFDriver.cpp | 73 |
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); } |