diff options
-rw-r--r-- | src/engine/MachineBuilder.cpp | 254 | ||||
-rw-r--r-- | src/engine/MachineBuilder.hpp | 9 |
2 files changed, 134 insertions, 129 deletions
diff --git a/src/engine/MachineBuilder.cpp b/src/engine/MachineBuilder.cpp index bb8f7c2..0a6dbfc 100644 --- a/src/engine/MachineBuilder.cpp +++ b/src/engine/MachineBuilder.cpp @@ -115,61 +115,135 @@ MachineBuilder::connect_nodes(SharedPtr<Machine> m, } void -MachineBuilder::event(Raul::TimeStamp time_offset, - size_t ev_size, - unsigned char* buf) +MachineBuilder::note_on(Raul::TimeStamp t, size_t ev_size, uint8_t* buf) { - const Raul::TimeUnit unit = time_offset.unit(); - Raul::TimeStamp t = _time + time_offset; + SharedPtr<Node> node(new Node(TimeStamp(t.unit()))); + node->set_enter_action(SharedPtr<Action>(new MidiAction(ev_size, buf))); + + SharedPtr<Node> this_connect_node; + Raul::TimeStamp this_connect_node_end_time(t.unit()); + + /* If currently polyphonic, use a poly node with no successors as connect + node, for more sensible patterns like what a human would build. */ + if (!_poly_nodes.empty()) { + for (PolyList::iterator j = _poly_nodes.begin(); + j != _poly_nodes.end(); ++j) { + if (j->second->edges().empty()) { + this_connect_node = j->second; + this_connect_node_end_time = j->first + j->second->duration(); + break; + } + } + } - if (ev_size == 0) { - return; + /* Currently monophonic, or didn't find a poly node, so use _connect_node + which is maintained below on note off events. */ + if (!this_connect_node) { + this_connect_node = _connect_node; + this_connect_node_end_time = _connect_node_end_time; } - if ((buf[0] & 0xF0) == LV2_MIDI_MSG_NOTE_ON) { + SharedPtr<Node> delay_node = connect_nodes( + _machine, this_connect_node, this_connect_node_end_time, node, t); + + if (delay_node) { + _connect_node = delay_node; + _connect_node_end_time = t; + } + + node->enter(NULL, t); + _active_nodes.push_back(node); +} - SharedPtr<Node> node(new Node(TimeStamp(unit))); - node->set_enter_action(SharedPtr<Action>(new MidiAction(ev_size, buf))); +void +MachineBuilder::resolve_note(Raul::TimeStamp t, + size_t ev_size, + uint8_t* buf, + SharedPtr<Node> resolved) +{ + resolved->set_exit_action( + SharedPtr<Action>(new MidiAction(ev_size, buf))); + set_node_duration(resolved, t - resolved->enter_time()); - SharedPtr<Node> this_connect_node; - Raul::TimeStamp this_connect_node_end_time(unit); + if (_active_nodes.size() == 1) { + // Last active note + _connect_node_end_time = t; - // If currently polyphonic, use a poly node with no successors as connect node - // Results in patterns closest to what a human would choose if (!_poly_nodes.empty()) { + // Finish a polyphonic section + _connect_node = SharedPtr<Node>(new Node(TimeStamp(t.unit()))); + _machine->add_node(_connect_node); + + connect_nodes(_machine, resolved, t, _connect_node, t); + for (PolyList::iterator j = _poly_nodes.begin(); j != _poly_nodes.end(); ++j) { - if (j->second->edges().empty()) { - this_connect_node = j->second; - this_connect_node_end_time = j->first + j->second->duration(); - break; + _machine->add_node(j->second); + if (j->second->edges().size() == 0) { + connect_nodes(_machine, j->second, + j->first + j->second->duration(), + _connect_node, t); } } - } + _poly_nodes.clear(); + + _machine->add_node(resolved); + + } else { + // Just monophonic + if (is_delay_node(_connect_node) + && _connect_node->duration().is_zero() + && (_connect_node->edges().size() == 1) + && ((*_connect_node->edges().begin())->head() == resolved)) { + // Trim useless delay node if possible (after poly sections) + + _connect_node->edges().clear(); + assert(_connect_node->edges().empty()); + _connect_node->set_enter_action(resolved->enter_action()); + _connect_node->set_exit_action(resolved->exit_action()); + resolved->set_enter_action(SharedPtr<Action>()); + resolved->set_exit_action(SharedPtr<Action>()); + set_node_duration(_connect_node, resolved->duration()); + resolved = _connect_node; + if (std::find(_machine->nodes().begin(), + _machine->nodes().end(), + _connect_node) + == _machine->nodes().end()) { + _machine->add_node(_connect_node); + } - // Currently monophonic, or didn't find a poly node, so use _connect_node - // which is maintained below on note off events. - if (!this_connect_node) { - this_connect_node = _connect_node; - this_connect_node_end_time = _connect_node_end_time; + } else { + _connect_node = resolved; + _machine->add_node(resolved); + } } - SharedPtr<Node> delay_node = connect_nodes(_machine, - this_connect_node, - this_connect_node_end_time, - node, - t); + } else { + // Polyphonic, add this state to poly list + _poly_nodes.push_back(make_pair(resolved->enter_time(), resolved)); + _connect_node = resolved; + _connect_node_end_time = t; + } - if (delay_node) { - _connect_node = delay_node; - _connect_node_end_time = t; - } + if (resolved->is_active()) { + resolved->exit(NULL, t); + } +} - node->enter(NULL, t); - _active_nodes.push_back(node); +void +MachineBuilder::event(Raul::TimeStamp time_offset, + size_t ev_size, + uint8_t* buf) +{ + Raul::TimeStamp t = _time + time_offset; - } else if ((buf[0] & 0xF0) == LV2_MIDI_MSG_NOTE_OFF) { + if (ev_size == 0) { + return; + } + if ((buf[0] & 0xF0) == LV2_MIDI_MSG_NOTE_ON) { + note_on(t, ev_size, buf); + } else if ((buf[0] & 0xF0) == LV2_MIDI_MSG_NOTE_OFF) { for (ActiveList::iterator i = _active_nodes.begin(); i != _active_nodes.end(); ++i) { SharedPtr<MidiAction> action = PtrCast<MidiAction>( @@ -178,96 +252,18 @@ MachineBuilder::event(Raul::TimeStamp time_offset, continue; } - const size_t ev_size = action->event_size(); - const unsigned char* ev = action->event(); - - if ((ev_size == 3) && ((ev[0] & 0xF0) == LV2_MIDI_MSG_NOTE_ON) - && ((ev[0] & 0x0F) == (buf[0] & 0x0F)) // same channel - && (ev[1] == buf[1])) { - // same note - SharedPtr<Node> resolved = *i; - - resolved->set_exit_action( - SharedPtr<Action>(new MidiAction(ev_size, buf))); - set_node_duration(resolved, t - resolved->enter_time()); - - // Last active note - if (_active_nodes.size() == 1) { - - _connect_node_end_time = t; - - // Finish a polyphonic section - if (!_poly_nodes.empty()) { - - _connect_node = SharedPtr<Node>(new Node(TimeStamp(unit))); - _machine->add_node(_connect_node); - - connect_nodes(_machine, resolved, t, _connect_node, t); - - for (PolyList::iterator j = _poly_nodes.begin(); - j != _poly_nodes.end(); ++j) { - _machine->add_node(j->second); - if (j->second->edges().size() == 0) { - connect_nodes(_machine, j->second, - j->first + j->second->duration(), - _connect_node, t); - } - } - _poly_nodes.clear(); - - _machine->add_node(resolved); - - // Just monophonic - } else { - - // Trim useless delay node if possible (these appear after poly sections) - if (is_delay_node(_connect_node) - && _connect_node->duration().is_zero() - && (_connect_node->edges().size() == 1) - && ((*_connect_node->edges().begin())->head() == - resolved)) { - - _connect_node->edges().clear(); - assert(_connect_node->edges().empty()); - _connect_node->set_enter_action( - resolved->enter_action()); - _connect_node->set_exit_action( - resolved->exit_action()); - resolved->set_enter_action(SharedPtr<Action>()); - resolved->set_exit_action(SharedPtr<Action>()); - set_node_duration(_connect_node, resolved->duration()); - resolved = _connect_node; - if (std::find(_machine->nodes().begin(), - _machine->nodes().end(), - _connect_node) - == _machine->nodes().end()) { - _machine->add_node(_connect_node); - } - - } else { - _connect_node = resolved; - _machine->add_node(resolved); - } - } - - // Polyphonic, add this state to poly list - } else { - _poly_nodes.push_back(make_pair(resolved->enter_time(), - resolved)); - _connect_node = resolved; - _connect_node_end_time = t; - } - - if (resolved->is_active()) { - resolved->exit(NULL, t); - } + const size_t ev_size = action->event_size(); + const uint8_t* ev = action->event(); + if ((ev[0] & 0xF0) == LV2_MIDI_MSG_NOTE_ON && + (ev[0] & 0x0F) == (buf[0] & 0x0F) && + ev[1] == buf[1]) { + // Same channel and note as on event + resolve_note(t, ev_size, buf, *i); _active_nodes.erase(i); - break; } } - } } @@ -288,14 +284,14 @@ MachineBuilder::resolve() continue; } - const size_t ev_size = action->event_size(); - const unsigned char* ev = action->event(); - if (ev_size == 3 && - (ev[0] & 0xF0) == LV2_MIDI_MSG_NOTE_ON) { - unsigned char note_off[3] - = { ((LV2_MIDI_MSG_NOTE_OFF & 0xF0) | (ev[0] & 0x0F)), - ev[1], - 0x40 }; + const size_t ev_size = action->event_size(); + const uint8_t* ev = action->event(); + if (ev_size == 3 && (ev[0] & 0xF0) == LV2_MIDI_MSG_NOTE_ON) { + const uint8_t note_off[3] = { + ((LV2_MIDI_MSG_NOTE_OFF & 0xF0) | (ev[0] & 0x0F)), + ev[1], + 0x40 + }; (*i)->set_exit_action( SharedPtr<Action>(new MidiAction(3, note_off))); set_node_duration((*i), _time - (*i)->enter_time()); diff --git a/src/engine/MachineBuilder.hpp b/src/engine/MachineBuilder.hpp index 7bd865d..cb3ccea 100644 --- a/src/engine/MachineBuilder.hpp +++ b/src/engine/MachineBuilder.hpp @@ -18,6 +18,8 @@ #ifndef MACHINA_MACHINEBUILDER_HPP #define MACHINA_MACHINEBUILDER_HPP +#include <stdint.h> + #include <list> #include "raul/SharedPtr.hpp" @@ -48,6 +50,13 @@ private: bool is_delay_node(SharedPtr<Node> node) const; void set_node_duration(SharedPtr<Node> node, Raul::TimeDuration d) const; + void note_on(Raul::TimeStamp t, size_t ev_size, uint8_t* buf); + + void resolve_note(Raul::TimeStamp t, + size_t ev_size, + uint8_t* buf, + SharedPtr<Node> resolved); + SharedPtr<Node>connect_nodes(SharedPtr<Machine> m, SharedPtr<Node> tail, Raul::TimeStamp tail_end_time, |