aboutsummaryrefslogtreecommitdiffstats
path: root/src/engine
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/JackDriver.cpp23
-rw-r--r--src/engine/MachineBuilder.cpp72
-rw-r--r--src/engine/MachineBuilder.hpp13
-rw-r--r--src/engine/Recorder.cpp3
-rw-r--r--src/engine/Recorder.hpp2
-rw-r--r--src/engine/SMFDriver.cpp6
-rw-r--r--src/engine/machina/Driver.hpp3
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() {}