From 1c4f8c131dec109677d0a9b2b008c39a66d08158 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 12 Mar 2007 21:36:32 +0000 Subject: Export to DOT file. Fixed loading of useless initial nodes. git-svn-id: http://svn.drobilla.net/lad/machina@358 a436a847-0d15-0410-975c-d299462d15a1 --- src/engine/Engine.cpp | 2 +- src/engine/SMFDriver.cpp | 73 ++++++++++++++++++++++++++++++++++------ src/engine/machina/SMFDriver.hpp | 7 ++-- 3 files changed, 67 insertions(+), 15 deletions(-) (limited to 'src/engine') diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 289abd3..5991276 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -46,7 +46,7 @@ SharedPtr Engine::learn_midi(const Glib::ustring& uri) { SharedPtr file_driver(new SMFDriver()); - SharedPtr m = file_driver->learn(uri); + SharedPtr m = file_driver->learn(uri, 32.0); m->activate(); _driver->set_machine(m); return m; 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 -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(); 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 -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 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 m, list > active_nodes; SharedPtr initial_node(new Node()); - m->add_node(initial_node); + initial_node->set_initial(true); + //m->add_node(initial_node); SharedPtr 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 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(new Node()); node->add_enter_action(SharedPtr(new MidiAction(ev_size, buf))); - connect_node->add_outgoing_edge(SharedPtr(new Edge(connect_node, node))); + assert(connect_node_end_time <= t); + + if (t == connect_node_end_time) { + connect_node->add_outgoing_edge(SharedPtr(new Edge(connect_node, node))); + } else { + SharedPtr delay_node(new Node()); + delay_node->set_duration(t - connect_node_end_time); + connect_node->add_outgoing_edge(SharedPtr(new Edge(connect_node, delay_node))); + delay_node->add_outgoing_edge(SharedPtr(new Edge(delay_node, node))); + m->add_node(delay_node); + ++added_nodes; + connect_node = delay_node; + connect_node_end_time = t; + } + node->enter(SharedPtr(), t); active_nodes.push_back(node); } else if ((buf[0] & 0xF0) == MIDI_CMD_NOTE_OFF) { @@ -125,14 +148,19 @@ SMFDriver::learn_track(SharedPtr 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(new MidiAction(ev_size, buf))); (*i)->set_duration(t - (*i)->enter_time()); (*i)->exit(SharedPtr(), 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 m, } } - initial_node->set_initial(true); + // Resolve any stuck notes when the rest of the machine is finished + if ( ! active_nodes.empty()) { + for (list >::iterator i = active_nodes.begin(); i != active_nodes.end(); ++i) { + cerr << "WARNING: Resolving stuck note from MIDI file." << endl; + SharedPtr action = PtrCast((*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(new MidiAction(3, note_off))); + (*i)->set_duration(t - (*i)->enter_time()); + (*i)->exit(SharedPtr(), t); + m->add_node((*i)); + ++added_nodes; + } + } + active_nodes.clear(); + } + + if (added_nodes > 0) + m->add_node(initial_node); } diff --git a/src/engine/machina/SMFDriver.hpp b/src/engine/machina/SMFDriver.hpp index f9b266b..28d2277 100644 --- a/src/engine/machina/SMFDriver.hpp +++ b/src/engine/machina/SMFDriver.hpp @@ -35,15 +35,16 @@ class Machine; class SMFDriver : public Raul::SMFWriter, public boost::enable_shared_from_this { public: - SharedPtr learn(const Glib::ustring& uri); - SharedPtr learn(const Glib::ustring& uri, unsigned track); + SharedPtr learn(const Glib::ustring& uri, Raul::BeatTime max_duration); + SharedPtr learn(const Glib::ustring& uri, unsigned track, Raul::BeatTime max_duration); void run(SharedPtr machine, Raul::BeatTime max_time); private: void learn_track(SharedPtr machine, Raul::SMFReader& reader, - unsigned track); + unsigned track, + Raul::BeatTime max_duration); }; -- cgit v1.2.1