diff options
Diffstat (limited to 'src/engine/SMFDriver.cpp')
-rw-r--r-- | src/engine/SMFDriver.cpp | 208 |
1 files changed, 16 insertions, 192 deletions
diff --git a/src/engine/SMFDriver.cpp b/src/engine/SMFDriver.cpp index 5b6d940..dc7ca59 100644 --- a/src/engine/SMFDriver.cpp +++ b/src/engine/SMFDriver.cpp @@ -20,7 +20,6 @@ #include <glibmm/convert.h> #include <raul/Quantizer.h> #include <raul/SharedPtr.h> -#include <raul/midi_events.h> #include <raul/SMFWriter.h> #include <raul/SMFReader.h> #include "machina/Machine.hpp" @@ -50,7 +49,7 @@ SharedPtr<Machine> SMFDriver::learn(const string& filename, unsigned track, double q, Raul::BeatTime max_duration) { SharedPtr<Machine> m(new Machine()); - + SharedPtr<MachineBuilder> builder = SharedPtr<MachineBuilder>(new MachineBuilder(m)); Raul::SMFReader reader; if (!reader.open(filename)) { @@ -61,7 +60,7 @@ SMFDriver::learn(const string& filename, unsigned track, double q, Raul::BeatTim if (track > reader.num_tracks()) return SharedPtr<Machine>(); else - learn_track(m, reader, track, q, max_duration); + learn_track(builder, reader, track, q, max_duration); m->reset(); @@ -80,15 +79,17 @@ SharedPtr<Machine> SMFDriver::learn(const string& filename, double q, Raul::BeatTime max_duration) { SharedPtr<Machine> m(new Machine()); - + SharedPtr<MachineBuilder> builder = SharedPtr<MachineBuilder>(new MachineBuilder(m)); Raul::SMFReader reader; + if (!reader.open(filename)) { cerr << "Unable to open MIDI file " << filename << endl; return SharedPtr<Machine>(); } for (unsigned t=1; t <= reader.num_tracks(); ++t) { - learn_track(m, reader, t, q, max_duration); + builder->reset(); + learn_track(builder, reader, t, q, max_duration); } m->reset(); @@ -100,80 +101,17 @@ SMFDriver::learn(const string& filename, double q, Raul::BeatTime max_duration) } -bool -SMFDriver::is_delay_node(SharedPtr<Node> node) const -{ - if (node->enter_action() || node->exit_action()) - return false; - else - return true; -} - - -/** Connect two nodes, inserting a delay node between them if necessary. - * - * If a delay node is added to the machine, it is returned. - */ -SharedPtr<Node> -SMFDriver::connect_nodes(SharedPtr<Machine> m, - SharedPtr<Node> tail, Raul::BeatTime tail_end_time, - SharedPtr<Node> head, Raul::BeatTime head_start_time) -{ - assert(tail != head); - assert(head_start_time >= tail_end_time); - - SharedPtr<Node> delay_node; - - //cerr << "Connect nodes durations: " << tail->duration() << " .. " << head->duration() << endl; - //cerr << "Connect nodes times: " << tail_end_time << " .. " << head_start_time << endl; - - if (head_start_time == tail_end_time) { - // Connect directly - tail->add_outgoing_edge(SharedPtr<Edge>(new Edge(tail, head))); - } else if (is_delay_node(tail)) { - // Tail is a delay node, just accumulate the time difference into it - tail->set_duration(tail->duration() + head_start_time - tail_end_time); - tail->add_outgoing_edge(SharedPtr<Edge>(new Edge(tail, head))); - } else { - // Need to actually create a delay node - //cerr << "Adding delay node for " << tail_end_time << " .. " << head_start_time << endl; - delay_node = SharedPtr<Node>(new Node()); - delay_node->set_duration(head_start_time - tail_end_time); - tail->add_outgoing_edge(SharedPtr<Edge>(new Edge(tail, delay_node))); - delay_node->add_outgoing_edge(SharedPtr<Edge>(new Edge(delay_node, head))); - m->add_node(delay_node); - } - - return delay_node; -} - - void -SMFDriver::learn_track(SharedPtr<Machine> m, - Raul::SMFReader& reader, - unsigned track, - double q, - Raul::BeatTime max_duration) +SMFDriver::learn_track(SharedPtr<MachineBuilder> builder, + Raul::SMFReader& reader, + unsigned track, + double q, + Raul::BeatTime max_duration) { const bool found_track = reader.seek_to_track(track); if (!found_track) return; - typedef list<SharedPtr<Node> > ActiveList; - ActiveList active_nodes; - - typedef list<pair<Raul::BeatTime, SharedPtr<Node> > > PolyList; - PolyList poly_nodes; - - SharedPtr<Node> initial_node(new 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 unquantized_t = 0; Raul::BeatTime t = 0; unsigned char buf[4]; @@ -183,130 +121,16 @@ SMFDriver::learn_track(SharedPtr<Machine> m, unquantized_t += ev_time / (double)reader.ppqn(); t = Raul::Quantizer::quantize(q, unquantized_t); + builder->set_time(t); + if (max_duration != 0 && 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] << ", channel = " << (int)(buf[0] & 0x0F) << endl; - SharedPtr<Node> node(new Node()); - - node->set_enter_action(SharedPtr<Action>(new MidiAction(ev_size, buf))); - - SharedPtr<Node> delay_node = connect_nodes(m, connect_node, connect_node_end_time, node, t); - if (delay_node) { - 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) { - //cerr << "NOTE OFF: " << (int)buf[1] << endl; - for (ActiveList::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[0] & 0x0F) == (buf[0] & 0x0F) // same channel - && ev[1] == buf[1]) // same note - { - //cerr << "FOUND MATCHING NOTE OFF!\n"; - - SharedPtr<Node> resolved = *i; - - resolved->set_exit_action(SharedPtr<Action>(new MidiAction(ev_size, buf))); - resolved->set_duration(t - resolved->enter_time()); - - ++added_nodes; - - connect_node_end_time = t; - - if (active_nodes.size() == 1) { - if (poly_nodes.size() > 0) { - - connect_node = SharedPtr<Node>(new Node()); - m->add_node(connect_node); - - connect_nodes(m, resolved, t, connect_node, t); - - for (PolyList::iterator j = poly_nodes.begin(); - j != poly_nodes.end(); ++j) { - m->add_node(j->second); - connect_nodes(m, j->second, j->first + j->second->duration(), - connect_node, t); - } - poly_nodes.clear(); - - m->add_node(resolved); - - } else { - // Trim useless delay node, if possible - // (these happen after polyphonic sections) - if (is_delay_node(connect_node) && connect_node->duration() == 0 - && connect_node->outgoing_edges().size() == 1 - && (*connect_node->outgoing_edges().begin())->head() == resolved) { - connect_node->outgoing_edges().clear(); - assert(connect_node->outgoing_edges().empty()); - connect_node->set_enter_action(resolved->enter_action()); - connect_node->set_exit_action(resolved->exit_action()); - resolved->remove_enter_action(); - resolved->remove_exit_action(); - connect_node->set_duration(resolved->duration()); - resolved = connect_node; - if (m->nodes().find(connect_node) == m->nodes().end()) - m->add_node(connect_node); - } else { - connect_node = resolved; - m->add_node(resolved); - } - } - - } else { - poly_nodes.push_back(make_pair(resolved->enter_time(), resolved)); - } - - if (resolved->is_active()) - resolved->exit(SharedPtr<Raul::MIDISink>(), t); - - active_nodes.erase(i); - - break; - } - } - } - } + if (ev_size > 0) + builder->event(0, ev_size, buf); } - - // 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)->set_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 (m->nodes().find(initial_node) == m->nodes().end()) - m->add_node(initial_node); + builder->resolve(); } |