diff options
Diffstat (limited to 'src/engine')
-rw-r--r-- | src/engine/JackDriver.cpp | 23 | ||||
-rw-r--r-- | src/engine/MachineBuilder.cpp | 72 | ||||
-rw-r--r-- | src/engine/MachineBuilder.hpp | 13 | ||||
-rw-r--r-- | src/engine/Recorder.cpp | 3 | ||||
-rw-r--r-- | src/engine/Recorder.hpp | 2 | ||||
-rw-r--r-- | src/engine/SMFDriver.cpp | 6 | ||||
-rw-r--r-- | src/engine/machina/Driver.hpp | 3 |
7 files changed, 77 insertions, 45 deletions
diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp index e5601d8..840573e 100644 --- a/src/engine/JackDriver.cpp +++ b/src/engine/JackDriver.cpp @@ -24,6 +24,7 @@ #include "Edge.hpp" #include "JackDriver.hpp" #include "LearnRequest.hpp" +#include "MachineBuilder.hpp" #include "MidiAction.hpp" using namespace machina; @@ -340,6 +341,7 @@ JackDriver::on_process(jack_nframes_t nframes) read_input_playing(machine, _context.time()); break; case PlayState::RECORDING: + case PlayState::STEP_RECORDING: read_input_recording(machine, _context.time()); break; } @@ -399,6 +401,7 @@ JackDriver::set_play_state(PlayState state) case PlayState::STOPPED: break; case PlayState::RECORDING: + case PlayState::STEP_RECORDING: finish_record(); // nobreak case PlayState::PLAYING: @@ -407,10 +410,14 @@ JackDriver::set_play_state(PlayState state) } break; case PlayState::RECORDING: - start_record(false); // FIXME: step record? + start_record(false); + break; + case PlayState::STEP_RECORDING: + start_record(true); break; case PlayState::PLAYING: - if (_play_state == PlayState::RECORDING) { + if (_play_state == PlayState::RECORDING || + _play_state == PlayState::STEP_RECORDING) { finish_record(); } } @@ -420,14 +427,20 @@ JackDriver::set_play_state(PlayState state) void JackDriver::start_record(bool step) { - if (_play_state.load() != PlayState::RECORDING) { - // FIXME: Choose an appropriate maximum ringbuffer size + switch (_play_state) { + case PlayState::STOPPED: + case PlayState::PLAYING: _recorder = SPtr<Recorder>( new Recorder(_forge, 1024, _beats_unit, _quantization.get(), step)); _recorder->start(); _record_dur = 0; - _play_state = PlayState::RECORDING; + break; + case PlayState::RECORDING: + case PlayState::STEP_RECORDING: + _recorder->builder()->set_step(true); + break; } + _play_state = step ? PlayState::STEP_RECORDING : PlayState::RECORDING; } void diff --git a/src/engine/MachineBuilder.cpp b/src/engine/MachineBuilder.cpp index d94e2da..566944e 100644 --- a/src/engine/MachineBuilder.cpp +++ b/src/engine/MachineBuilder.cpp @@ -37,6 +37,7 @@ MachineBuilder::MachineBuilder(SPtr<Machine> machine, double q, bool step) , _initial_node(machine->initial_node()) // duration 0 , _connect_node(_initial_node) , _connect_node_end_time(_time) // = 0 + , _step_duration(machine->time().unit(), 1, 0) , _step(step) {} @@ -51,7 +52,9 @@ MachineBuilder::reset() bool MachineBuilder::is_delay_node(SPtr<Node> node) const { - return !node->enter_action() && !node->exit_action(); + return node != _initial_node && + !node->enter_action() && + !node->exit_action(); } /** Set the duration of a node, with quantization. @@ -61,7 +64,7 @@ MachineBuilder::set_node_duration(SPtr<Node> node, Raul::TimeDuration d) const { if (_step) { - node->set_duration(TimeStamp(d.unit(), 1, 0)); + node->set_duration(_step_duration); return; } @@ -85,10 +88,10 @@ MachineBuilder::connect_nodes(SPtr<Machine> m, SPtr<Node> head, Raul::TimeStamp head_start_time) { - assert(tail != head); - assert(head_start_time >= tail_end_time); - SPtr<Node> delay_node; + if (tail == head) { + return delay_node; + } if (is_delay_node(tail) && tail->edges().empty()) { // Tail is a delay node, just accumulate the time difference into it @@ -112,9 +115,22 @@ MachineBuilder::connect_nodes(SPtr<Machine> m, void MachineBuilder::note_on(Raul::TimeStamp t, size_t ev_size, uint8_t* buf) { - SPtr<Node> node(new Node(TimeStamp(t.unit()))); + SPtr<Node> node; + if (_step && _poly_nodes.empty() && is_delay_node(_connect_node)) { + /* Stepping and the connect node is the merge node after a polyphonic + group. Re-use it to avoid creating delay nodes in step mode. */ + node = _connect_node; + node->set_duration(_step_duration); + } else { + node = SPtr<Node>(new Node(default_duration())); + } + node->set_enter_action(SPtr<Action>(new MidiAction(ev_size, buf))); + if (_step && _poly_nodes.empty()) { + t = _time = _time + _step_duration; // Advance time one step + } + SPtr<Node> this_connect_node; Raul::TimeStamp this_connect_node_end_time(t.unit()); @@ -151,25 +167,27 @@ MachineBuilder::note_on(Raul::TimeStamp t, size_t ev_size, uint8_t* buf) } void -MachineBuilder::resolve_note(Raul::TimeStamp t, +MachineBuilder::resolve_note(Raul::TimeStamp time, size_t ev_size, uint8_t* buf, SPtr<Node> resolved) { - resolved->set_exit_action( - SPtr<Action>(new MidiAction(ev_size, buf))); - set_node_duration(resolved, t - resolved->enter_time()); + resolved->set_exit_action(SPtr<Action>(new MidiAction(ev_size, buf))); if (_active_nodes.size() == 1) { + if (_step) { + time = _time = _time + _step_duration; + } + // Last active note - _connect_node_end_time = t; + _connect_node_end_time = time; if (!_poly_nodes.empty()) { // Finish a polyphonic section - _connect_node = SPtr<Node>(new Node(TimeStamp(t.unit()))); + _connect_node = SPtr<Node>(new Node(TimeStamp(_time.unit(), 0, 0))); _machine->add_node(_connect_node); - connect_nodes(_machine, resolved, t, _connect_node, t); + connect_nodes(_machine, resolved, time, _connect_node, time); for (PolyList::iterator j = _poly_nodes.begin(); j != _poly_nodes.end(); ++j) { @@ -177,7 +195,7 @@ MachineBuilder::resolve_note(Raul::TimeStamp t, if (j->second->edges().empty()) { connect_nodes(_machine, j->second, j->first + j->second->duration(), - _connect_node, t); + _connect_node, time); } } _poly_nodes.clear(); @@ -193,7 +211,6 @@ MachineBuilder::resolve_note(Raul::TimeStamp t, // 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(SPtr<Action>()); @@ -209,30 +226,32 @@ MachineBuilder::resolve_note(Raul::TimeStamp t, } } else { - // Polyphonic, add this state to poly list + // Polyphonic, add this node to poly list _poly_nodes.push_back(make_pair(resolved->enter_time(), resolved)); _connect_node = resolved; - _connect_node_end_time = t; + _connect_node_end_time = _time; } if (resolved->is_active()) { - resolved->exit(NULL, t); + resolved->exit(NULL, _time); } } void -MachineBuilder::event(Raul::TimeStamp time_offset, +MachineBuilder::event(Raul::TimeStamp time, size_t ev_size, uint8_t* buf) { - Raul::TimeStamp t = _time + time_offset; - if (ev_size == 0) { return; } + if (!_step) { + _time = time; + } + if ((buf[0] & 0xF0) == LV2_MIDI_MSG_NOTE_ON) { - note_on(t, ev_size, buf); + note_on(time, 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) { @@ -249,7 +268,7 @@ MachineBuilder::event(Raul::TimeStamp time_offset, (ev[0] & 0x0F) == (buf[0] & 0x0F) && ev[1] == buf[1]) { // Same channel and note as on event - resolve_note(t, ev_size, buf, *i); + resolve_note(time, ev_size, buf, *i); _active_nodes.erase(i); break; } @@ -277,11 +296,8 @@ MachineBuilder::resolve() 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 - }; + uint8_t st((LV2_MIDI_MSG_NOTE_OFF & 0xF0) | (ev[0] & 0x0F)); + const uint8_t note_off[3] = { st, ev[1], 0x40 }; (*i)->set_exit_action( SPtr<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 c4bbe1b..83baf78 100644 --- a/src/engine/MachineBuilder.hpp +++ b/src/engine/MachineBuilder.hpp @@ -36,9 +36,9 @@ public: double quantization, bool step); - void set_time(Raul::TimeStamp time) { _time = time; } + void event(Raul::TimeStamp time, size_t size, unsigned char* buf); - void event(Raul::TimeStamp time_offset, size_t size, unsigned char* buf); + void set_step(bool step) { _step = step; } void reset(); void resolve(); @@ -62,6 +62,10 @@ private: SPtr<Node> head, Raul::TimeStamp head_start_time); + Raul::TimeStamp default_duration() { + return _step ? _step_duration : Raul::TimeStamp(_time.unit(), 0, 0); + } + typedef std::list<SPtr<Node> > ActiveList; ActiveList _active_nodes; @@ -70,13 +74,12 @@ private: double _quantization; Raul::TimeStamp _time; - SPtr<Machine> _machine; SPtr<Node> _initial_node; SPtr<Node> _connect_node; Raul::TimeStamp _connect_node_end_time; - - bool _step; + Raul::TimeStamp _step_duration; + bool _step; }; } // namespace machina diff --git a/src/engine/Recorder.cpp b/src/engine/Recorder.cpp index e628b64..6636f1d 100644 --- a/src/engine/Recorder.cpp +++ b/src/engine/Recorder.cpp @@ -52,8 +52,7 @@ Recorder::_whipped() success = _record_buffer.read(size, buf); } if (success) { - _builder->set_time(t); - _builder->event(TimeStamp(_unit), size, buf); + _builder->event(t, size, buf); } else { break; } diff --git a/src/engine/Recorder.hpp b/src/engine/Recorder.hpp index 1c97219..529eec9 100644 --- a/src/engine/Recorder.hpp +++ b/src/engine/Recorder.hpp @@ -51,6 +51,8 @@ public: } } + SPtr<MachineBuilder> builder() { return _builder; } + SPtr<Machine> finish(); private: diff --git a/src/engine/SMFDriver.cpp b/src/engine/SMFDriver.cpp index 1b7e727..58ff8a0 100644 --- a/src/engine/SMFDriver.cpp +++ b/src/engine/SMFDriver.cpp @@ -136,15 +136,13 @@ SMFDriver::learn_track(SPtr<MachineBuilder> builder, const double frac = smf_ticks / (double)reader.ppqn(); const uint32_t ticks = frac * MACHINA_PPQN; - // TODO: quantize - builder->set_time(TimeStamp(unit, beats, ticks)); - if (!max_duration.is_zero() && t > max_duration.to_double()) { break; } if (ev_size > 0) { - builder->event(TimeStamp(max_duration.unit(), 0, 0), ev_size, buf); + // TODO: quantize + builder->event(TimeStamp(unit, beats, ticks), ev_size, buf); } } diff --git a/src/engine/machina/Driver.hpp b/src/engine/machina/Driver.hpp index 83169ea..1fad9b3 100644 --- a/src/engine/machina/Driver.hpp +++ b/src/engine/machina/Driver.hpp @@ -41,7 +41,8 @@ public: enum class PlayState { STOPPED, PLAYING, - RECORDING + RECORDING, + STEP_RECORDING }; virtual ~Driver() {} |